diff options
289 files changed, 6236 insertions, 2439 deletions
diff --git a/apex/Android.bp b/apex/Android.bp index c1715a002d6d..371bd7fc9479 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -63,9 +63,9 @@ mainline_service_stubs_args = "--hide-annotation android.annotation.Hide " + "--hide InternalClasses " // com.android.* classes are okay in this interface -// Defaults for mainline module provided java_sdk_library instances. +// Defaults common to all mainline module java_sdk_library instances. java_defaults { - name: "framework-module-defaults", + name: "framework-module-common-defaults", // Additional annotations used for compiling both the implementation and the // stubs libraries. @@ -88,14 +88,6 @@ java_defaults { enabled: true, sdk_version: "module_current", }, - system: { - enabled: true, - sdk_version: "module_current", - }, - module_lib: { - enabled: true, - sdk_version: "module_current", - }, // Configure framework module specific metalava options. droiddoc_options: [mainline_stubs_args], @@ -127,6 +119,32 @@ java_defaults { sdk_version: "module_current", } +// Defaults for mainline module provided java_sdk_library instances. +java_defaults { + name: "framework-module-defaults", + defaults: ["framework-module-common-defaults"], + + system: { + enabled: true, + sdk_version: "module_current", + }, + module_lib: { + enabled: true, + sdk_version: "module_current", + }, +} + +// Defaults for mainline module system server provided java_sdk_library instances. +java_defaults { + name: "framework-system-server-module-defaults", + defaults: ["framework-module-common-defaults"], + + system_server: { + enabled: true, + sdk_version: "module_current", + }, +} + stubs_defaults { name: "framework-module-stubs-defaults-publicapi", args: mainline_framework_stubs_args, diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java index bcef8ceaa941..ecc78ce7cf34 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java @@ -219,7 +219,7 @@ public final class BlobHandle implements Parcelable { public void dump(IndentingPrintWriter fout, boolean dumpFull) { if (dumpFull) { fout.println("algo: " + algorithm); - fout.println("digest: " + (dumpFull ? encodeDigest() : safeDigest())); + fout.println("digest: " + (dumpFull ? encodeDigest(digest) : safeDigest(digest))); fout.println("label: " + label); fout.println("expiryMs: " + expiryTimeMillis); fout.println("tag: " + tag); @@ -243,19 +243,20 @@ public final class BlobHandle implements Parcelable { public String toString() { return "BlobHandle {" + "algo:" + algorithm + "," - + "digest:" + safeDigest() + "," + + "digest:" + safeDigest(digest) + "," + "label:" + label + "," + "expiryMs:" + expiryTimeMillis + "," + "tag:" + tag + "}"; } - private String safeDigest() { - final String digestStr = encodeDigest(); + /** @hide */ + public static String safeDigest(@NonNull byte[] digest) { + final String digestStr = encodeDigest(digest); return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2); } - private String encodeDigest() { + private static String encodeDigest(@NonNull byte[] digest) { return Base64.encodeToString(digest, Base64.NO_WRAP); } diff --git a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java index 80062d5d245f..ba92d95b483e 100644 --- a/apex/blobstore/framework/java/android/app/blob/BlobInfo.java +++ b/apex/blobstore/framework/java/android/app/blob/BlobInfo.java @@ -16,9 +16,13 @@ package android.app.blob; +import static android.text.format.Formatter.FLAG_IEC_UNITS; + import android.annotation.NonNull; +import android.app.AppGlobals; import android.os.Parcel; import android.os.Parcelable; +import android.text.format.Formatter; import java.util.Collections; import java.util.List; @@ -32,13 +36,15 @@ public final class BlobInfo implements Parcelable { private final long mId; private final long mExpiryTimeMs; private final CharSequence mLabel; + private final long mSizeBytes; private final List<LeaseInfo> mLeaseInfos; - public BlobInfo(long id, long expiryTimeMs, CharSequence label, + public BlobInfo(long id, long expiryTimeMs, CharSequence label, long sizeBytes, List<LeaseInfo> leaseInfos) { mId = id; mExpiryTimeMs = expiryTimeMs; mLabel = label; + mSizeBytes = sizeBytes; mLeaseInfos = leaseInfos; } @@ -46,6 +52,7 @@ public final class BlobInfo implements Parcelable { mId = in.readLong(); mExpiryTimeMs = in.readLong(); mLabel = in.readCharSequence(); + mSizeBytes = in.readLong(); mLeaseInfos = in.readArrayList(null /* classloader */); } @@ -61,6 +68,10 @@ public final class BlobInfo implements Parcelable { return mLabel; } + public long getSizeBytes() { + return mSizeBytes; + } + public List<LeaseInfo> getLeases() { return Collections.unmodifiableList(mLeaseInfos); } @@ -70,6 +81,7 @@ public final class BlobInfo implements Parcelable { dest.writeLong(mId); dest.writeLong(mExpiryTimeMs); dest.writeCharSequence(mLabel); + dest.writeLong(mSizeBytes); dest.writeList(mLeaseInfos); } @@ -83,10 +95,16 @@ public final class BlobInfo implements Parcelable { + "id: " + mId + "," + "expiryMs: " + mExpiryTimeMs + "," + "label: " + mLabel + "," + + "size: " + formatBlobSize(mSizeBytes) + "," + "leases: " + LeaseInfo.toShortString(mLeaseInfos) + "," + "}"; } + private static String formatBlobSize(long sizeBytes) { + return Formatter.formatFileSize(AppGlobals.getInitialApplication(), + sizeBytes, FLAG_IEC_UNITS); + } + @Override public int describeContents() { return 0; diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java index 8fff0d9c950b..68c4bb675907 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -478,11 +478,14 @@ public class BlobStoreManagerService extends SystemService { ? Resources.ID_NULL : getDescriptionResourceId(resourcesGetter.apply(leasee.packageName), leasee.descriptionResEntryName, leasee.packageName); - leaseInfos.add(new LeaseInfo(leasee.packageName, leasee.expiryTimeMillis, + final long expiryTimeMs = leasee.expiryTimeMillis == 0 + ? blobHandle.getExpiryTimeMillis() : leasee.expiryTimeMillis; + leaseInfos.add(new LeaseInfo(leasee.packageName, expiryTimeMs, descriptionResId, leasee.description)); }); blobInfos.add(new BlobInfo(blobMetadata.getBlobId(), - blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), leaseInfos)); + blobHandle.getExpiryTimeMillis(), blobHandle.getLabel(), + blobMetadata.getSize(), leaseInfos)); }); } return blobInfos; @@ -591,6 +594,7 @@ public class BlobStoreManagerService extends SystemService { } else { blob.addOrReplaceCommitter(existingCommitter); } + Slog.d(TAG, "Error committing the blob", e); session.sendCommitCallbackResult(COMMIT_RESULT_ERROR); } getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())) diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java index 2b0458303a23..22d5d11e9ccb 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java @@ -28,7 +28,6 @@ import static android.system.OsConstants.O_RDONLY; import static android.system.OsConstants.O_RDWR; import static android.system.OsConstants.SEEK_SET; -import static com.android.server.blob.BlobStoreConfig.LOGV; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_SESSION_CREATION_TIME; import static com.android.server.blob.BlobStoreConfig.hasSessionExpired; @@ -423,9 +422,10 @@ class BlobStoreSession extends IBlobStoreSession.Stub { mState = STATE_VERIFIED_VALID; // Commit callback will be sent once the data is persisted. } else { - if (LOGV) { - Slog.v(TAG, "Digest of the data didn't match the given BlobHandle.digest"); - } + Slog.d(TAG, "Digest of the data (" + + (mDataDigest == null ? "null" : BlobHandle.safeDigest(mDataDigest)) + + ") didn't match the given BlobHandle.digest (" + + BlobHandle.safeDigest(mBlobHandle.digest) + ")"); mState = STATE_VERIFIED_INVALID; sendCommitCallbackResult(COMMIT_RESULT_ERROR); } diff --git a/apex/media/framework/java/android/media/MediaParser.java b/apex/media/framework/java/android/media/MediaParser.java index 7cbb98e1bb4e..19f578ecfc66 100644 --- a/apex/media/framework/java/android/media/MediaParser.java +++ b/apex/media/framework/java/android/media/MediaParser.java @@ -203,6 +203,15 @@ public final class MediaParser { /** Returned by {@link #getDurationMicros()} when the duration is unknown. */ public static final int UNKNOWN_DURATION = Integer.MIN_VALUE; + /** + * For each {@link #getSeekPoints} call, returns a single {@link SeekPoint} whose {@link + * SeekPoint#timeMicros} matches the requested timestamp, and whose {@link + * SeekPoint#position} is 0. + * + * @hide + */ + public static final SeekMap DUMMY = new SeekMap(new DummyExoPlayerSeekMap()); + private final com.google.android.exoplayer2.extractor.SeekMap mExoPlayerSeekMap; private SeekMap(com.google.android.exoplayer2.extractor.SeekMap exoplayerSeekMap) { @@ -795,6 +804,18 @@ public final class MediaParser { */ public static final String PARAMETER_EAGERLY_EXPOSE_TRACKTYPE = "android.media.mediaparser.eagerlyExposeTrackType"; + /** + * Sets whether a dummy {@link SeekMap} should be exposed before starting extraction. {@code + * boolean} expected. Default value is {@code false}. + * + * <p>For each {@link SeekMap#getSeekPoints} call, the dummy {@link SeekMap} returns a single + * {@link SeekPoint} whose {@link SeekPoint#timeMicros} matches the requested timestamp, and + * whose {@link SeekPoint#position} is 0. + * + * @hide + */ + public static final String PARAMETER_EXPOSE_DUMMY_SEEKMAP = + "android.media.mediaparser.exposeDummySeekMap"; // Private constants. @@ -958,6 +979,7 @@ public final class MediaParser { private boolean mIncludeSupplementalData; private boolean mIgnoreTimestampOffset; private boolean mEagerlyExposeTrackType; + private boolean mExposeDummySeekMap; private String mParserName; private Extractor mExtractor; private ExtractorInput mExtractorInput; @@ -1017,6 +1039,9 @@ public final class MediaParser { if (PARAMETER_EAGERLY_EXPOSE_TRACKTYPE.equals(parameterName)) { mEagerlyExposeTrackType = (boolean) value; } + if (PARAMETER_EXPOSE_DUMMY_SEEKMAP.equals(parameterName)) { + mExposeDummySeekMap = (boolean) value; + } mParserParameters.put(parameterName, value); return this; } @@ -1078,11 +1103,10 @@ public final class MediaParser { } mExoDataReader.mInputReader = seekableInputReader; - // TODO: Apply parameters when creating extractor instances. if (mExtractor == null) { + mPendingExtractorInit = true; if (!mParserName.equals(PARSER_NAME_UNKNOWN)) { mExtractor = createExtractor(mParserName); - mExtractor.init(new ExtractorOutputAdapter()); } else { for (String parserName : mParserNamesPool) { Extractor extractor = createExtractor(parserName); @@ -1107,9 +1131,18 @@ public final class MediaParser { } if (mPendingExtractorInit) { + if (mExposeDummySeekMap) { + // We propagate the dummy seek map before initializing the extractor, in case the + // extractor initialization outputs a seek map. + mOutputConsumer.onSeekMapFound(SeekMap.DUMMY); + } mExtractor.init(new ExtractorOutputAdapter()); mPendingExtractorInit = false; + // We return after initialization to allow clients use any output information before + // starting actual extraction. + return true; } + if (isPendingSeek()) { mExtractor.seek(mPendingSeekPosition, mPendingSeekTimeMicros); removePendingSeek(); @@ -1683,6 +1716,28 @@ public final class MediaParser { } } + private static final class DummyExoPlayerSeekMap + implements com.google.android.exoplayer2.extractor.SeekMap { + + @Override + public boolean isSeekable() { + return true; + } + + @Override + public long getDurationUs() { + return C.TIME_UNSET; + } + + @Override + public SeekPoints getSeekPoints(long timeUs) { + com.google.android.exoplayer2.extractor.SeekPoint seekPoint = + new com.google.android.exoplayer2.extractor.SeekPoint( + timeUs, /* position= */ 0); + return new SeekPoints(seekPoint, seekPoint); + } + } + /** Creates extractor instances. */ private interface ExtractorFactory { @@ -1923,6 +1978,7 @@ public final class MediaParser { expectedTypeByParameterName.put(PARAMETER_INCLUDE_SUPPLEMENTAL_DATA, Boolean.class); expectedTypeByParameterName.put(PARAMETER_IGNORE_TIMESTAMP_OFFSET, Boolean.class); expectedTypeByParameterName.put(PARAMETER_EAGERLY_EXPOSE_TRACKTYPE, Boolean.class); + expectedTypeByParameterName.put(PARAMETER_EXPOSE_DUMMY_SEEKMAP, Boolean.class); EXPECTED_TYPE_BY_PARAMETER_NAME = Collections.unmodifiableMap(expectedTypeByParameterName); } } diff --git a/apex/permission/service/Android.bp b/apex/permission/service/Android.bp index 61449763540b..7f3187949712 100644 --- a/apex/permission/service/Android.bp +++ b/apex/permission/service/Android.bp @@ -20,14 +20,26 @@ filegroup { path: "java", } -java_library { +java_sdk_library { name: "service-permission", + defaults: ["framework-system-server-module-defaults"], + visibility: [ + "//frameworks/base/services/core", + "//frameworks/base/apex/permission", + "//frameworks/base/apex/permission/testing", + "//frameworks/base/apex/permission/tests", + "//frameworks/base/services/tests/mockingservicestests", + ], + impl_library_visibility: [ + "//visibility:override", + "//frameworks/base/apex/permission/tests", + "//frameworks/base/services/tests/mockingservicestests", + "//frameworks/base/services/tests/servicestests", + ], srcs: [ ":service-permission-sources", ], - sdk_version: "module_current", libs: [ - "framework-annotations-lib", "framework-permission", ], apex_available: [ @@ -36,28 +48,3 @@ java_library { ], installable: true, } - -droidstubs { - name: "service-permission-stubs-srcs", - srcs: [ ":service-permission-sources" ], - defaults: ["service-module-stubs-srcs-defaults"], - check_api: { - last_released: { - api_file: ":service-permission.api.system-server.latest", - removed_api_file: ":service-permission-removed.api.system-server.latest", - }, - api_lint: { - new_since: ":service-permission.api.system-server.latest", - }, - }, - visibility: ["//visibility:private"], - dist: { dest: "service-permission.txt" }, -} - -java_library { - name: "service-permission-stubs", - srcs: [":service-permission-stubs-srcs"], - defaults: ["service-module-stubs-defaults"], - visibility: ["//frameworks/base/services/core"], - dist: { dest: "service-permission.jar" }, -} diff --git a/apex/permission/service/api/current.txt b/apex/permission/service/api/current.txt index c76cc3275737..d802177e249b 100644 --- a/apex/permission/service/api/current.txt +++ b/apex/permission/service/api/current.txt @@ -1,46 +1 @@ // Signature format: 2.0 -package com.android.permission.persistence { - - public interface RuntimePermissionsPersistence { - method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance(); - method public void deleteForUser(@NonNull android.os.UserHandle); - method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle); - method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); - } - - public final class RuntimePermissionsState { - ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>); - method @Nullable public String getFingerprint(); - method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions(); - method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions(); - method public int getVersion(); - field public static final int NO_VERSION = -1; // 0xffffffff - } - - public static final class RuntimePermissionsState.PermissionState { - ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int); - method public int getFlags(); - method @NonNull public String getName(); - method public boolean isGranted(); - } - -} - -package com.android.role.persistence { - - public interface RolesPersistence { - method @NonNull public static com.android.role.persistence.RolesPersistence createInstance(); - method public void deleteForUser(@NonNull android.os.UserHandle); - method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle); - method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); - } - - public final class RolesState { - ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>); - method @Nullable public String getPackagesHash(); - method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles(); - method public int getVersion(); - } - -} - diff --git a/apex/permission/service/api/system-server-current.txt b/apex/permission/service/api/system-server-current.txt new file mode 100644 index 000000000000..c76cc3275737 --- /dev/null +++ b/apex/permission/service/api/system-server-current.txt @@ -0,0 +1,46 @@ +// Signature format: 2.0 +package com.android.permission.persistence { + + public interface RuntimePermissionsPersistence { + method @NonNull public static com.android.permission.persistence.RuntimePermissionsPersistence createInstance(); + method public void deleteForUser(@NonNull android.os.UserHandle); + method @Nullable public com.android.permission.persistence.RuntimePermissionsState readForUser(@NonNull android.os.UserHandle); + method public void writeForUser(@NonNull com.android.permission.persistence.RuntimePermissionsState, @NonNull android.os.UserHandle); + } + + public final class RuntimePermissionsState { + ctor public RuntimePermissionsState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>, @NonNull java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>>); + method @Nullable public String getFingerprint(); + method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getPackagePermissions(); + method @NonNull public java.util.Map<java.lang.String,java.util.List<com.android.permission.persistence.RuntimePermissionsState.PermissionState>> getSharedUserPermissions(); + method public int getVersion(); + field public static final int NO_VERSION = -1; // 0xffffffff + } + + public static final class RuntimePermissionsState.PermissionState { + ctor public RuntimePermissionsState.PermissionState(@NonNull String, boolean, int); + method public int getFlags(); + method @NonNull public String getName(); + method public boolean isGranted(); + } + +} + +package com.android.role.persistence { + + public interface RolesPersistence { + method @NonNull public static com.android.role.persistence.RolesPersistence createInstance(); + method public void deleteForUser(@NonNull android.os.UserHandle); + method @Nullable public com.android.role.persistence.RolesState readForUser(@NonNull android.os.UserHandle); + method public void writeForUser(@NonNull com.android.role.persistence.RolesState, @NonNull android.os.UserHandle); + } + + public final class RolesState { + ctor public RolesState(int, @Nullable String, @NonNull java.util.Map<java.lang.String,java.util.Set<java.lang.String>>); + method @Nullable public String getPackagesHash(); + method @NonNull public java.util.Map<java.lang.String,java.util.Set<java.lang.String>> getRoles(); + method public int getVersion(); + } + +} + diff --git a/apex/permission/service/api/system-server-removed.txt b/apex/permission/service/api/system-server-removed.txt new file mode 100644 index 000000000000..d802177e249b --- /dev/null +++ b/apex/permission/service/api/system-server-removed.txt @@ -0,0 +1 @@ +// Signature format: 2.0 diff --git a/apex/permission/tests/Android.bp b/apex/permission/tests/Android.bp index a1f7a544434c..271e328c1139 100644 --- a/apex/permission/tests/Android.bp +++ b/apex/permission/tests/Android.bp @@ -19,7 +19,7 @@ android_test { "java/**/*.kt", ], static_libs: [ - "service-permission", + "service-permission.impl", "androidx.test.rules", "androidx.test.ext.junit", "androidx.test.ext.truth", diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index 22166337cb42..e2fd511a222b 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -450,13 +450,28 @@ message Atom { TvCasSessionOpenStatus tv_cas_session_open_status = 280 [(module) = "framework"]; AssistantInvocationReported assistant_invocation_reported = 281 [(module) = "framework"]; + DisplayWakeReported display_wake_reported = 282 [(module) = "framework"]; + CarUserHalModifyUserRequestReported car_user_hal_modify_user_request_reported = + 283 [(module) = "car"]; + CarUserHalModifyUserResponseReported car_user_hal_modify_user_response_reported = + 284 [(module) = "car"]; + CarUserHalPostSwitchResponseReported car_user_hal_post_switch_response_reported = + 285 [(module) = "car"]; + CarUserHalInitialUserInfoRequestReported car_user_hal_initial_user_info_request_reported = + 286 [(module) = "car"]; + CarUserHalInitialUserInfoResponseReported car_user_hal_initial_user_info_response_reported = + 287 [(module) = "car"]; + CarUserHalUserAssociationRequestReported car_user_hal_user_association_request_reported = + 288 [(module) = "car"]; + CarUserHalSetUserAssociationResponseReported car_user_hal_set_user_association_response_reported = + 289 [(module) = "car"]; // StatsdStats tracks platform atoms with ids upto 500. // Update StatsdStats::kMaxPushedAtomId when atom ids here approach that value. } // Pulled events will start at field 10000. - // Next: 10084 + // Next: 10081 oneof pulled { WifiBytesTransfer wifi_bytes_transfer = 10000 [(module) = "framework"]; WifiBytesTransferByFgBg wifi_bytes_transfer_by_fg_bg = 10001 [(module) = "framework"]; @@ -547,10 +562,11 @@ message Atom { SimSlotState sim_slot_state = 10078 [(module) = "telephony"]; SupportedRadioAccessFamily supported_radio_access_family = 10079 [(module) = "telephony"]; SettingSnapshot setting_snapshot = 10080 [(module) = "framework"]; - DisplayWakeReason display_wake_reason = 10081 [(module) = "framework"]; + //10081 free for use DataUsageBytesTransfer data_usage_bytes_transfer = 10082 [(module) = "framework"]; BytesTransferByTagAndMetered bytes_transfer_by_tag_and_metered = 10083 [(module) = "framework"]; + DNDModeProto dnd_mode_rule = 10084 [(module) = "framework"]; } // DO NOT USE field numbers above 100,000 in AOSP. @@ -6068,6 +6084,76 @@ message PackageNotificationChannelPreferences { } /** + * Atom that represents an item in the list of Do Not Disturb rules, pulled from + * NotificationManagerService.java. + */ +message DNDModeProto { + enum Mode { + ROOT_CONFIG = -1; // Used to distinguish the config (one per user) from the rules. + ZEN_MODE_OFF = 0; + ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; + ZEN_MODE_NO_INTERRUPTIONS = 2; + ZEN_MODE_ALARMS = 3; + } + optional int32 user = 1; // Android user ID (0, 1, 10, ...) + optional bool enabled = 2; // true for ROOT_CONFIG if a manualRule is enabled + optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG + optional Mode zen_mode = 4; + // id is one of the system default rule IDs, or empty + // May also be "MANUAL_RULE" to indicate app-activation of the manual rule. + optional string id = 5; + optional int32 uid = 6 [(is_uid) = true]; // currently only SYSTEM_UID or 0 for other + optional DNDPolicyProto policy = 7; +} + +/** + * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto. + */ +message DNDPolicyProto { + enum State { + STATE_UNSET = 0; + STATE_ALLOW = 1; + STATE_DISALLOW = 2; + } + optional State calls = 1; + optional State repeat_callers = 2; + optional State messages = 3; + optional State conversations = 4; + optional State reminders = 5; + optional State events = 6; + optional State alarms = 7; + optional State media = 8; + optional State system = 9; + optional State fullscreen = 10; + optional State lights = 11; + optional State peek = 12; + optional State status_bar = 13; + optional State badge = 14; + optional State ambient = 15; + optional State notification_list = 16; + + enum PeopleType { + PEOPLE_UNSET = 0; + PEOPLE_ANYONE = 1; + PEOPLE_CONTACTS = 2; + PEOPLE_STARRED = 3; + PEOPLE_NONE = 4; + } + + optional PeopleType allow_calls_from = 17; + optional PeopleType allow_messages_from = 18; + + enum ConversationType { + CONV_UNSET = 0; + CONV_ANYONE = 1; + CONV_IMPORTANT = 2; + CONV_NONE = 3; + } + + optional ConversationType allow_conversations_from = 19; +} + +/** * Atom that contains a list of a package's channel group preferences, pulled from * NotificationManagerService.java. */ @@ -6318,6 +6404,16 @@ message ContentCaptureServiceEvents { SET_WHITELIST = 3; SET_DISABLED = 4; ON_USER_DATA_REMOVED = 5; + ON_DATA_SHARE_REQUEST = 6; + ACCEPT_DATA_SHARE_REQUEST = 7; + REJECT_DATA_SHARE_REQUEST = 8; + DATA_SHARE_WRITE_FINISHED = 9; + DATA_SHARE_ERROR_IOEXCEPTION = 10; + DATA_SHARE_ERROR_EMPTY_DATA = 11; + DATA_SHARE_ERROR_CLIENT_PIPE_FAIL = 12; + DATA_SHARE_ERROR_SERVICE_PIPE_FAIL = 13; + DATA_SHARE_ERROR_CONCURRENT_REQUEST = 14; + DATA_SHARE_ERROR_TIMEOUT_INTERRUPTED = 15; } optional Event event = 1; // component/package of content capture service. @@ -8001,6 +8097,245 @@ message CarPowerStateChanged { } /** + * Logs when Car User Hal is requested to switch/create/remove user. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalModifyUserRequestReported { + // Request id for the request. + optional int32 request_id = 1; + // Request type. + enum RequestType { + UNKNOWN = 0; + // Car user manager requested user switch. + SWITCH_REQUEST_ANDROID = 1; + // OEM requested User switch. + SWITCH_REQUEST_OEM = 2; + // Hal switch requested after android switch using activity manager. + SWITCH_REQUEST_LEGACY = 3; + // Create User + CREATE_REQUEST = 4; + // Remove User + REMOVE_REQUEST = 5; + } + optional RequestType request_type = 2; + // Android User id of the current user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 user_id = 3; + // VHAL flags of the current user. (-1 if not available) + optional int32 user_flags = 4; + // Android User id of the target user for switch/create/remove. It can only + // be 0, 10, 11 and so on. -1 if not available. + optional int32 target_user_id = 5; + // VHAL flags of the target user for switch/create/remove. (-1 if not available) + optional int32 target_user_flags = 6; + // Request timeout Milliseconds (-1 if not available) + optional int32 timeout_millis = 7; +} + +/** + * Logs when Car User Hal responds to switch/create user request. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalModifyUserResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + + // Hal request status for user switch/create/remove. + enum HalRequestStatus { + UNSPECIFIED = 0; + // Hal request for user switch/create is successful. + SUCCESS = 1; + // Hal request for user switch/create failed. + FAILURE = 2; + } + optional HalRequestStatus request_status = 3; +} + +/** + * Logs when post switch response is posted to Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalPostSwitchResponseReported { + // Request id. + optional int32 request_id = 1; + + // Android user switch status. + enum UserSwitchStatus { + UNKNOWN = 0; + // Android user switch is successful. + SUCCESS = 1; + // Android user switch failed. + FAILURE = 2; + } + optional UserSwitchStatus switch_status = 2; +} + +/** + * Logs when initial user information is requested from Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalInitialUserInfoRequestReported { + // Request id for the request. + optional int32 request_id = 1; + + // Request type for initial user information. + enum InitialUserInfoRequestType { + UNKNOWN = 0; + // At the first time Android was booted (or after a factory reset). + FIRST_BOOT = 1; + // At the first time Android was booted after the system was updated. + FIRST_BOOT_AFTER_OTA = 2; + // When Android was booted "from scratch". + COLD_BOOT = 3; + // When Android was resumed after the system was suspended to memory. + RESUME = 4; + } + optional InitialUserInfoRequestType request_type = 2; + // Request timeout Milliseconds (-1 if not available) + optional int32 timeout_millis = 3; +} + +/** + * Logs when Car User Hal responds to initial user information requests. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalInitialUserInfoResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + // Response for initial user information request. + enum InitialUserInfoResponseAction { + UNSPECIFIED = 0; + // Let the Android System decide what to do. + DEFAULT = 1; + // Switch to an existing Android user. + SWITCH = 2; + // Create a new Android user (and switch to it). + CREATE = 3; + } + optional InitialUserInfoResponseAction response_action = 3; + // Android User id of the target user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 target_user = 4; + // VHAL flags of the current user. (-1 if not available) + optional int32 target_user_flags = 5; + // User locales + optional string user_locales = 6; +} + +/** + * Logs when set user association is requested from Car User Hal. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalUserAssociationRequestReported { + // Request id for the request. + optional int32 request_id = 1; + // Request type. + enum RequestType { + UNKNOWN = 0; + // For setting user association information. + SET = 1; + // For getting user association information. + GET = 2; + } + optional RequestType request_type = 2; + // Android User id of the current user which can only be 0, 10, 11 and so on. + // -1 if not available. + optional int32 current_user_id = 3; + // VHAL flags of the current user. (-1 if not available) + optional int32 current_user_flags = 4; + // Number of the set associations requested. + optional int32 number_associations = 5; + // Concatenated string for the types from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_types = 6; + // Concatenated string for the values from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_values = 7; +} + +/** + * Logs when Car User Hal responds to set user association requests. + * + * Logged from: + * packages/services/Car/service/src/com/android/car/hal/UserHalService.java + */ +message CarUserHalSetUserAssociationResponseReported { + // Request id of the request associated with the response. + optional int32 request_id = 1; + // Car user hal callback status. + enum CallbackStatus { + UNKNOWN = 0; + // Hal response was invalid. + INVALID = 1; + // Hal response was ok. + OK = 2; + // Hal timeout during set call. + HAL_SET_TIMEOUT = 3; + // Hal response timeout. + HAL_RESPONSE_TIMEOUT = 4; + // Hal responded with wrong info. + WRONG_HAL_RESPONSE = 5; + // Hal is processing multiple requests simultaneously. + CONCURRENT_OPERATION = 6; + } + optional CallbackStatus callback_status = 2; + // Number of the set associations in the response. + optional int32 number_associations = 3; + // Concatenated string for the types from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_types = 4; + // Concatenated string for the values from set associations request. + // This is a string converted from an array of integers. + optional string user_identification_association_values = 5; +} + +/** * Logs whether GarageMode is entered. * * Logged from: @@ -9817,15 +10152,20 @@ message AccessibilityServiceReported { optional android.stats.accessibility.ServiceStatus service_status = 2; } -message DisplayWakeReason { +/** + * Logs when display wake up. + * + * Logged from: + * services/core/java/com/android/server/power/Notifier.java + */ + +message DisplayWakeReported { // Wake_up_reason code // If LOWORD(wake_up_reason) = 0 // reference to HIWORD(wake_up_reason) PowerManager.WAKE_REASON_XXX // else reference wake_up_reason to - // frameworks/base/services/core/java/com/android/server/power/Notifier.java#DispWakeupReason + // services/core/java/com/android/server/power/Notifier.java#onWakeUp optional int32 wake_up_reason = 1; - // Count of wake up by reason - optional int32 wake_times = 2; } /** diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java index 97b704ccc1c9..b608a343fc7d 100644 --- a/core/java/android/app/ActivityManager.java +++ b/core/java/android/app/ActivityManager.java @@ -601,20 +601,6 @@ public class ActivityManager { @TestApi public static final int PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 2; - // TODO: remove this when development is done. - // These are debug flags used between OomAdjuster and AppOpsService to detect and report absence - // of the real flags. - /** @hide */ - public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q = 1 << 27; - /** @hide */ - public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q = 1 << 28; - /** @hide */ - public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE = 1 << 29; - /** @hide */ - public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA = 1 << 30; - /** @hide */ - public static final int DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION = 1 << 31; - /** @hide all capabilities, the ORing of all flags in {@link ProcessCapability}*/ @TestApi public static final int PROCESS_CAPABILITY_ALL = PROCESS_CAPABILITY_FOREGROUND_LOCATION @@ -653,29 +639,9 @@ public class ActivityManager { */ public static void printCapabilitiesFull(PrintWriter pw, @ProcessCapability int caps) { printCapabilitiesSummary(pw, caps); - if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) { - pw.print(" !L"); - } - if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { - pw.print(" !C"); - } - if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) { - pw.print(" !Cq"); - } - if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { - pw.print(" !M"); - } - if ((caps & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) { - pw.print(" !Mq"); - } final int remain = caps & ~(PROCESS_CAPABILITY_FOREGROUND_LOCATION | PROCESS_CAPABILITY_FOREGROUND_CAMERA - | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - | DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION - | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA - | DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q - | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - | DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q); + | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE); if (remain != 0) { pw.print('+'); pw.print(remain); diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java index c491eea7a674..a5965bc7f85f 100644 --- a/core/java/android/app/ActivityManagerInternal.java +++ b/core/java/android/app/ActivityManagerInternal.java @@ -398,13 +398,6 @@ public abstract class ActivityManagerInternal { */ public abstract boolean isUidCurrentlyInstrumented(int uid); - /** - * Show a debug toast, asking user to file a bugreport. - */ - // TODO: remove this toast after feature development is done - public abstract void showWhileInUseDebugToast(int uid, int op, int mode); - - /** Is this a device owner app? */ public abstract boolean isDeviceOwner(int uid); @@ -429,11 +422,17 @@ public abstract class ActivityManagerInternal { int userId, int[] appIdWhitelist); /** - * Add or delete uid from the ActivityManagerService PendingStartActivityUids list. + * Add uid to the ActivityManagerService PendingStartActivityUids list. + * @param uid uid + * @param pid pid of the ProcessRecord that is pending top. + */ + public abstract void addPendingTopUid(int uid, int pid); + + /** + * Delete uid from the ActivityManagerService PendingStartActivityUids list. * @param uid uid - * @param pending add to the list if true, delete from list if false. */ - public abstract void updatePendingTopUid(int uid, boolean pending); + public abstract void deletePendingTopUid(int uid); /** * Is the uid in ActivityManagerService PendingStartActivityUids list? diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 108b9eec34fb..812ca4aefb9b 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -123,6 +123,7 @@ import android.os.SystemProperties; import android.os.TelephonyServiceManager; import android.os.Trace; import android.os.UserHandle; +import android.os.UserManager; import android.permission.IPermissionManager; import android.provider.BlockedNumberContract; import android.provider.CalendarContract; @@ -6816,7 +6817,11 @@ public final class ActivityThread extends ClientTransactionHandler { throw ex.rethrowFromSystemServer(); } if (holder == null) { - Slog.e(TAG, "Failed to find provider info for " + auth); + if (UserManager.get(c).isUserUnlocked(userId)) { + Slog.e(TAG, "Failed to find provider info for " + auth); + } else { + Slog.w(TAG, "Failed to find provider info for " + auth + " (user not unlocked)"); + } return null; } diff --git a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java index bea1bd6e70d6..b3f9e31abaa4 100644 --- a/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java +++ b/core/java/android/app/contentsuggestions/ContentSuggestionsManager.java @@ -95,7 +95,7 @@ public final class ContentSuggestionsManager { try { mService.provideContextBitmap(mUser, bitmap, imageContextRequestExtras); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -117,7 +117,7 @@ public final class ContentSuggestionsManager { try { mService.provideContextImage(mUser, taskId, imageContextRequestExtras); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -146,7 +146,7 @@ public final class ContentSuggestionsManager { mService.suggestContentSelections( mUser, request, new SelectionsCallbackWrapper(callback, callbackExecutor)); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -173,7 +173,7 @@ public final class ContentSuggestionsManager { mService.classifyContentSelections( mUser, request, new ClassificationsCallbackWrapper(callback, callbackExecutor)); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -193,7 +193,7 @@ public final class ContentSuggestionsManager { try { mService.notifyInteraction(mUser, requestId, interaction); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -213,9 +213,10 @@ public final class ContentSuggestionsManager { mService.isEnabled(mUser, receiver); return receiver.getIntResult() != 0; } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get the enable status."); } - return false; } /** diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java index 6d49add65c5b..23c86029f3be 100644 --- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java @@ -1072,7 +1072,7 @@ public class CameraDeviceImpl extends CameraDevice * @param lastFrameNumber last frame number returned from binder. * @param repeatingRequestTypes the repeating requests' types. */ - private void checkEarlyTriggerSequenceComplete( + private void checkEarlyTriggerSequenceCompleteLocked( final int requestId, final long lastFrameNumber, final int[] repeatingRequestTypes) { // lastFrameNumber being equal to NO_FRAMES_CAPTURED means that the request @@ -1212,7 +1212,7 @@ public class CameraDeviceImpl extends CameraDevice if (repeating) { if (mRepeatingRequestId != REQUEST_ID_NONE) { - checkEarlyTriggerSequenceComplete(mRepeatingRequestId, + checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, requestInfo.getLastFrameNumber(), mRepeatingRequestTypes); } @@ -1269,7 +1269,7 @@ public class CameraDeviceImpl extends CameraDevice return; } - checkEarlyTriggerSequenceComplete(requestId, lastFrameNumber, requestTypes); + checkEarlyTriggerSequenceCompleteLocked(requestId, lastFrameNumber, requestTypes); } } } @@ -1302,7 +1302,7 @@ public class CameraDeviceImpl extends CameraDevice long lastFrameNumber = mRemoteDevice.flush(); if (mRepeatingRequestId != REQUEST_ID_NONE) { - checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber, + checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, lastFrameNumber, mRepeatingRequestTypes); mRepeatingRequestId = REQUEST_ID_NONE; mRepeatingRequestTypes = null; @@ -1442,78 +1442,135 @@ public class CameraDeviceImpl extends CameraDevice long completedFrameNumber = mFrameNumberTracker.getCompletedFrameNumber(); long completedReprocessFrameNumber = mFrameNumberTracker.getCompletedReprocessFrameNumber(); long completedZslStillFrameNumber = mFrameNumberTracker.getCompletedZslStillFrameNumber(); - boolean isReprocess = false; + Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator(); while (iter.hasNext()) { final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); - boolean sequenceCompleted = false; final int requestId = requestLastFrameNumbers.getRequestId(); final CaptureCallbackHolder holder; - synchronized(mInterfaceLock) { - if (mRemoteDevice == null) { - Log.w(TAG, "Camera closed while checking sequences"); - return; + if (mRemoteDevice == null) { + Log.w(TAG, "Camera closed while checking sequences"); + return; + } + if (!requestLastFrameNumbers.isSequenceCompleted()) { + long lastRegularFrameNumber = + requestLastFrameNumbers.getLastRegularFrameNumber(); + long lastReprocessFrameNumber = + requestLastFrameNumbers.getLastReprocessFrameNumber(); + long lastZslStillFrameNumber = + requestLastFrameNumbers.getLastZslStillFrameNumber(); + if (lastRegularFrameNumber <= completedFrameNumber + && lastReprocessFrameNumber <= completedReprocessFrameNumber + && lastZslStillFrameNumber <= completedZslStillFrameNumber) { + Log.v(TAG, String.format( + "Mark requestId %d as completed, because lastRegularFrame %d " + + "is <= %d, lastReprocessFrame %d is <= %d, " + + "lastZslStillFrame %d is <= %d", requestId, + lastRegularFrameNumber, completedFrameNumber, + lastReprocessFrameNumber, completedReprocessFrameNumber, + lastZslStillFrameNumber, completedZslStillFrameNumber)); + requestLastFrameNumbers.markSequenceCompleted(); } + // Call onCaptureSequenceCompleted int index = mCaptureCallbackMap.indexOfKey(requestId); holder = (index >= 0) ? mCaptureCallbackMap.valueAt(index) : null; - if (holder != null) { - long lastRegularFrameNumber = - requestLastFrameNumbers.getLastRegularFrameNumber(); - long lastReprocessFrameNumber = - requestLastFrameNumbers.getLastReprocessFrameNumber(); - long lastZslStillFrameNumber = - requestLastFrameNumbers.getLastZslStillFrameNumber(); - // check if it's okay to remove request from mCaptureCallbackMap - if (lastRegularFrameNumber <= completedFrameNumber - && lastReprocessFrameNumber <= completedReprocessFrameNumber - && lastZslStillFrameNumber <= completedZslStillFrameNumber) { - sequenceCompleted = true; - mCaptureCallbackMap.removeAt(index); - if (DEBUG) { - Log.v(TAG, String.format( - "Remove holder for requestId %d, because lastRegularFrame %d " - + "is <= %d, lastReprocessFrame %d is <= %d, " - + "lastZslStillFrame %d is <= %d", requestId, - lastRegularFrameNumber, completedFrameNumber, - lastReprocessFrameNumber, completedReprocessFrameNumber, - lastZslStillFrameNumber, completedZslStillFrameNumber)); + if (holder != null && requestLastFrameNumbers.isSequenceCompleted()) { + Runnable resultDispatch = new Runnable() { + @Override + public void run() { + if (!CameraDeviceImpl.this.isClosed()){ + if (DEBUG) { + Log.d(TAG, String.format( + "fire sequence complete for request %d", + requestId)); + } + + holder.getCallback().onCaptureSequenceCompleted( + CameraDeviceImpl.this, + requestId, + requestLastFrameNumbers.getLastFrameNumber()); + } } + }; + final long ident = Binder.clearCallingIdentity(); + try { + holder.getExecutor().execute(resultDispatch); + } finally { + Binder.restoreCallingIdentity(ident); } } } - // If no callback is registered for this requestId or sequence completed, remove it - // from the frame number->request pair because it's not needed anymore. - if (holder == null || sequenceCompleted) { + if (requestLastFrameNumbers.isSequenceCompleted() && + requestLastFrameNumbers.isInflightCompleted()) { + int index = mCaptureCallbackMap.indexOfKey(requestId); + if (index >= 0) { + mCaptureCallbackMap.removeAt(index); + } + if (DEBUG) { + Log.v(TAG, String.format( + "Remove holder for requestId %d", requestId)); + } iter.remove(); } + } + } - // Call onCaptureSequenceCompleted - if (sequenceCompleted) { - Runnable resultDispatch = new Runnable() { - @Override - public void run() { - if (!CameraDeviceImpl.this.isClosed()){ - if (DEBUG) { - Log.d(TAG, String.format( - "fire sequence complete for request %d", - requestId)); - } + private void removeCompletedCallbackHolderLocked(long lastCompletedRegularFrameNumber, + long lastCompletedReprocessFrameNumber, long lastCompletedZslStillFrameNumber) { + if (DEBUG) { + Log.v(TAG, String.format("remove completed callback holders for " + + "lastCompletedRegularFrameNumber %d, " + + "lastCompletedReprocessFrameNumber %d, " + + "lastCompletedZslStillFrameNumber %d", + lastCompletedRegularFrameNumber, + lastCompletedReprocessFrameNumber, + lastCompletedZslStillFrameNumber)); + } - holder.getCallback().onCaptureSequenceCompleted( - CameraDeviceImpl.this, - requestId, - requestLastFrameNumbers.getLastFrameNumber()); - } + Iterator<RequestLastFrameNumbersHolder> iter = mRequestLastFrameNumbersList.iterator(); + while (iter.hasNext()) { + final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); + final int requestId = requestLastFrameNumbers.getRequestId(); + final CaptureCallbackHolder holder; + if (mRemoteDevice == null) { + Log.w(TAG, "Camera closed while removing completed callback holders"); + return; + } + + long lastRegularFrameNumber = + requestLastFrameNumbers.getLastRegularFrameNumber(); + long lastReprocessFrameNumber = + requestLastFrameNumbers.getLastReprocessFrameNumber(); + long lastZslStillFrameNumber = + requestLastFrameNumbers.getLastZslStillFrameNumber(); + + if (lastRegularFrameNumber <= lastCompletedRegularFrameNumber + && lastReprocessFrameNumber <= lastCompletedReprocessFrameNumber + && lastZslStillFrameNumber <= lastCompletedZslStillFrameNumber) { + + if (requestLastFrameNumbers.isSequenceCompleted()) { + int index = mCaptureCallbackMap.indexOfKey(requestId); + if (index >= 0) { + mCaptureCallbackMap.removeAt(index); } - }; - final long ident = Binder.clearCallingIdentity(); - try { - holder.getExecutor().execute(resultDispatch); - } finally { - Binder.restoreCallingIdentity(ident); + if (DEBUG) { + Log.v(TAG, String.format( + "Remove holder for requestId %d, because lastRegularFrame %d " + + "is <= %d, lastReprocessFrame %d is <= %d, " + + "lastZslStillFrame %d is <= %d", requestId, + lastRegularFrameNumber, lastCompletedRegularFrameNumber, + lastReprocessFrameNumber, lastCompletedReprocessFrameNumber, + lastZslStillFrameNumber, lastCompletedZslStillFrameNumber)); + } + iter.remove(); + } else { + if (DEBUG) { + Log.v(TAG, "Sequence not yet completed for request id " + requestId); + } + requestLastFrameNumbers.markInflightCompleted(); } } } @@ -1702,6 +1759,12 @@ public class CameraDeviceImpl extends CameraDevice return; } + // Remove all capture callbacks now that device has gone to IDLE state. + removeCompletedCallbackHolderLocked( + Long.MAX_VALUE, /*lastCompletedRegularFrameNumber*/ + Long.MAX_VALUE, /*lastCompletedReprocessFrameNumber*/ + Long.MAX_VALUE /*lastCompletedZslStillFrameNumber*/); + if (!CameraDeviceImpl.this.mIdle) { final long ident = Binder.clearCallingIdentity(); try { @@ -1747,7 +1810,7 @@ public class CameraDeviceImpl extends CameraDevice return; } - checkEarlyTriggerSequenceComplete(mRepeatingRequestId, lastFrameNumber, + checkEarlyTriggerSequenceCompleteLocked(mRepeatingRequestId, lastFrameNumber, mRepeatingRequestTypes); // Check if there is already a new repeating request if (mRepeatingRequestId == repeatingRequestId) { @@ -1766,9 +1829,18 @@ public class CameraDeviceImpl extends CameraDevice public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { int requestId = resultExtras.getRequestId(); final long frameNumber = resultExtras.getFrameNumber(); + final long lastCompletedRegularFrameNumber = + resultExtras.getLastCompletedRegularFrameNumber(); + final long lastCompletedReprocessFrameNumber = + resultExtras.getLastCompletedReprocessFrameNumber(); + final long lastCompletedZslFrameNumber = + resultExtras.getLastCompletedZslFrameNumber(); if (DEBUG) { - Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber); + Log.d(TAG, "Capture started for id " + requestId + " frame number " + frameNumber + + ": completedRegularFrameNumber " + lastCompletedRegularFrameNumber + + ", completedReprocessFrameNUmber " + lastCompletedReprocessFrameNumber + + ", completedZslFrameNumber " + lastCompletedZslFrameNumber); } final CaptureCallbackHolder holder; @@ -1784,6 +1856,12 @@ public class CameraDeviceImpl extends CameraDevice return; } + // Check if it's okay to remove completed callbacks from mCaptureCallbackMap. + // A callback is completed if the corresponding inflight request has been removed + // from the inflight queue in cameraservice. + removeCompletedCallbackHolderLocked(lastCompletedRegularFrameNumber, + lastCompletedReprocessFrameNumber, lastCompletedZslFrameNumber); + // Get the callback for this frame ID, if there is one holder = CameraDeviceImpl.this.mCaptureCallbackMap.get(requestId); diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java index 1d9d644c9306..413caf5e22e0 100644 --- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java +++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java @@ -182,6 +182,12 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession return; } + // Remove all capture callbacks now that device has gone to IDLE state. + removeCompletedCallbackHolderLocked( + Long.MAX_VALUE, /*lastCompletedRegularFrameNumber*/ + Long.MAX_VALUE, /*lastCompletedReprocessFrameNumber*/ + Long.MAX_VALUE /*lastCompletedZslStillFrameNumber*/); + Runnable idleDispatch = new Runnable() { @Override public void run() { @@ -204,10 +210,22 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession public void onCaptureStarted(final CaptureResultExtras resultExtras, final long timestamp) { int requestId = resultExtras.getRequestId(); final long frameNumber = resultExtras.getFrameNumber(); + final long lastCompletedRegularFrameNumber = + resultExtras.getLastCompletedRegularFrameNumber(); + final long lastCompletedReprocessFrameNumber = + resultExtras.getLastCompletedReprocessFrameNumber(); + final long lastCompletedZslFrameNumber = + resultExtras.getLastCompletedZslFrameNumber(); final CaptureCallbackHolder holder; synchronized(mInterfaceLock) { + // Check if it's okay to remove completed callbacks from mCaptureCallbackMap. + // A callback is completed if the corresponding inflight request has been removed + // from the inflight queue in cameraservice. + removeCompletedCallbackHolderLocked(lastCompletedRegularFrameNumber, + lastCompletedReprocessFrameNumber, lastCompletedZslFrameNumber); + // Get the callback for this frame ID, if there is one holder = CameraOfflineSessionImpl.this.mCaptureCallbackMap.get(requestId); @@ -601,6 +619,61 @@ public class CameraOfflineSessionImpl extends CameraOfflineSession } } + private void removeCompletedCallbackHolderLocked(long lastCompletedRegularFrameNumber, + long lastCompletedReprocessFrameNumber, long lastCompletedZslStillFrameNumber) { + if (DEBUG) { + Log.v(TAG, String.format("remove completed callback holders for " + + "lastCompletedRegularFrameNumber %d, " + + "lastCompletedReprocessFrameNumber %d, " + + "lastCompletedZslStillFrameNumber %d", + lastCompletedRegularFrameNumber, + lastCompletedReprocessFrameNumber, + lastCompletedZslStillFrameNumber)); + } + + boolean isReprocess = false; + Iterator<RequestLastFrameNumbersHolder> iter = + mOfflineRequestLastFrameNumbersList.iterator(); + while (iter.hasNext()) { + final RequestLastFrameNumbersHolder requestLastFrameNumbers = iter.next(); + final int requestId = requestLastFrameNumbers.getRequestId(); + final CaptureCallbackHolder holder; + + int index = mCaptureCallbackMap.indexOfKey(requestId); + holder = (index >= 0) ? + mCaptureCallbackMap.valueAt(index) : null; + if (holder != null) { + long lastRegularFrameNumber = + requestLastFrameNumbers.getLastRegularFrameNumber(); + long lastReprocessFrameNumber = + requestLastFrameNumbers.getLastReprocessFrameNumber(); + long lastZslStillFrameNumber = + requestLastFrameNumbers.getLastZslStillFrameNumber(); + if (lastRegularFrameNumber <= lastCompletedRegularFrameNumber + && lastReprocessFrameNumber <= lastCompletedReprocessFrameNumber + && lastZslStillFrameNumber <= lastCompletedZslStillFrameNumber) { + if (requestLastFrameNumbers.isSequenceCompleted()) { + mCaptureCallbackMap.removeAt(index); + if (DEBUG) { + Log.v(TAG, String.format( + "Remove holder for requestId %d, because lastRegularFrame %d " + + "is <= %d, lastReprocessFrame %d is <= %d, " + + "lastZslStillFrame %d is <= %d", requestId, + lastRegularFrameNumber, lastCompletedRegularFrameNumber, + lastReprocessFrameNumber, lastCompletedReprocessFrameNumber, + lastZslStillFrameNumber, lastCompletedZslStillFrameNumber)); + } + + iter.remove(); + } else { + Log.e(TAG, "Sequence not yet completed for request id " + requestId); + continue; + } + } + } + } + } + public void notifyFailedSwitch() { synchronized(mInterfaceLock) { Runnable switchFailDispatch = new Runnable() { diff --git a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java index 1ff5bd562f2e..5d9da73fd5c0 100644 --- a/core/java/android/hardware/camera2/impl/CaptureResultExtras.java +++ b/core/java/android/hardware/camera2/impl/CaptureResultExtras.java @@ -30,6 +30,9 @@ public class CaptureResultExtras implements Parcelable { private int partialResultCount; private int errorStreamId; private String errorPhysicalCameraId; + private long lastCompletedRegularFrameNumber; + private long lastCompletedReprocessFrameNumber; + private long lastCompletedZslFrameNumber; public static final @android.annotation.NonNull Parcelable.Creator<CaptureResultExtras> CREATOR = new Parcelable.Creator<CaptureResultExtras>() { @@ -51,7 +54,9 @@ public class CaptureResultExtras implements Parcelable { public CaptureResultExtras(int requestId, int subsequenceId, int afTriggerId, int precaptureTriggerId, long frameNumber, int partialResultCount, int errorStreamId, - String errorPhysicalCameraId) { + String errorPhysicalCameraId, long lastCompletedRegularFrameNumber, + long lastCompletedReprocessFrameNumber, + long lastCompletedZslFrameNumber) { this.requestId = requestId; this.subsequenceId = subsequenceId; this.afTriggerId = afTriggerId; @@ -60,6 +65,9 @@ public class CaptureResultExtras implements Parcelable { this.partialResultCount = partialResultCount; this.errorStreamId = errorStreamId; this.errorPhysicalCameraId = errorPhysicalCameraId; + this.lastCompletedRegularFrameNumber = lastCompletedRegularFrameNumber; + this.lastCompletedReprocessFrameNumber = lastCompletedReprocessFrameNumber; + this.lastCompletedZslFrameNumber = lastCompletedZslFrameNumber; } @Override @@ -82,6 +90,9 @@ public class CaptureResultExtras implements Parcelable { } else { dest.writeBoolean(false); } + dest.writeLong(lastCompletedRegularFrameNumber); + dest.writeLong(lastCompletedReprocessFrameNumber); + dest.writeLong(lastCompletedZslFrameNumber); } public void readFromParcel(Parcel in) { @@ -96,6 +107,9 @@ public class CaptureResultExtras implements Parcelable { if (errorPhysicalCameraIdPresent) { errorPhysicalCameraId = in.readString(); } + lastCompletedRegularFrameNumber = in.readLong(); + lastCompletedReprocessFrameNumber = in.readLong(); + lastCompletedZslFrameNumber = in.readLong(); } public String getErrorPhysicalCameraId() { @@ -129,4 +143,16 @@ public class CaptureResultExtras implements Parcelable { public int getErrorStreamId() { return errorStreamId; } + + public long getLastCompletedRegularFrameNumber() { + return lastCompletedRegularFrameNumber; + } + + public long getLastCompletedReprocessFrameNumber() { + return lastCompletedReprocessFrameNumber; + } + + public long getLastCompletedZslFrameNumber() { + return lastCompletedZslFrameNumber; + } } diff --git a/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java b/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java index bd1df9e1ac7d..0ee4ebc1aa87 100644 --- a/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java +++ b/core/java/android/hardware/camera2/impl/RequestLastFrameNumbersHolder.java @@ -38,6 +38,10 @@ public class RequestLastFrameNumbersHolder { // The last ZSL still capture frame number for this request ID. It's // CaptureCallback.NO_FRAMES_CAPTURED if the request ID has no zsl request. private final long mLastZslStillFrameNumber; + // Whether the sequence is completed. (only consider capture result) + private boolean mSequenceCompleted; + // Whether the inflight request is completed. (consider result, buffers, and notifies) + private boolean mInflightCompleted; /** * Create a request-last-frame-numbers holder with a list of requests, request ID, and @@ -89,6 +93,8 @@ public class RequestLastFrameNumbersHolder { mLastReprocessFrameNumber = lastReprocessFrameNumber; mLastZslStillFrameNumber = lastZslStillFrameNumber; mRequestId = requestInfo.getRequestId(); + mSequenceCompleted = false; + mInflightCompleted = false; } /** @@ -137,6 +143,8 @@ public class RequestLastFrameNumbersHolder { mLastZslStillFrameNumber = lastZslStillFrameNumber; mLastReprocessFrameNumber = CameraCaptureSession.CaptureCallback.NO_FRAMES_CAPTURED; mRequestId = requestId; + mSequenceCompleted = false; + mInflightCompleted = false; } /** @@ -177,5 +185,34 @@ public class RequestLastFrameNumbersHolder { public int getRequestId() { return mRequestId; } + + /** + * Return whether the capture sequence is completed. + */ + public boolean isSequenceCompleted() { + return mSequenceCompleted; + } + + /** + * Mark the capture sequence as completed. + */ + public void markSequenceCompleted() { + mSequenceCompleted = true; + } + + /** + * Return whether the inflight capture is completed. + */ + public boolean isInflightCompleted() { + return mInflightCompleted; + } + + /** + * Mark the inflight capture as completed. + */ + public void markInflightCompleted() { + mInflightCompleted = true; + } + } diff --git a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java index fbc9ac3229c3..fdd578c419d8 100644 --- a/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java +++ b/core/java/android/hardware/camera2/legacy/LegacyCameraDevice.java @@ -109,11 +109,12 @@ public class LegacyCameraDevice implements AutoCloseable { } if (holder == null) { return new CaptureResultExtras(ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, - ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, null); + ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE, null, + ILLEGAL_VALUE, ILLEGAL_VALUE, ILLEGAL_VALUE); } return new CaptureResultExtras(holder.getRequestId(), holder.getSubsequeceId(), /*afTriggerId*/0, /*precaptureTriggerId*/0, holder.getFrameNumber(), - /*partialResultCount*/1, errorStreamId, null); + /*partialResultCount*/1, errorStreamId, null, holder.getFrameNumber(), -1, -1); } /** diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java index 1f6555c85a66..0827fef60252 100644 --- a/core/java/android/service/notification/ZenModeConfig.java +++ b/core/java/android/service/notification/ZenModeConfig.java @@ -78,6 +78,7 @@ public class ZenModeConfig implements Parcelable { private static final int DEFAULT_SOURCE = SOURCE_CONTACT; private static final int DEFAULT_CALLS_SOURCE = SOURCE_STAR; + public static final String MANUAL_RULE_ID = "MANUAL_RULE"; public static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE"; public static final String EVERY_NIGHT_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE"; public static final List<String> DEFAULT_RULE_IDS = Arrays.asList(EVERY_NIGHT_DEFAULT_RULE_ID, @@ -959,6 +960,48 @@ public class ZenModeConfig implements Parcelable { }; /** + * Converts a ZenModeConfig to a ZenPolicy + */ + public ZenPolicy toZenPolicy() { + ZenPolicy.Builder builder = new ZenPolicy.Builder() + .allowCalls(allowCalls + ? ZenModeConfig.getZenPolicySenders(allowCallsFrom) + : ZenPolicy.PEOPLE_TYPE_NONE) + .allowRepeatCallers(allowRepeatCallers) + .allowMessages(allowMessages + ? ZenModeConfig.getZenPolicySenders(allowMessagesFrom) + : ZenPolicy.PEOPLE_TYPE_NONE) + .allowReminders(allowReminders) + .allowEvents(allowEvents) + .allowAlarms(allowAlarms) + .allowMedia(allowMedia) + .allowSystem(allowSystem) + .allowConversations(allowConversations + ? ZenModeConfig.getZenPolicySenders(allowConversationsFrom) + : ZenPolicy.PEOPLE_TYPE_NONE); + if (suppressedVisualEffects == 0) { + builder.showAllVisualEffects(); + } else { + // configs don't have an unset state: wither true or false. + builder.showFullScreenIntent( + (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT) == 0); + builder.showLights( + (suppressedVisualEffects & SUPPRESSED_EFFECT_LIGHTS) == 0); + builder.showPeeking( + (suppressedVisualEffects & SUPPRESSED_EFFECT_PEEK) == 0); + builder.showStatusBarIcons( + (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_STATUS_BAR) == 0); + builder.showBadges( + (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_BADGE) == 0); + builder.showInAmbientDisplay( + (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_AMBIENT) == 0); + builder.showInNotificationList( + (suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_NOTIFICATION_LIST) == 0); + } + return builder.build(); + } + + /** * Converts a zenPolicy to a notificationPolicy using this ZenModeConfig's values as its * defaults for all unset values in zenPolicy */ diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java index 87295e1c95b9..6d0bcffe148e 100644 --- a/core/java/android/service/notification/ZenPolicy.java +++ b/core/java/android/service/notification/ZenPolicy.java @@ -24,6 +24,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.util.proto.ProtoOutputStream; +import java.io.ByteArrayOutputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; @@ -1111,6 +1112,40 @@ public final class ZenPolicy implements Parcelable { } /** + * Converts a policy to a statsd proto. + * @hides + */ + public byte[] toProto() { + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + ProtoOutputStream proto = new ProtoOutputStream(bytes); + + proto.write(DNDPolicyProto.CALLS, getPriorityCategoryCalls()); + proto.write(DNDPolicyProto.REPEAT_CALLERS, getPriorityCategoryRepeatCallers()); + proto.write(DNDPolicyProto.MESSAGES, getPriorityCategoryMessages()); + proto.write(DNDPolicyProto.CONVERSATIONS, getPriorityCategoryConversations()); + proto.write(DNDPolicyProto.REMINDERS, getPriorityCategoryReminders()); + proto.write(DNDPolicyProto.EVENTS, getPriorityCategoryEvents()); + proto.write(DNDPolicyProto.ALARMS, getPriorityCategoryAlarms()); + proto.write(DNDPolicyProto.MEDIA, getPriorityCategoryMedia()); + proto.write(DNDPolicyProto.SYSTEM, getPriorityCategorySystem()); + + proto.write(DNDPolicyProto.FULLSCREEN, getVisualEffectFullScreenIntent()); + proto.write(DNDPolicyProto.LIGHTS, getVisualEffectLights()); + proto.write(DNDPolicyProto.PEEK, getVisualEffectPeek()); + proto.write(DNDPolicyProto.STATUS_BAR, getVisualEffectStatusBar()); + proto.write(DNDPolicyProto.BADGE, getVisualEffectBadge()); + proto.write(DNDPolicyProto.AMBIENT, getVisualEffectAmbient()); + proto.write(DNDPolicyProto.NOTIFICATION_LIST, getVisualEffectNotificationList()); + + proto.write(DNDPolicyProto.ALLOW_CALLS_FROM, getPriorityCallSenders()); + proto.write(DNDPolicyProto.ALLOW_MESSAGES_FROM, getPriorityMessageSenders()); + proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders()); + + proto.flush(); + return bytes.toByteArray(); + } + + /** * Makes deep copy of this ZenPolicy. * @hide */ diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java index 9b293eb463e5..ef21900dc3e3 100644 --- a/core/java/android/telephony/PhoneStateListener.java +++ b/core/java/android/telephony/PhoneStateListener.java @@ -157,8 +157,8 @@ public class PhoneStateListener { * Listen for changes to the device's cell location. Note that * this will result in frequent callbacks to the listener. * {@more} - * Requires Permission: {@link android.Manifest.permission#ACCESS_COARSE_LOCATION - * ACCESS_COARSE_LOCATION} + * Requires Permission: {@link android.Manifest.permission#ACCESS_FINE_LOCATION + * ACCESS_FINE_LOCATION} * <p> * If you need regular location updates but want more control over * the update interval or location precision, you can set up a listener diff --git a/core/java/android/view/ImeFocusController.java b/core/java/android/view/ImeFocusController.java index a4800726bbe8..825077ffd57a 100644 --- a/core/java/android/view/ImeFocusController.java +++ b/core/java/android/view/ImeFocusController.java @@ -125,6 +125,13 @@ public final class ImeFocusController { final View viewForWindowFocus = focusedView != null ? focusedView : mViewRootImpl.mView; onViewFocusChanged(viewForWindowFocus, true); + // Skip starting input when the next focused view is same as served view and the served + // input connection still exists. + final boolean nextFocusIsServedView = mServedView != null && mServedView == focusedView; + if (nextFocusIsServedView && immDelegate.isAcceptingText()) { + forceFocus = false; + } + immDelegate.startInputAsyncOnWindowFocusGain(viewForWindowFocus, windowAttribute.softInputMode, windowAttribute.flags, forceFocus); } @@ -247,6 +254,7 @@ public final class ImeFocusController { void setCurrentRootView(ViewRootImpl rootView); boolean isCurrentRootView(ViewRootImpl rootView); boolean isRestartOnNextWindowFocus(boolean reset); + boolean isAcceptingText(); } public View getServedView() { diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index ef9edc6c0741..e4d53c64a063 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -791,7 +791,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation WindowInsetsAnimationControlListener listener, boolean fromIme, long durationMs, @Nullable Interpolator interpolator, @AnimationType int animationType) { - if (!checkDisplayFramesForControlling()) { + if ((mState.calculateUncontrollableInsetsFromFrame(mFrame) & types) != 0) { listener.onCancelled(null); return; } @@ -801,13 +801,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation false /* useInsetsAnimationThread */); } - private boolean checkDisplayFramesForControlling() { - - // If the frame of our window doesn't span the entire display, the control API makes very - // little sense, as we don't deal with negative insets. So just cancel immediately. - return mState.getDisplayFrame().equals(mFrame); - } - private void controlAnimationUnchecked(@InsetsType int types, @Nullable CancellationSignal cancellationSignal, WindowInsetsAnimationControlListener listener, Rect frame, boolean fromIme, @@ -1285,9 +1278,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } private @InsetsType int calculateControllableTypes() { - if (!checkDisplayFramesForControlling()) { - return 0; - } @InsetsType int result = 0; for (int i = mSourceConsumers.size() - 1; i >= 0; i--) { InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i); @@ -1295,7 +1285,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation result |= toPublicType(consumer.mType); } } - return result; + return result & ~mState.calculateUncontrollableInsetsFromFrame(mFrame); } /** diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 3822ee59b4aa..f0bca260be38 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -245,6 +245,44 @@ public class InsetsState implements Parcelable { return insets.toRect(); } + /** + * Calculate which insets *cannot* be controlled, because the frame does not cover the + * respective side of the inset. + * + * If the frame of our window doesn't cover the entire inset, the control API makes very + * little sense, as we don't deal with negative insets. + */ + @InsetsType + public int calculateUncontrollableInsetsFromFrame(Rect frame) { + int blocked = 0; + for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) { + InsetsSource source = mSources.get(type); + if (source == null) { + continue; + } + if (!canControlSide(frame, getInsetSide( + source.calculateInsets(frame, true /* ignoreVisibility */)))) { + blocked |= toPublicType(type); + } + } + return blocked; + } + + private boolean canControlSide(Rect frame, int side) { + switch (side) { + case ISIDE_LEFT: + case ISIDE_RIGHT: + return frame.left == mDisplayFrame.left && frame.right == mDisplayFrame.right; + case ISIDE_TOP: + case ISIDE_BOTTOM: + return frame.top == mDisplayFrame.top && frame.bottom == mDisplayFrame.bottom; + case ISIDE_FLOATING: + return true; + default: + return false; + } + } + private void processSource(InsetsSource source, Rect relativeFrame, boolean ignoreVisibility, Insets[] typeInsetsMap, @Nullable @InternalInsetsSide SparseIntArray typeSideMap, @Nullable boolean[] typeVisibilityMap) { diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java index eaaaa80f65ed..214da380ccda 100644 --- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java +++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java @@ -635,7 +635,7 @@ public class AccessibilityNodeInfo implements Parcelable { "android.view.accessibility.extra.DATA_TEXT_CHARACTER_LOCATION_ARG_LENGTH"; /** - * Key used to request extra data for accessibility scanning tool's purposes. + * Key used to request extra data for the rendering information. * The key requests that a {@link AccessibilityNodeInfo.ExtraRenderingInfo} be added to this * info. This request is made with {@link #refreshWithExtraData(String, Bundle)} without * argument. @@ -5847,12 +5847,15 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets the size object containing the height and the width of layout params if the node is - * a {@link ViewGroup} or a {@link TextView}, or null otherwise. Useful for accessibility - * scanning tool to understand whether the text is scalable and fits the view or not. + * Gets the size object containing the height and the width of + * {@link android.view.ViewGroup.LayoutParams} if the node is a {@link ViewGroup} or + * a {@link TextView}, or null otherwise. Useful for some accessibility services to + * understand whether the text is scalable and fits the view or not. * - * @return a {@link Size} stores layout height and layout width of the view, - * or null otherwise. + * @return a {@link Size} stores layout height and layout width of the view, or null + * otherwise. And the size value may be in pixels, + * {@link android.view.ViewGroup.LayoutParams#MATCH_PARENT}, + * or {@link android.view.ViewGroup.LayoutParams#WRAP_CONTENT} */ public @Nullable Size getLayoutSize() { return mLayoutSize; @@ -5870,9 +5873,9 @@ public class AccessibilityNodeInfo implements Parcelable { } /** - * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for - * accessibility scanning tool to understand whether the text is scalable and fits the view - * or not. + * Gets the text size if the node is a {@link TextView}, or -1 otherwise. Useful for some + * accessibility services to understand whether the text is scalable and fits the view or + * not. * * @return the text size of a {@code TextView}, or -1 otherwise. */ @@ -5893,7 +5896,7 @@ public class AccessibilityNodeInfo implements Parcelable { /** * Gets the text size unit if the node is a {@link TextView}, or -1 otherwise. * Text size returned from {@link #getTextSizeInPx} in raw pixels may scale by factors and - * convert from other units. Useful for accessibility scanning tool to understand whether + * convert from other units. Useful for some accessibility services to understand whether * the text is scalable and fits the view or not. * * @return the text size unit which type is {@link TypedValue#TYPE_DIMENSION} of a diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java index 3112039c36d8..fbfeda6f0bcc 100644 --- a/core/java/android/view/autofill/AutofillManager.java +++ b/core/java/android/view/autofill/AutofillManager.java @@ -751,6 +751,8 @@ public final class AutofillManager { } } catch (RemoteException e) { Log.e(TAG, "Could not figure out if there was an autofill session", e); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get session restore status: " + e); } } } @@ -864,7 +866,9 @@ public final class AutofillManager { mService.getFillEventHistory(receiver); return receiver.getParcelableResult(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get fill event history: " + e); return null; } } @@ -1477,10 +1481,13 @@ public final class AutofillManager { final SyncResultReceiver receiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); try { - mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), receiver); + mService.isServiceEnabled(mContext.getUserId(), mContext.getPackageName(), + receiver); return receiver.getIntResult() == 1; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get enabled autofill services status."); } } @@ -1498,6 +1505,8 @@ public final class AutofillManager { return receiver.getParcelableResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get autofill services component name."); } } @@ -1522,8 +1531,9 @@ public final class AutofillManager { mService.getUserDataId(receiver); return receiver.getStringResult(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return null; + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get user data id for field classification."); } } @@ -1544,8 +1554,9 @@ public final class AutofillManager { mService.getUserData(receiver); return receiver.getParcelableResult(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return null; + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get user data for field classification."); } } @@ -1561,7 +1572,7 @@ public final class AutofillManager { try { mService.setUserData(userData); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -1583,8 +1594,9 @@ public final class AutofillManager { mService.isFieldClassificationEnabled(receiver); return receiver.getIntResult() == 1; } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return false; + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get field classification enabled status."); } } @@ -1606,8 +1618,9 @@ public final class AutofillManager { mService.getDefaultFieldClassificationAlgorithm(receiver); return receiver.getStringResult(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return null; + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get default field classification algorithm."); } } @@ -1627,8 +1640,9 @@ public final class AutofillManager { final String[] algorithms = receiver.getStringArrayResult(); return algorithms != null ? Arrays.asList(algorithms) : Collections.emptyList(); } catch (RemoteException e) { - e.rethrowFromSystemServer(); - return null; + throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get available field classification algorithms."); } } @@ -1651,6 +1665,8 @@ public final class AutofillManager { return receiver.getIntResult() == 1; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get autofill supported status."); } } @@ -2040,13 +2056,16 @@ public final class AutofillManager { } final SyncResultReceiver resultReceiver = new SyncResultReceiver(SYNC_CALLS_TIMEOUT_MS); - final int resultCode; + int resultCode; try { mService.setAugmentedAutofillWhitelist(toList(packages), toList(activities), resultReceiver); resultCode = resultReceiver.getIntResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get the result of set AugmentedAutofill whitelist. " + e); + return; } switch (resultCode) { case RESULT_OK: @@ -2283,7 +2302,7 @@ public final class AutofillManager { // In theory, we could ignore this error since it's not a big deal, but // in reality, we rather crash the app anyways, as the failure could be // a consequence of something going wrong on the server side... - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -2661,7 +2680,7 @@ public final class AutofillManager { try { mService.onPendingSaveUi(operation, token); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + Log.e(TAG, "Error in onPendingSaveUi: ", e); } } } diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java index 756ff78e5906..484b1c10423c 100644 --- a/core/java/android/view/contentcapture/ContentCaptureManager.java +++ b/core/java/android/view/contentcapture/ContentCaptureManager.java @@ -487,6 +487,8 @@ public final class ContentCaptureManager { return resultReceiver.getParcelableResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get service componentName."); } } @@ -516,6 +518,9 @@ public final class ContentCaptureManager { return resultReceiver.getParcelableResult(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get service settings componentName: " + e); + return null; } } @@ -567,9 +572,13 @@ public final class ContentCaptureManager { final SyncResultReceiver resultReceiver = syncRun( (r) -> mService.getContentCaptureConditions(mContext.getPackageName(), r)); - final ArrayList<ContentCaptureCondition> result = resultReceiver - .getParcelableListResult(); - return toSet(result); + try { + final ArrayList<ContentCaptureCondition> result = resultReceiver + .getParcelableListResult(); + return toSet(result); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get content capture conditions."); + } } /** @@ -639,15 +648,21 @@ public final class ContentCaptureManager { public boolean isContentCaptureFeatureEnabled() { final SyncResultReceiver resultReceiver = syncRun( (r) -> mService.isContentCaptureFeatureEnabled(r)); - final int resultCode = resultReceiver.getIntResult(); - switch (resultCode) { - case RESULT_CODE_TRUE: - return true; - case RESULT_CODE_FALSE: - return false; - default: - Log.wtf(TAG, "received invalid result: " + resultCode); - return false; + + try { + final int resultCode = resultReceiver.getIntResult(); + switch (resultCode) { + case RESULT_CODE_TRUE: + return true; + case RESULT_CODE_FALSE: + return false; + default: + Log.wtf(TAG, "received invalid result: " + resultCode); + return false; + } + } catch (SyncResultReceiver.TimeoutException e) { + Log.e(TAG, "Fail to get content capture feature enable status: " + e); + return false; } } @@ -663,7 +678,7 @@ public final class ContentCaptureManager { try { mService.removeData(request); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -691,7 +706,7 @@ public final class ContentCaptureManager { new DataShareAdapterDelegate(executor, dataShareWriteAdapter, mDataShareAdapterResourceManager)); } catch (RemoteException e) { - e.rethrowFromSystemServer(); + throw e.rethrowFromSystemServer(); } } @@ -709,10 +724,12 @@ public final class ContentCaptureManager { if (resultCode == RESULT_CODE_SECURITY_EXCEPTION) { throw new SecurityException(resultReceiver.getStringResult()); } - return resultReceiver; } catch (RemoteException e) { throw e.rethrowFromSystemServer(); + } catch (SyncResultReceiver.TimeoutException e) { + throw new RuntimeException("Fail to get syn run result from SyncResultReceiver."); } + return resultReceiver; } /** @hide */ diff --git a/core/java/android/view/inputmethod/InlineSuggestion.java b/core/java/android/view/inputmethod/InlineSuggestion.java index e4ac5889a3c0..b8893cee834d 100644 --- a/core/java/android/view/inputmethod/InlineSuggestion.java +++ b/core/java/android/view/inputmethod/InlineSuggestion.java @@ -317,8 +317,24 @@ public final class InlineSuggestion implements Parcelable { */ @MainThread private void handleOnSurfacePackage(SurfaceControlViewHost.SurfacePackage surfacePackage) { + if (surfacePackage == null) { + return; + } + if (mSurfacePackage != null || mSurfacePackageConsumer == null) { + // The surface package is not consumed, release it immediately. + surfacePackage.release(); + try { + mInlineContentProvider.onSurfacePackageReleased(); + } catch (RemoteException e) { + Slog.w(TAG, "Error calling onSurfacePackageReleased(): " + e); + } + return; + } mSurfacePackage = surfacePackage; - if (mSurfacePackage != null && mSurfacePackageConsumer != null) { + if (mSurfacePackage == null) { + return; + } + if (mSurfacePackageConsumer != null) { mSurfacePackageConsumer.accept(mSurfacePackage); mSurfacePackageConsumer = null; } @@ -334,6 +350,10 @@ public final class InlineSuggestion implements Parcelable { } mSurfacePackage = null; } + // Clear the pending surface package consumer, if any. This can happen if the IME + // attaches the view to window and then quickly detaches it from the window, before + // the surface package requested upon attaching to window was returned. + mSurfacePackageConsumer = null; } @MainThread diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 71dd6653f6a6..477dd1d13295 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -616,12 +616,19 @@ public final class InputMethodManager { // For some reason we didn't do a startInput + windowFocusGain, so // we'll just do a window focus gain and call it a day. try { - if (DEBUG) Log.v(TAG, "Reporting focus gain, without startInput"); + View servedView = controller.getServedView(); + boolean nextFocusIsServedView = servedView != null && servedView == focusedView; + if (DEBUG) { + Log.v(TAG, "Reporting focus gain, without startInput" + + ", nextFocusIsServedView=" + nextFocusIsServedView); + } mService.startInputOrWindowGainedFocus( StartInputReason.WINDOW_FOCUS_GAIN_REPORT_ONLY, mClient, focusedView.getWindowToken(), startInputFlags, softInputMode, windowFlags, - null, null, 0 /* missingMethodFlags */, + nextFocusIsServedView ? mCurrentTextBoxAttribute : null, + nextFocusIsServedView ? mServedInputConnectionWrapper : null, + 0 /* missingMethodFlags */, mCurRootView.mContext.getApplicationInfo().targetSdkVersion); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); @@ -646,8 +653,7 @@ public final class InputMethodManager { public void setCurrentRootView(ViewRootImpl rootView) { synchronized (mH) { if (mCurRootView != null) { - // Reset the last served view and restart window focus state of the root view. - mCurRootView.getImeFocusController().setServedView(null); + // Restart the input when the next window focus state of the root view changed. mRestartOnNextWindowFocus = true; } mCurRootView = rootView; @@ -677,6 +683,18 @@ public final class InputMethodManager { } return result; } + + /** + * For {@link ImeFocusController} to check if the currently served view is accepting full + * text edits. + */ + @Override + public boolean isAcceptingText() { + synchronized (mH) { + return mServedInputConnectionWrapper != null + && mServedInputConnectionWrapper.getInputConnection() != null; + } + } } /** @hide */ diff --git a/core/java/android/widget/inline/InlineContentView.java b/core/java/android/widget/inline/InlineContentView.java index 8657e828a3f6..6a85de5ca757 100644 --- a/core/java/android/widget/inline/InlineContentView.java +++ b/core/java/android/widget/inline/InlineContentView.java @@ -197,7 +197,9 @@ public class InlineContentView extends ViewGroup { mSurfacePackageUpdater.getSurfacePackage( sp -> { if (DEBUG) Log.v(TAG, "Received new SurfacePackage"); - mSurfaceView.setChildSurfacePackage(sp); + if (getViewRootImpl() != null) { + mSurfaceView.setChildSurfacePackage(sp); + } }); } } diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index b36c71f6c7a8..2d4d9575584d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -1121,7 +1121,7 @@ public class ChooserActivity extends ResolverActivity implements final ComponentName cn = getNearbySharingComponent(); if (cn == null) return null; - final Intent resolveIntent = new Intent(); + final Intent resolveIntent = new Intent(originalIntent); resolveIntent.setComponent(cn); final ResolveInfo ri = getPackageManager().resolveActivity( resolveIntent, PackageManager.GET_META_DATA); @@ -1285,6 +1285,12 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup parent) { ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_image, parent, false); + + final ViewGroup actionRow = + (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); + //TODO: addActionButton(actionRow, createCopyButton()); + addActionButton(actionRow, createNearbyButton(targetIntent)); + mPreviewCoord = new ContentPreviewCoordinator(contentPreviewLayout, true); String action = targetIntent.getAction(); @@ -1395,10 +1401,11 @@ public class ChooserActivity extends ResolverActivity implements ViewGroup contentPreviewLayout = (ViewGroup) layoutInflater.inflate( R.layout.chooser_grid_preview_file, parent, false); - // TODO(b/120417119): Disable file copy until after moving to sysui, - // due to permissions issues - //((ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row)) - // .addView(createCopyButton()); + final ViewGroup actionRow = + (ViewGroup) contentPreviewLayout.findViewById(R.id.chooser_action_row); + //TODO(b/120417119): addActionButton(actionRow, createCopyButton()); + addActionButton(actionRow, createNearbyButton(targetIntent)); + String action = targetIntent.getAction(); if (Intent.ACTION_SEND.equals(action)) { diff --git a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java index 86a9af3db196..fe0e7d012262 100644 --- a/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java +++ b/core/java/com/android/internal/app/chooser/DisplayResolveInfo.java @@ -40,8 +40,10 @@ import java.util.List; * resolve it to an activity. */ public class DisplayResolveInfo implements TargetInfo { - // Temporary flag for new chooser delegate behavior. - private static final boolean ENABLE_CHOOSER_DELEGATE = true; + // Temporary flag for new chooser delegate behavior. There are occassional token + // permission errors from bouncing through the delegate. Watch out before reenabling: + // b/157272342 is one example but this issue has been reported many times + private static final boolean ENABLE_CHOOSER_DELEGATE = false; private final ResolveInfo mResolveInfo; private CharSequence mDisplayLabel; diff --git a/core/java/com/android/internal/inputmethod/StartInputReason.java b/core/java/com/android/internal/inputmethod/StartInputReason.java index a01c45919b8f..a4eaa21538f7 100644 --- a/core/java/com/android/internal/inputmethod/StartInputReason.java +++ b/core/java/com/android/internal/inputmethod/StartInputReason.java @@ -50,8 +50,9 @@ public @interface StartInputReason { int WINDOW_FOCUS_GAIN = 1; /** * {@link android.view.Window} gained focus but there is no {@link android.view.View} that is - * eligible to have IME focus. {@link android.view.inputmethod.InputMethodManager} just reports - * this window focus change event. + * eligible to have IME focus, or the focused view is same as current served view and its + * input connection remains. {@link android.view.inputmethod.InputMethodManager} just reports + * this window focus change event to sync IME input target for system. */ int WINDOW_FOCUS_GAIN_REPORT_ONLY = 2; /** diff --git a/core/java/com/android/internal/util/SyncResultReceiver.java b/core/java/com/android/internal/util/SyncResultReceiver.java index 00e91017a9eb..6b1358293d02 100644 --- a/core/java/com/android/internal/util/SyncResultReceiver.java +++ b/core/java/com/android/internal/util/SyncResultReceiver.java @@ -182,7 +182,7 @@ public final class SyncResultReceiver extends IResultReceiver.Stub { } /** @hide */ - public static final class TimeoutException extends RuntimeException { + public static final class TimeoutException extends Exception { private TimeoutException(String msg) { super(msg); } diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java index 1f2ae5f96449..7c7d9312e2db 100644 --- a/core/java/com/android/internal/widget/ConversationLayout.java +++ b/core/java/com/android/internal/widget/ConversationLayout.java @@ -21,6 +21,10 @@ import static com.android.internal.widget.MessagingGroup.IMAGE_DISPLAY_LOCATION_ import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_IN; import static com.android.internal.widget.MessagingPropertyAnimator.ALPHA_OUT; +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; import android.annotation.AttrRes; import android.annotation.NonNull; import android.annotation.Nullable; @@ -36,6 +40,7 @@ import android.graphics.Color; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Typeface; +import android.graphics.drawable.GradientDrawable; import android.graphics.drawable.Icon; import android.os.Bundle; import android.os.Parcelable; @@ -80,7 +85,7 @@ public class ConversationLayout extends FrameLayout private static final float COLOR_SHIFT_AMOUNT = 60; /** - * Pattren for filter some ingonable characters. + * Pattern for filter some ignorable characters. * p{Z} for any kind of whitespace or invisible separator. * p{C} for any kind of punctuation character. */ @@ -93,8 +98,12 @@ public class ConversationLayout extends FrameLayout public static final Interpolator LINEAR_OUT_SLOW_IN = new PathInterpolator(0f, 0f, 0.2f, 1f); public static final Interpolator FAST_OUT_LINEAR_IN = new PathInterpolator(0.4f, 0f, 1f, 1f); public static final Interpolator FAST_OUT_SLOW_IN = new PathInterpolator(0.4f, 0f, 0.2f, 1f); + public static final Interpolator OVERSHOOT = new PathInterpolator(0.4f, 0f, 0.2f, 1.4f); public static final OnLayoutChangeListener MESSAGING_PROPERTY_ANIMATOR = new MessagingPropertyAnimator(); + public static final int IMPORTANCE_ANIM_GROW_DURATION = 250; + public static final int IMPORTANCE_ANIM_SHRINK_DURATION = 200; + public static final int IMPORTANCE_ANIM_SHRINK_DELAY = 25; private List<MessagingMessage> mMessages = new ArrayList<>(); private List<MessagingMessage> mHistoricMessages = new ArrayList<>(); private MessagingLinearLayout mMessagingLinearLayout; @@ -331,14 +340,74 @@ public class ConversationLayout extends FrameLayout mNameReplacement = nameReplacement; } - /** - * Sets this conversation as "important", adding some additional UI treatment. - */ + /** Sets this conversation as "important", adding some additional UI treatment. */ @RemotableViewMethod public void setIsImportantConversation(boolean isImportantConversation) { + setIsImportantConversation(isImportantConversation, false); + } + + /** @hide **/ + public void setIsImportantConversation(boolean isImportantConversation, boolean animate) { mImportantConversation = isImportantConversation; - mImportanceRingView.setVisibility(isImportantConversation - && mIcon.getVisibility() != GONE ? VISIBLE : GONE); + mImportanceRingView.setVisibility(isImportantConversation && mIcon.getVisibility() != GONE + ? VISIBLE : GONE); + + if (animate && isImportantConversation) { + GradientDrawable ring = (GradientDrawable) mImportanceRingView.getDrawable(); + ring.mutate(); + GradientDrawable bg = (GradientDrawable) mConversationIconBadgeBg.getDrawable(); + bg.mutate(); + int ringColor = getResources() + .getColor(R.color.conversation_important_highlight); + int standardThickness = getResources() + .getDimensionPixelSize(R.dimen.importance_ring_stroke_width); + int largeThickness = getResources() + .getDimensionPixelSize(R.dimen.importance_ring_anim_max_stroke_width); + int standardSize = getResources().getDimensionPixelSize( + R.dimen.importance_ring_size); + int baseSize = standardSize - standardThickness * 2; + int bgSize = getResources() + .getDimensionPixelSize(R.dimen.conversation_icon_size_badged); + + ValueAnimator.AnimatorUpdateListener animatorUpdateListener = animation -> { + int strokeWidth = Math.round((float) animation.getAnimatedValue()); + ring.setStroke(strokeWidth, ringColor); + int newSize = baseSize + strokeWidth * 2; + ring.setSize(newSize, newSize); + mImportanceRingView.invalidate(); + }; + + ValueAnimator growAnimation = ValueAnimator.ofFloat(0, largeThickness); + growAnimation.setInterpolator(LINEAR_OUT_SLOW_IN); + growAnimation.setDuration(IMPORTANCE_ANIM_GROW_DURATION); + growAnimation.addUpdateListener(animatorUpdateListener); + + ValueAnimator shrinkAnimation = + ValueAnimator.ofFloat(largeThickness, standardThickness); + shrinkAnimation.setDuration(IMPORTANCE_ANIM_SHRINK_DURATION); + shrinkAnimation.setStartDelay(IMPORTANCE_ANIM_SHRINK_DELAY); + shrinkAnimation.setInterpolator(OVERSHOOT); + shrinkAnimation.addUpdateListener(animatorUpdateListener); + shrinkAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + // Shrink the badge bg so that it doesn't peek behind the animation + bg.setSize(baseSize, baseSize); + mConversationIconBadgeBg.invalidate(); + } + + @Override + public void onAnimationEnd(Animator animation) { + // Reset bg back to normal size + bg.setSize(bgSize, bgSize); + mConversationIconBadgeBg.invalidate(); + } + }); + + AnimatorSet anims = new AnimatorSet(); + anims.playSequentially(growAnimation, shrinkAnimation); + anims.start(); + } } public boolean isImportantConversation() { @@ -1176,7 +1245,6 @@ public class ConversationLayout extends FrameLayout } private void updateContentEndPaddings() { - // Let's make sure the conversation header can't run into the expand button when we're // collapsed and update the paddings of the content int headerPaddingEnd; diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto index ecb4193a2c6c..8e4006aa6861 100644 --- a/core/proto/android/service/notification.proto +++ b/core/proto/android/service/notification.proto @@ -274,4 +274,74 @@ message PackageRemoteViewInfoProto { // Next Tag: 2 message NotificationRemoteViewsProto { repeated PackageRemoteViewInfoProto package_remote_view_info = 1; -}
\ No newline at end of file +} + +/** + * Atom that represents an item in the list of Do Not Disturb rules, pulled from + * NotificationManagerService.java. + */ +message DNDModeProto { + enum Mode { + ROOT_CONFIG = -1; // Used to distinguish the config (one per user) from the rules. + ZEN_MODE_OFF = 0; + ZEN_MODE_IMPORTANT_INTERRUPTIONS = 1; + ZEN_MODE_NO_INTERRUPTIONS = 2; + ZEN_MODE_ALARMS = 3; + } + optional int32 user = 1; // Android user ID (0, 1, 10, ...) + optional bool enabled = 2; // true for ROOT_CONFIG if a manualRule is enabled + optional bool channels_bypassing = 3; // only valid for ROOT_CONFIG + optional Mode zen_mode = 4; + // id is one of the system default rule IDs, or empty + // May also be "MANUAL_RULE" to indicate app-activation of the manual rule. + optional string id = 5; + optional int32 uid = 6; // currently only SYSTEM_UID or 0 for other + optional DNDPolicyProto policy = 7; +} + +/** + * Atom that represents a Do Not Disturb policy, an optional detail proto for DNDModeProto. + */ +message DNDPolicyProto { + enum State { + STATE_UNSET = 0; + STATE_ALLOW = 1; + STATE_DISALLOW = 2; + } + optional State calls = 1; + optional State repeat_callers = 2; + optional State messages = 3; + optional State conversations = 4; + optional State reminders = 5; + optional State events = 6; + optional State alarms = 7; + optional State media = 8; + optional State system = 9; + optional State fullscreen = 10; + optional State lights = 11; + optional State peek = 12; + optional State status_bar = 13; + optional State badge = 14; + optional State ambient = 15; + optional State notification_list = 16; + + enum PeopleType { + PEOPLE_UNSET = 0; + PEOPLE_ANYONE = 1; + PEOPLE_CONTACTS = 2; + PEOPLE_STARRED = 3; + PEOPLE_NONE = 4; + } + + optional PeopleType allow_calls_from = 17; + optional PeopleType allow_messages_from = 18; + + enum ConversationType { + CONV_UNSET = 0; + CONV_ANYONE = 1; + CONV_IMPORTANT = 2; + CONV_NONE = 3; + } + + optional ConversationType allow_conversations_from = 19; +} diff --git a/core/res/res/drawable/conversation_badge_background.xml b/core/res/res/drawable/conversation_badge_background.xml index 0dd0dcda40fb..9e6405dc1040 100644 --- a/core/res/res/drawable/conversation_badge_background.xml +++ b/core/res/res/drawable/conversation_badge_background.xml @@ -22,7 +22,7 @@ android:color="#ffffff"/> <size - android:width="26dp" - android:height="26dp"/> + android:width="20dp" + android:height="20dp"/> </shape> diff --git a/core/res/res/drawable/conversation_badge_ring.xml b/core/res/res/drawable/conversation_badge_ring.xml index 11ba8ad69505..eee53d1c21b5 100644 --- a/core/res/res/drawable/conversation_badge_ring.xml +++ b/core/res/res/drawable/conversation_badge_ring.xml @@ -16,17 +16,18 @@ --> <shape xmlns:android="http://schemas.android.com/apk/res/android" - android:shape="oval"> - - <solid - android:color="@color/transparent"/> + android:shape="oval" +> + <solid android:color="@color/transparent" /> <stroke android:color="@color/conversation_important_highlight" - android:width="2dp"/> + android:width="@dimen/importance_ring_stroke_width" + /> <size - android:width="26dp" - android:height="26dp"/> + android:width="@dimen/importance_ring_size" + android:height="@dimen/importance_ring_size" + /> </shape> diff --git a/core/res/res/layout/chooser_grid_preview_text.xml b/core/res/res/layout/chooser_grid_preview_text.xml index 002917463ab3..1d18648b9ef7 100644 --- a/core/res/res/layout/chooser_grid_preview_text.xml +++ b/core/res/res/layout/chooser_grid_preview_text.xml @@ -44,6 +44,8 @@ android:ellipsize="end" android:fontFamily="@android:string/config_headlineFontFamily" android:textColor="?android:attr/textColorPrimary" + android:textAlignment="gravity" + android:textDirection="locale" android:maxLines="2" android:focusable="true"/> @@ -90,6 +92,8 @@ android:layout_gravity="center_vertical" android:ellipsize="end" android:maxLines="2" + android:textAlignment="gravity" + android:textDirection="locale" android:textAppearance="@style/TextAppearance.DeviceDefault.WindowTitle" android:fontFamily="@android:string/config_headlineFontFamily"/> </LinearLayout> diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml index 9a9d8b96c677..d3857941969b 100644 --- a/core/res/res/layout/notification_template_material_conversation.xml +++ b/core/res/res/layout/notification_template_material_conversation.xml @@ -38,6 +38,8 @@ <FrameLayout android:layout_width="wrap_content" android:layout_height="wrap_content" + android:clipChildren="false" + android:clipToPadding="false" android:layout_gravity="top|center_horizontal" > @@ -63,13 +65,17 @@ android:layout_height="@dimen/conversation_icon_size_badged" android:layout_marginLeft="@dimen/conversation_badge_side_margin" android:layout_marginTop="@dimen/conversation_badge_side_margin" + android:clipChildren="false" + android:clipToPadding="false" > <com.android.internal.widget.CachingIconView android:id="@+id/conversation_icon_badge_bg" android:layout_width="match_parent" android:layout_height="match_parent" + android:layout_gravity="center" android:src="@drawable/conversation_badge_background" android:forceHasOverlappingRendering="false" + android:scaleType="center" /> <com.android.internal.widget.CachingIconView android:id="@+id/icon" @@ -81,11 +87,14 @@ /> <com.android.internal.widget.CachingIconView android:id="@+id/conversation_icon_badge_ring" - android:layout_width="match_parent" - android:layout_height="match_parent" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:layout_gravity="center" android:src="@drawable/conversation_badge_ring" android:visibility="gone" android:forceHasOverlappingRendering="false" + android:clipToPadding="false" + android:scaleType="center" /> </FrameLayout> </FrameLayout> @@ -132,7 +141,7 @@ android:id="@+id/conversation_text" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:textAppearance="@style/TextAppearance.DeviceDefault.Notification.Title" android:textSize="16sp" android:singleLine="true" @@ -145,8 +154,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?attr/notificationHeaderTextAppearance" - android:layout_marginStart="@dimen/notification_header_separating_margin" - android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:text="@string/notification_header_divider_symbol" android:layout_gravity="center" android:paddingTop="1sp" @@ -161,7 +170,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:paddingTop="1sp" android:singleLine="true" /> @@ -171,8 +181,8 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:textAppearance="?attr/notificationHeaderTextAppearance" - android:layout_marginStart="@dimen/notification_header_separating_margin" - android:layout_marginEnd="@dimen/notification_header_separating_margin" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" + android:layout_marginEnd="@dimen/notification_conversation_header_separating_margin" android:text="@string/notification_header_divider_symbol" android:layout_gravity="center" android:paddingTop="1sp" @@ -186,7 +196,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" - android:layout_marginStart="@dimen/notification_header_separating_margin" + android:layout_marginStart="@dimen/notification_conversation_header_separating_margin" android:paddingTop="1sp" android:showRelative="true" android:singleLine="true" diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 1a8c129af06f..8272fed8cc97 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -1786,7 +1786,7 @@ <string name="managed_profile_label_badge" msgid="6762559569999499495">"<xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string> <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string> <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3.º <xliff:g id="LABEL">%1$s</xliff:g> do traballo"</string> - <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para soltar fixación"</string> + <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Solicitar PIN para deixar de fixar"</string> <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar un padrón de desbloqueo antes de deixar de fixar a pantalla"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar un contrasinal para deixar de fixar a pantalla"</string> <string name="package_installed_device_owner" msgid="7035926868974878525">"Instalado polo teu administrador"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 2877e8009407..11683ae46138 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1786,7 +1786,7 @@ <string name="managed_profile_label_badge" msgid="6762559569999499495">"Ажлын <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="managed_profile_label_badge_2" msgid="5673187309555352550">"2 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string> <string name="managed_profile_label_badge_3" msgid="6882151970556391957">"3 дахь ажил <xliff:g id="LABEL">%1$s</xliff:g>"</string> - <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Тогтоосныг суллахаас өмнө PIN асуух"</string> + <string name="lock_to_app_unlock_pin" msgid="3890940811866290782">"Бэхэлснийг болиулахаасаа өмнө PIN асуух"</string> <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тогтоосныг суллахаас өмнө түгжээ тайлах хээ асуух"</string> <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string> <string name="package_installed_device_owner" msgid="7035926868974878525">"Таны админ суулгасан"</string> @@ -1841,7 +1841,7 @@ <string name="zen_mode_default_weeknights_name" msgid="7902108149994062847">"Ажлын өдрийн шөнө"</string> <string name="zen_mode_default_weekends_name" msgid="4707200272709377930">"Амралтын өдөр"</string> <string name="zen_mode_default_events_name" msgid="2280682960128512257">"Үйл явдал"</string> - <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Идэвхгүй"</string> + <string name="zen_mode_default_every_night_name" msgid="1467765312174275823">"Унтлагын цаг"</string> <string name="muted_by" msgid="91464083490094950">"<xliff:g id="THIRD_PARTY">%1$s</xliff:g> зарим дууны дууг хааж байна"</string> <string name="system_error_wipe_data" msgid="5910572292172208493">"Таны төхөөрөмжид дотоод алдаа байна.Та төхөөрөмжөө үйлдвэрээс гарсан төлөвт шилжүүлэх хүртэл таны төхөөрөмж чинь тогтворгүй байж болох юм."</string> <string name="system_error_manufacturer" msgid="703545241070116315">"Таны төхөөрөмжид дотоод алдаа байна. Дэлгэрэнгүй мэдээлэл авахыг хүсвэл үйлдвэрлэгчтэйгээ холбоо барина уу."</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index 1f72b8b83315..d910fc03e165 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1551,7 +1551,7 @@ <string name="activity_resolver_use_once" msgid="948462794469672658">"တစ်ခါတည်း"</string> <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s က အလုပ်ပရိုဖိုင်ကို မပံ့ပိုးပါ။"</string> <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"တက်ဘလက်"</string> - <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"တီဗွီ"</string> + <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"TV"</string> <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"ဖုန်း"</string> <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"အထိုင်ရှိသော စပီကာများ"</string> <string name="default_audio_route_name_hdmi" msgid="5474470558160717850">"HDMI"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 1739453fe0b8..b1c4fbbf0b09 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -951,11 +951,11 @@ <string name="autofill_area" msgid="8289022370678448983">"Gebied"</string> <string name="autofill_emirate" msgid="2544082046790551168">"Emiraat"</string> <string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"je webbladwijzers en -geschiedenis lezen"</string> - <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bladwijzers in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string> + <string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"Hiermee kan de app de geschiedenis lezen van alle URL\'s die in de systeemeigen browser zijn bezocht, en alle bookmarks in de systeemeigen browser. Let op: deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string> <string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"webbladwijzers en -geschiedenis schrijven"</string> - <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string> - <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bladwijzers bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string> - <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bladwijzers die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string> + <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je tablet. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden.."</string> + <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"Hiermee kan de app de browsergeschiedenis of opgeslagen bookmarks bewerken op je Android TV-apparaat. Hierdoor kan de app mogelijk browsergegevens wissen of aanpassen. Opmerking: Dit recht kan niet worden afgedwongen door andere browsers of andere apps met internetmogelijkheden."</string> + <string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"Hiermee kan de app de webgeschiedenis wijzigen in de systeemeigen browser en de bookmarks die zijn opgeslagen op je telefoon. Deze toestemming kan niet worden geforceerd door andere browsers of andere apps met internetmogelijkheden."</string> <string name="permlab_setAlarm" msgid="1158001610254173567">"een wekker instellen"</string> <string name="permdesc_setAlarm" msgid="2185033720060109640">"Hiermee kan de app een wekker instellen in een geïnstalleerde wekker-app. Deze functie wordt door sommige wekker-apps niet geïmplementeerd."</string> <string name="permlab_addVoicemail" msgid="4770245808840814471">"voicemail toevoegen"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index 4224523a5333..5986e7652fa3 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -787,7 +787,7 @@ <string name="imProtocolYahoo" msgid="5373338758093392231">"Yahoo"</string> <string name="imProtocolSkype" msgid="1486297589164830043">"Skype"</string> <string name="imProtocolQq" msgid="7254708777029006592">"QQ"</string> - <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"ହ୍ୟାଙ୍ଗଆଉଟ୍ସ"</string> + <string name="imProtocolGoogleTalk" msgid="9194016024343166782">"Hangouts"</string> <string name="imProtocolIcq" msgid="2410325380427389521">"ICQ"</string> <string name="imProtocolJabber" msgid="7919269388889582015">"Jabber"</string> <string name="imProtocolNetMeeting" msgid="4985002408136148256">"NetMeeting"</string> diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml index 59bb052cbdf5..4ee919289f28 100644 --- a/core/res/res/values/dimens.xml +++ b/core/res/res/values/dimens.xml @@ -273,6 +273,9 @@ <!-- The margin before and after each of the items in the notification header. --> <dimen name="notification_header_separating_margin">2dp</dimen> + <!-- The margin before and after each of the items in the conversation header. --> + <dimen name="notification_conversation_header_separating_margin">4dp</dimen> + <!-- The absolute size of the notification expand icon. -2 for wrap_content. --> <dimen name="notification_header_expand_icon_size">-2px</dimen> @@ -719,10 +722,16 @@ <!-- The width of the protection of the face pile layout when expanded--> <dimen name="conversation_face_pile_protection_width_expanded">1dp</dimen> <!-- The padding of the expanded message container--> - <dimen name="expanded_group_conversation_message_padding">14dp</dimen> + <dimen name="expanded_group_conversation_message_padding">17dp</dimen> + <!-- The stroke width of the ring used to visually mark a conversation as important --> + <dimen name="importance_ring_stroke_width">2dp</dimen> + <!-- The maximum stroke width used for the animation shown when a conversation is marked as important --> + <dimen name="importance_ring_anim_max_stroke_width">10dp</dimen> + <!-- The size of the importance ring --> + <dimen name="importance_ring_size">20dp</dimen> <!-- The top padding of the conversation icon container in the regular state--> - <dimen name="conversation_icon_container_top_padding">9dp</dimen> + <dimen name="conversation_icon_container_top_padding">12dp</dimen> <!-- The top padding of the conversation icon container when the avatar is small--> <dimen name="conversation_icon_container_top_padding_small_avatar">17.5dp</dimen> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index ab4005b4893c..23ae1e7d271e 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -3903,6 +3903,12 @@ <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionPkgs" /> <java-symbol type="array" name="config_defaultImperceptibleKillingExemptionProcStates" /> + <java-symbol type="color" name="conversation_important_highlight" /> + <java-symbol type="dimen" name="importance_ring_stroke_width" /> + <java-symbol type="dimen" name="importance_ring_anim_max_stroke_width" /> + <java-symbol type="dimen" name="importance_ring_size" /> + <java-symbol type="dimen" name="conversation_icon_size_badged" /> + <java-symbol type="id" name="header_icon_container" /> <java-symbol type="attr" name="notificationHeaderTextAppearance" /> <java-symbol type="string" name="conversation_single_line_name_display" /> diff --git a/core/res/res/xml/sms_short_codes.xml b/core/res/res/xml/sms_short_codes.xml index 70917e76f8b4..d5733e34a8ef 100644 --- a/core/res/res/xml/sms_short_codes.xml +++ b/core/res/res/xml/sms_short_codes.xml @@ -39,7 +39,7 @@ <!-- Albania: 5 digits, known short codes listed --> <shortcode country="al" pattern="\\d{5}" premium="15191|55[56]00" /> - <!-- Argentia: 5 digits, known short codes listed --> + <!-- Argentina: 5 digits, known short codes listed --> <shortcode country="ar" pattern="\\d{5}" free="11711|28291" /> <!-- Armenia: 3-4 digits, emergency numbers 10[123] --> @@ -70,7 +70,7 @@ <shortcode country="by" pattern="\\d{4}" premium="3336|4161|444[4689]|501[34]|7781" /> <!-- Canada: 5-6 digits --> - <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" /> + <shortcode country="ca" pattern="\\d{5,6}" premium="60999|88188|43030" standard="244444" free="455677" /> <!-- Switzerland: 3-5 digits: http://www.swisscom.ch/fxres/kmu/thirdpartybusiness_code_of_conduct_en.pdf --> <shortcode country="ch" pattern="[2-9]\\d{2,4}" premium="543|83111|30118" free="98765|30075|30047" /> diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index daaf31a6bb65..cd93eeb857f1 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -27,6 +27,8 @@ import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; import static android.view.View.SYSTEM_UI_FLAG_LAYOUT_STABLE; import static android.view.WindowInsets.Type.ime; +import static android.view.WindowInsets.Type.navigationBars; +import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN; import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE; @@ -341,6 +343,26 @@ public class InsetsStateTest { } } + @Test + public void testCalculateUncontrollableInsets() throws Exception { + try (InsetsModeSession session = new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 200, 100)); + mState.getSource(ITYPE_STATUS_BAR).setVisible(true); + mState.getSource(ITYPE_IME).setFrame(new Rect(0, 200, 200, 300)); + mState.getSource(ITYPE_IME).setVisible(true); + mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(100, 0, 200, 300)); + mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true); + + mState.setDisplayFrame(new Rect(0, 0, 200, 300)); + assertEquals(0, + mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 0, 200, 300))); + assertEquals(statusBars() | ime(), + mState.calculateUncontrollableInsetsFromFrame(new Rect(0, 50, 200, 250))); + assertEquals(navigationBars(), + mState.calculateUncontrollableInsetsFromFrame(new Rect(50, 0, 150, 300))); + } + } + private void assertEqualsAndHashCode() { assertEquals(mState, mState2); assertEquals(mState.hashCode(), mState2.hashCode()); diff --git a/data/etc/car/Android.bp b/data/etc/car/Android.bp index 1b1a624cda50..d6542de91e08 100644 --- a/data/etc/car/Android.bp +++ b/data/etc/car/Android.bp @@ -122,6 +122,13 @@ prebuilt_etc { } prebuilt_etc { + name: "privapp_whitelist_com.android.car.bugreport", + sub_dir: "permissions", + src: "com.android.car.bugreport.xml", + filename_from_src: true, +} + +prebuilt_etc { name: "privapp_whitelist_com.google.android.car.kitchensink", sub_dir: "permissions", src: "com.google.android.car.kitchensink.xml", diff --git a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml b/data/etc/car/com.android.car.bugreport.xml index 696e9b121564..432a838a90e8 100644 --- a/packages/SystemUI/res/color/qs_user_detail_avatar_tint.xml +++ b/data/etc/car/com.android.car.bugreport.xml @@ -1,7 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> - <!-- - ~ Copyright (C) 2016 The Android Open Source Project + ~ Copyright (C) 2020 The Android Open Source Project ~ ~ Licensed under the Apache License, Version 2.0 (the "License"); ~ you may not use this file except in compliance with the License. @@ -15,8 +14,11 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License --> - -<selector xmlns:android="http://schemas.android.com/apk/res/android"> - <item android:state_enabled="false" android:color="?android:attr/textColorPrimary" /> - <item android:color="@android:color/transparent" /> -</selector> +<permissions> + <privapp-permissions package="com.android.car.bugreport"> + <permission name="android.permission.DUMP"/> + <permission name="android.permission.INTERACT_ACROSS_USERS"/> + <permission name="android.permission.READ_LOGS"/> + <permission name="android.permission.MANAGE_USERS"/> + </privapp-permissions> + </permissions> diff --git a/data/etc/preinstalled-packages-platform.xml b/data/etc/preinstalled-packages-platform.xml index 17e1f2e0c229..625558406b9c 100644 --- a/data/etc/preinstalled-packages-platform.xml +++ b/data/etc/preinstalled-packages-platform.xml @@ -17,7 +17,9 @@ <!-- This XML file declares which system packages should be initially installed for new users based on their user type. All system packages on the device should ideally have an entry in an xml file -(keyed by its manifest name). +(keyed by its manifest name), except auto-generated rro packages. Auto-generated RRO packages +(package name ends with ".auto_generated_rro_product__" or ".auto_generated_rro_vendor__") +will be installed for new users according to corresponding overlay target packages. Base user-types (every user will be at least one of these types) are: SYSTEM (user 0) @@ -51,7 +53,7 @@ The following three examples should cover most normal cases: 2. For a system package to be pre-installed on all human users (e.g. a web browser), i.e. to be -installed on any user of type type FULL or PROFILE (since this covers all human users): +installed on any user of type FULL or PROFILE (since this covers all human users): <install-in-user-type package="com.android.example"> <install-in user-type="FULL" /> diff --git a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java index 9846436b3ac8..67a040dba3e7 100644 --- a/location/java/com/android/internal/location/GpsNetInitiatedHandler.java +++ b/location/java/com/android/internal/location/GpsNetInitiatedHandler.java @@ -18,7 +18,6 @@ package com.android.internal.location; import android.app.Notification; import android.app.NotificationManager; -import android.app.PendingIntent; import android.compat.annotation.UnsupportedAppUsage; import android.content.BroadcastReceiver; import android.content.Context; @@ -402,13 +401,9 @@ public class GpsNetInitiatedHandler { mNiNotificationBuilder.setDefaults(0); } - // if not to popup dialog immediately, pending intent will open the dialog - Intent intent = !mPopupImmediately ? getDlgIntent(notif) : new Intent(); - PendingIntent pi = PendingIntent.getBroadcast(mContext, 0, intent, 0); mNiNotificationBuilder.setTicker(getNotifTicker(notif, mContext)) .setContentTitle(title) - .setContentText(message) - .setContentIntent(pi); + .setContentText(message); notificationManager.notifyAsUser(null, notif.notificationId, mNiNotificationBuilder.build(), UserHandle.ALL); diff --git a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java index 323bba3fdd71..6c401161062f 100644 --- a/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java +++ b/location/java/com/android/internal/location/gnssmetrics/GnssMetrics.java @@ -32,7 +32,7 @@ import android.util.TimeUtils; import com.android.internal.app.IBatteryStats; import com.android.internal.location.nano.GnssLogsProto.GnssLog; import com.android.internal.location.nano.GnssLogsProto.PowerMetrics; -import com.android.internal.os.BackgroundThread; +import com.android.internal.util.ConcurrentUtils; import com.android.internal.util.FrameworkStatsLog; import java.util.ArrayList; @@ -124,8 +124,6 @@ public class GnssMetrics { private long mL5SvStatusReportsUsedInFix; /** Stats manager service for reporting atoms */ private StatsManager mStatsManager; - /** Pull atom callback, this is called when atom pull request occurs */ - private StatsPullAtomCallbackImpl mPullAtomCallback; /* Statds Logging Variables Section End */ public GnssMetrics(Context context, IBatteryStats stats) { @@ -467,8 +465,8 @@ public class GnssMetrics { mConstellationTypes = new boolean[GnssStatus.CONSTELLATION_COUNT]; } - /** Class for storing statistics */ - private class Statistics { + /** Thread-safe class for storing statistics */ + private static class Statistics { private int mCount; private double mSum; @@ -476,7 +474,7 @@ public class GnssMetrics { private long mLongSum; /** Resets statistics */ - public void reset() { + public synchronized void reset() { mCount = 0; mSum = 0.0; mSumSquare = 0.0; @@ -484,7 +482,7 @@ public class GnssMetrics { } /** Adds an item */ - public void addItem(double item) { + public synchronized void addItem(double item) { mCount++; mSum += item; mSumSquare += item * item; @@ -492,17 +490,17 @@ public class GnssMetrics { } /** Returns number of items added */ - public int getCount() { + public synchronized int getCount() { return mCount; } /** Returns mean */ - public double getMean() { + public synchronized double getMean() { return mSum / mCount; } /** Returns standard deviation */ - public double getStandardDeviation() { + public synchronized double getStandardDeviation() { double m = mSum / mCount; m = m * m; double v = mSumSquare / mCount; @@ -513,7 +511,7 @@ public class GnssMetrics { } /** Returns long sum */ - public long getLongSum() { + public synchronized long getLongSum() { return mLongSum; } } @@ -623,11 +621,11 @@ public class GnssMetrics { } private void registerGnssStats() { - mPullAtomCallback = new StatsPullAtomCallbackImpl(); + StatsPullAtomCallbackImpl pullAtomCallback = new StatsPullAtomCallbackImpl(); mStatsManager.setPullAtomCallback( FrameworkStatsLog.GNSS_STATS, null, // use default PullAtomMetadata values - BackgroundThread.getExecutor(), mPullAtomCallback); + ConcurrentUtils.DIRECT_EXECUTOR, pullAtomCallback); } /** diff --git a/media/java/android/media/IMediaRouter2Manager.aidl b/media/java/android/media/IMediaRouter2Manager.aidl index 5925d380115c..5113dc2058e0 100644 --- a/media/java/android/media/IMediaRouter2Manager.aidl +++ b/media/java/android/media/IMediaRouter2Manager.aidl @@ -24,8 +24,9 @@ import android.media.RoutingSessionInfo; * {@hide} */ oneway interface IMediaRouter2Manager { - void notifySessionCreated(int requestId, in RoutingSessionInfo sessionInfo); - void notifySessionUpdated(in RoutingSessionInfo sessionInfo); + void notifySessionCreated(int requestId, in RoutingSessionInfo session); + void notifySessionUpdated(in RoutingSessionInfo session); + void notifySessionReleased(in RoutingSessionInfo session); void notifyPreferredFeaturesChanged(String packageName, in List<String> preferredFeatures); void notifyRoutesAdded(in List<MediaRoute2Info> routes); void notifyRoutesRemoved(in List<MediaRoute2Info> routes); diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java index 20e26cd66e34..e767c68f13ac 100644 --- a/media/java/android/media/MediaRouter2.java +++ b/media/java/android/media/MediaRouter2.java @@ -399,11 +399,16 @@ public final class MediaRouter2 { Objects.requireNonNull(controller, "controller must not be null"); Objects.requireNonNull(route, "route must not be null"); - // TODO(b/157873496): Check thread-safety, at least check "sRouterLock" for every variable - if (!mRoutes.containsKey(route.getId())) { + boolean routeFound; + synchronized (sRouterLock) { + // TODO: Check thread-safety + routeFound = mRoutes.containsKey(route.getId()); + } + if (!routeFound) { notifyTransferFailure(route); return; } + if (controller.getRoutingSessionInfo().getTransferableRoutes().contains(route.getId())) { controller.transferToRoute(route); return; @@ -572,10 +577,6 @@ public final class MediaRouter2 { } void addRoutesOnHandler(List<MediaRoute2Info> routes) { - // TODO(b/157874065): When onRoutesAdded is first called, - // 1) clear mRoutes before adding the routes - // 2) Call onRouteSelected(system_route, reason_fallback) if previously selected route - // does not exist anymore. => We may need 'boolean MediaRoute2Info#isSystemRoute()'. List<MediaRoute2Info> addedRoutes = new ArrayList<>(); synchronized (sRouterLock) { for (MediaRoute2Info route : routes) { diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java index 673fffe710a2..1c2d581b733d 100644 --- a/media/java/android/media/MediaRouter2Manager.java +++ b/media/java/android/media/MediaRouter2Manager.java @@ -509,7 +509,7 @@ public final class MediaRouter2Manager { notifyRequestFailed(reason); } - void handleSessionsUpdated(RoutingSessionInfo sessionInfo) { + void handleSessionsUpdatedOnHandler(RoutingSessionInfo sessionInfo) { for (TransferRequest request : mTransferRequests) { String sessionId = request.mOldSessionInfo.getId(); if (!TextUtils.equals(sessionId, sessionInfo.getId())) { @@ -551,6 +551,12 @@ public final class MediaRouter2Manager { } } + void notifySessionReleased(RoutingSessionInfo session) { + for (CallbackRecord record : mCallbackRecords) { + record.mExecutor.execute(() -> record.mCallback.onSessionReleased(session)); + } + } + void notifyRequestFailed(int reason) { for (CallbackRecord record : mCallbackRecords) { record.mExecutor.execute(() -> record.mCallback.onRequestFailed(reason)); @@ -864,9 +870,16 @@ public final class MediaRouter2Manager { /** * Called when a session is changed. - * @param sessionInfo the updated session + * @param session the updated session + */ + public void onSessionUpdated(@NonNull RoutingSessionInfo session) {} + + /** + * Called when a session is released. + * @param session the released session. + * @see #releaseSession(RoutingSessionInfo) */ - public void onSessionUpdated(@NonNull RoutingSessionInfo sessionInfo) {} + public void onSessionReleased(@NonNull RoutingSessionInfo session) {} /** * Called when media is transferred. @@ -946,15 +959,21 @@ public final class MediaRouter2Manager { class Client extends IMediaRouter2Manager.Stub { @Override - public void notifySessionCreated(int requestId, RoutingSessionInfo sessionInfo) { + public void notifySessionCreated(int requestId, RoutingSessionInfo session) { mHandler.sendMessage(obtainMessage(MediaRouter2Manager::createSessionOnHandler, - MediaRouter2Manager.this, requestId, sessionInfo)); + MediaRouter2Manager.this, requestId, session)); + } + + @Override + public void notifySessionUpdated(RoutingSessionInfo session) { + mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdatedOnHandler, + MediaRouter2Manager.this, session)); } @Override - public void notifySessionUpdated(RoutingSessionInfo sessionInfo) { - mHandler.sendMessage(obtainMessage(MediaRouter2Manager::handleSessionsUpdated, - MediaRouter2Manager.this, sessionInfo)); + public void notifySessionReleased(RoutingSessionInfo session) { + mHandler.sendMessage(obtainMessage(MediaRouter2Manager::notifySessionReleased, + MediaRouter2Manager.this, session)); } @Override diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index a03b24cbbcf6..f970b598d6f8 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -233,10 +233,12 @@ void JMediaCodec::release() { } void JMediaCodec::releaseAsync() { - if (mCodec != NULL) { - mCodec->releaseAsync(); - } - mInitStatus = NO_INIT; + std::call_once(mAsyncReleaseFlag, [this] { + if (mCodec != NULL) { + mCodec->releaseAsync(new AMessage(kWhatAsyncReleaseComplete, this)); + } + mInitStatus = NO_INIT; + }); } JMediaCodec::~JMediaCodec() { @@ -1084,6 +1086,12 @@ void JMediaCodec::onMessageReceived(const sp<AMessage> &msg) { handleFrameRenderedNotification(msg); break; } + case kWhatAsyncReleaseComplete: + { + mCodec.clear(); + mLooper->stop(); + break; + } default: TRESPASS(); } diff --git a/media/jni/android_media_MediaCodec.h b/media/jni/android_media_MediaCodec.h index 5c34341a86a1..a58f9a74b563 100644 --- a/media/jni/android_media_MediaCodec.h +++ b/media/jni/android_media_MediaCodec.h @@ -173,6 +173,7 @@ private: enum { kWhatCallbackNotify, kWhatFrameRendered, + kWhatAsyncReleaseComplete, }; jclass mClass; @@ -185,6 +186,7 @@ private: bool mGraphicOutput{false}; bool mHasCryptoOrDescrambler{false}; std::once_flag mReleaseFlag; + std::once_flag mAsyncReleaseFlag; sp<AMessage> mCallbackNotification; sp<AMessage> mOnFrameRenderedNotification; diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java index 356acdcc9dd8..957558107de9 100644 --- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java +++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouter2ManagerTest.java @@ -281,17 +281,19 @@ public class MediaRouter2ManagerTest { } @Test - public void testGetRoutingControllers() throws Exception { + public void testGetRoutingSessions() throws Exception { CountDownLatch latch = new CountDownLatch(1); Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); + MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1); + addRouterCallback(new RouteCallback() {}); addManagerCallback(new MediaRouter2Manager.Callback() { @Override public void onTransferred(RoutingSessionInfo oldSessionInfo, RoutingSessionInfo newSessionInfo) { if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName()) - && newSessionInfo.getSelectedRoutes().contains(ROUTE_ID1)) { + && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) { latch.countDown(); } } @@ -299,11 +301,10 @@ public class MediaRouter2ManagerTest { assertEquals(1, mManager.getRoutingSessions(mPackageName).size()); - mManager.selectRoute(mPackageName, routes.get(ROUTE_ID1)); - latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS); + mManager.selectRoute(mPackageName, routeToSelect); + assertTrue(latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); List<RoutingSessionInfo> sessions = mManager.getRoutingSessions(mPackageName); - assertEquals(2, sessions.size()); RoutingSessionInfo sessionInfo = sessions.get(1); @@ -344,6 +345,47 @@ public class MediaRouter2ManagerTest { assertTrue(onTransferFailedLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); } + @Test + public void testRouterRelease_managerGetRoutingSessions() throws Exception { + CountDownLatch transferLatch = new CountDownLatch(1); + CountDownLatch releaseLatch = new CountDownLatch(1); + + Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_ALL); + MediaRoute2Info routeToSelect = routes.get(ROUTE_ID1); + assertNotNull(routeToSelect); + + addRouterCallback(new RouteCallback() {}); + addManagerCallback(new MediaRouter2Manager.Callback() { + @Override + public void onTransferred(RoutingSessionInfo oldSessionInfo, + RoutingSessionInfo newSessionInfo) { + if (TextUtils.equals(mPackageName, newSessionInfo.getClientPackageName()) + && newSessionInfo.getSelectedRoutes().contains(routeToSelect.getId())) { + transferLatch.countDown(); + } + } + @Override + public void onSessionReleased(RoutingSessionInfo session) { + releaseLatch.countDown(); + } + }); + + assertEquals(1, mManager.getRoutingSessions(mPackageName).size()); + assertEquals(1, mRouter2.getControllers().size()); + + mManager.transfer(mManager.getRoutingSessions(mPackageName).get(0), routeToSelect); + assertTrue(transferLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + assertEquals(2, mManager.getRoutingSessions(mPackageName).size()); + assertEquals(2, mRouter2.getControllers().size()); + mRouter2.getControllers().get(1).release(); + + assertTrue(releaseLatch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)); + + assertEquals(1, mRouter2.getControllers().size()); + assertEquals(1, mManager.getRoutingSessions(mPackageName).size()); + } + /** * Tests select, transfer, release of routes of a provider */ diff --git a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java index 4438893dabfc..3bf43dd4d1bf 100644 --- a/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java +++ b/packages/SettingsLib/AdaptiveIcon/src/com/android/settingslib/widget/AdaptiveOutlineDrawable.java @@ -29,7 +29,12 @@ import android.graphics.Path; import android.graphics.Rect; import android.graphics.drawable.AdaptiveIconDrawable; import android.graphics.drawable.DrawableWrapper; +import android.os.RemoteException; +import android.util.DisplayMetrics; import android.util.PathParser; +import android.view.Display; +import android.view.IWindowManager; +import android.view.WindowManagerGlobal; import androidx.annotation.IntDef; import androidx.annotation.VisibleForTesting; @@ -56,6 +61,7 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper { private int mStrokeWidth; private Bitmap mBitmap; private int mType; + private float mDensity; public AdaptiveOutlineDrawable(Resources resources, Bitmap bitmap) { super(new AdaptiveIconShapeDrawable(resources)); @@ -77,6 +83,7 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper { mPath = new Path(PathParser.createPathFromPathData( resources.getString(com.android.internal.R.string.config_icon_mask))); mStrokeWidth = resources.getDimensionPixelSize(R.dimen.adaptive_outline_stroke); + mDensity = resources.getDisplayMetrics().density; mOutlinePaint = new Paint(); mOutlinePaint.setColor(getColor(resources, type)); mOutlinePaint.setStyle(Paint.Style.STROKE); @@ -130,7 +137,12 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper { if (mType == TYPE_DEFAULT) { canvas.drawPath(mPath, mOutlinePaint); } else { - canvas.drawCircle(2 * mInsetPx, 2 * mInsetPx, 2 * mInsetPx - mStrokeWidth, + final float defaultDensity = getDefaultDisplayDensity(Display.DEFAULT_DISPLAY) + / (float) DisplayMetrics.DENSITY_DEFAULT; + final int insetPx = + Math.round(mInsetPx / (float) (Math.floor( + (mDensity / defaultDensity) * 100) / 100.0)); + canvas.drawCircle(2 * insetPx, 2 * insetPx, 2 * insetPx - mStrokeWidth, mOutlinePaint); } canvas.restoreToCount(count); @@ -139,6 +151,15 @@ public class AdaptiveOutlineDrawable extends DrawableWrapper { canvas.drawBitmap(mBitmap, bounds.left + mInsetPx, bounds.top + mInsetPx, null); } + private static int getDefaultDisplayDensity(int displayId) { + try { + final IWindowManager wm = WindowManagerGlobal.getWindowManagerService(); + return wm.getInitialDisplayDensity(displayId); + } catch (RemoteException exc) { + return -1; + } + } + @Override public int getIntrinsicHeight() { return mBitmap.getHeight() + 2 * mInsetPx; diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index 1d4cfdc88ad5..a89cf37e2d06 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -60,6 +60,7 @@ import androidx.lifecycle.OnLifecycleEvent; import com.android.internal.R; import com.android.internal.util.ArrayUtils; import com.android.settingslib.Utils; +import com.android.settingslib.utils.ThreadUtils; import java.io.File; import java.io.IOException; @@ -1588,6 +1589,15 @@ public class ApplicationsState { this.size = SIZE_UNKNOWN; this.sizeStale = true; ensureLabel(context); + // Speed up the cache of the icon and label description if they haven't been created. + ThreadUtils.postOnBackgroundThread(() -> { + if (this.icon == null) { + this.ensureIconLocked(context); + } + if (this.labelDescription == null) { + this.ensureLabelDescriptionLocked(context); + } + }); } public void ensureLabel(Context context) { diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java index d1cd043352cb..3015397ff1a3 100644 --- a/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java +++ b/packages/SettingsLib/src/com/android/settingslib/wifi/WifiTracker.java @@ -900,9 +900,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro updateNetworkInfo(info); fetchScansAndConfigsAndUpdateAccessPoints(); } else if (WifiManager.RSSI_CHANGED_ACTION.equals(action)) { - NetworkInfo info = - mConnectivityManager.getNetworkInfo(mWifiManager.getCurrentNetwork()); - updateNetworkInfo(info); + updateNetworkInfo(/* networkInfo= */ null); } } }; @@ -948,7 +946,7 @@ public class WifiTracker implements LifecycleObserver, OnStart, OnStop, OnDestro // We don't send a NetworkInfo object along with this message, because even if we // fetch one from ConnectivityManager, it might be older than the most recent // NetworkInfo message we got via a WIFI_STATE_CHANGED broadcast. - updateNetworkInfo(null); + updateNetworkInfo(/* networkInfo= */ null); } } } diff --git a/packages/SystemUI/res/drawable/ic_error_outline.xml b/packages/SystemUI/res/drawable/ic_error_outline.xml new file mode 100644 index 000000000000..140180ae8dbf --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_error_outline.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:fillColor="#FF000000" + android:pathData="M11,15h2v2h-2v-2zM11,7h2v6h-2L11,7zM11.99,2C6.47,2 2,6.48 2,12s4.47,10 9.99,10C17.52,22 22,17.52 22,12S17.52,2 11.99,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z"/> +</vector> diff --git a/packages/SystemUI/res/drawable/ic_settings_power.xml b/packages/SystemUI/res/drawable/ic_settings_power.xml new file mode 100644 index 000000000000..137c289ac572 --- /dev/null +++ b/packages/SystemUI/res/drawable/ic_settings_power.xml @@ -0,0 +1,25 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<vector xmlns:android="http://schemas.android.com/apk/res/android" + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M8,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM12,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1zM13,2h-2v10h2L13,2zM16.56,4.44l-1.45,1.45C16.84,6.94 18,8.83 18,11c0,3.31 -2.69,6 -6,6s-6,-2.69 -6,-6c0,-2.17 1.16,-4.06 2.88,-5.12L7.44,4.44C5.36,5.88 4,8.28 4,11c0,4.42 3.58,8 8,8s8,-3.58 8,-8c0,-2.72 -1.36,-5.12 -3.44,-6.56zM16,24c0.55,0 1,-0.45 1,-1s-0.45,-1 -1,-1 -1,0.45 -1,1 0.45,1 1,1z" + android:fillColor="#000000"/> +</vector>
\ No newline at end of file diff --git a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml index 4413b1ef3cd3..9ce030e844d4 100644 --- a/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout-sw600dp/keyguard_user_switcher_item.xml @@ -27,13 +27,13 @@ android:gravity="end|center_vertical" android:clickable="true" android:background="@drawable/kg_user_switcher_rounded_bg" + sysui:activatedTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" sysui:regularTextAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher"> <TextView android:id="@+id/user_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="25dp" android:layout_marginEnd="12dp" - android:textAppearance="@style/TextAppearance.StatusBar.Expanded.UserSwitcher" /> <com.android.systemui.statusbar.phone.UserAvatarView android:id="@+id/user_picture" android:layout_width="@dimen/kg_framed_avatar_size" diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index 477a70f4c7ad..5f83f45958e9 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -52,6 +52,7 @@ android:singleLine="true" android:ellipsize="marquee" android:marqueeRepeatLimit = "marquee_forever" + android:textDirection="locale" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toBottomOf="@+id/icon" app:layout_constraintStart_toEndOf="@+id/icon" /> @@ -67,6 +68,7 @@ android:focusable="false" android:maxLines="1" android:ellipsize="end" + android:textDirection="locale" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintBottom_toTopOf="@id/barrier"/> @@ -90,6 +92,7 @@ android:focusable="false" android:maxLines="1" android:ellipsize="end" + android:textDirection="locale" app:layout_constraintStart_toStartOf="parent" app:layout_constraintEnd_toStartOf="@id/favorite" app:layout_constraintTop_toTopOf="@id/favorite" diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml index df03787d567c..da9c43ccc1e9 100644 --- a/packages/SystemUI/res/layout/controls_more_item.xml +++ b/packages/SystemUI/res/layout/controls_more_item.xml @@ -20,5 +20,6 @@ android:layout_height="wrap_content" android:layout_gravity="start" android:paddingStart="@dimen/control_menu_horizontal_padding" - android:paddingEnd="@dimen/control_menu_horizontal_padding"/> + android:paddingEnd="@dimen/control_menu_horizontal_padding" + android:textDirection="locale"/> diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml index a46823d9bc38..da5277ce3876 100644 --- a/packages/SystemUI/res/layout/global_screenshot_static.xml +++ b/packages/SystemUI/res/layout/global_screenshot_static.xml @@ -53,15 +53,6 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"/> </HorizontalScrollView> - <ImageView - android:id="@+id/global_screenshot_animated_view" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:layout_gravity="center" - android:visibility="gone" - android:elevation="@dimen/screenshot_preview_elevation" - android:background="@drawable/screenshot_rounded_corners" - android:adjustViewBounds="true"/> <include layout="@layout/global_screenshot_preview"/> <FrameLayout android:id="@+id/global_screenshot_dismiss_button" diff --git a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml index 626951c8c0b7..1cd1a04ab462 100644 --- a/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml +++ b/packages/SystemUI/res/layout/keyguard_user_switcher_item.xml @@ -39,8 +39,6 @@ android:layout_width="@dimen/kg_framed_avatar_size" android:layout_height="@dimen/kg_framed_avatar_size" android:contentDescription="@null" - android:backgroundTint="@color/qs_user_detail_avatar_tint" - android:backgroundTintMode="src_atop" sysui:frameWidth="@dimen/keyguard_user_switcher_border_thickness" sysui:framePadding="2.5dp" sysui:badgeDiameter="18dp" diff --git a/packages/SystemUI/res/layout/partial_conversation_info.xml b/packages/SystemUI/res/layout/partial_conversation_info.xml index 803b0c61e6da..ecc311893497 100644 --- a/packages/SystemUI/res/layout/partial_conversation_info.xml +++ b/packages/SystemUI/res/layout/partial_conversation_info.xml @@ -35,7 +35,7 @@ android:clipChildren="false" android:clipToPadding="false"> <ImageView - android:id="@+id/conversation_icon" + android:id="@+id/icon" android:layout_width="@dimen/notification_guts_conversation_icon_size" android:layout_height="@dimen/notification_guts_conversation_icon_size" android:layout_centerVertical="true" @@ -60,20 +60,6 @@ android:textDirection="locale" style="@style/TextAppearance.NotificationImportanceChannel"/> <TextView - android:id="@+id/parent_channel_name" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:ellipsize="end" - android:textDirection="locale" - style="@style/TextAppearance.NotificationImportanceChannel"/> - <TextView - android:id="@+id/group_name" - android:layout_width="match_parent" - android:layout_height="wrap_content" - android:ellipsize="end" - android:textDirection="locale" - style="@style/TextAppearance.NotificationImportanceChannelGroup"/> - <TextView android:id="@+id/delegate_name" android:layout_width="match_parent" android:layout_height="wrap_content" diff --git a/packages/SystemUI/res/layout/qs_user_detail_item.xml b/packages/SystemUI/res/layout/qs_user_detail_item.xml index 0608685c3440..cc6c5d343502 100644 --- a/packages/SystemUI/res/layout/qs_user_detail_item.xml +++ b/packages/SystemUI/res/layout/qs_user_detail_item.xml @@ -30,6 +30,7 @@ android:clipToPadding="false" android:focusable="true" android:background="@drawable/ripple_drawable" + systemui:activatedTextAppearance="@style/TextAppearance.QS.UserSwitcher" systemui:regularTextAppearance="@style/TextAppearance.QS.UserSwitcher"> <com.android.systemui.statusbar.phone.UserAvatarView @@ -37,8 +38,6 @@ android:layout_width="@dimen/qs_framed_avatar_size" android:layout_height="@dimen/qs_framed_avatar_size" android:layout_marginBottom="7dp" - android:backgroundTint="@color/qs_user_detail_avatar_tint" - android:backgroundTintMode="src_atop" systemui:frameWidth="6dp" systemui:badgeDiameter="18dp" systemui:badgeMargin="1dp" diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 45d4cb4c191d..88102b2adc94 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Beweeg na regs bo"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Beweeg na links onder"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Beweeg na regs onder"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Maak toe"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Moenie dat gesprek \'n borrel word nie"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klets met borrels"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nuwe gesprekke verskyn as swerwende ikone, of borrels Tik op borrel om dit oop te maak. Sleep om dit te skuif."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swiep om meer te sien"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laai tans aanbevelings"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Maak hierdie mediasessie toe"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Hervat"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Onaktief, gaan program na"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Fout, probeer tans weer …"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Toestel is verwyder"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nie gekry nie"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrole is nie beskikbaar nie"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Kon nie by <xliff:g id="DEVICE">%1$s</xliff:g> ingaan nie. Gaan die <xliff:g id="APPLICATION">%2$s</xliff:g>-program na om seker te maak dat die kontrole steeds beskikbaar is en dat die programinstellings nie verander het nie."</string> + <string name="controls_open_app" msgid="483650971094300141">"Maak program oop"</string> <string name="controls_error_generic" msgid="352500456918362905">"Kan nie status laai nie"</string> <string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer weer"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Besig"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index a88be367da78..66c0131d6671 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ወደ ላይኛው ቀኝ አንቀሳቅስ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"የግርጌውን ግራ አንቀሳቅስ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ታችኛውን ቀኝ ያንቀሳቅሱ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"አሰናብት"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ውይይቶችን በአረፋ አታሳይ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"አረፋዎችን በመጠቀም ይወያዩ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"አዲስ ውይይቶች እንደ ተንሳፋፊ አዶዎች ወይም አረፋዎች ሆነው ይታያሉ። አረፋን ለመክፈት መታ ያድርጉ። ለመውሰድ ይጎትቱት።"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ተጨማሪ ለማየት ያንሸራትቱ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ምክሮችን በመጫን ላይ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ይህን የሚዲያ ክፍለ-ጊዜ ዝጋ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ከቆመበት ቀጥል"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ንቁ ያልኾነ፣ መተግበሪያን ይፈትሹ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ስህተት፣ እንደገና በመሞከር ላይ…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"መሣሪያ ተወግዷል"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"አልተገኘም"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"መቆጣጠሪያ አይገኝም"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ን መድረስ አልተቻለም። አሁንም ድረስ መቆጣጠሪያው ሊገኝ እንደሚችል እና የመተግበሪያ ቅንብሮቹ እንዳልተለወጡ ለማረጋገጥ <xliff:g id="APPLICATION">%2$s</xliff:g> መተግበሪያን ይፈትሹ።"</string> + <string name="controls_open_app" msgid="483650971094300141">"መተግበሪያ ክፈት"</string> <string name="controls_error_generic" msgid="352500456918362905">"ሁኔታን መጫን አልተቻልም"</string> <string name="controls_error_failed" msgid="960228639198558525">"ስህተት፣ እንደገና ይሞክሩ"</string> <string name="controls_in_progress" msgid="4421080500238215939">"በሂደት ላይ"</string> diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml index 2a0af5df1490..ebf4bc80b689 100644 --- a/packages/SystemUI/res/values-ar/strings.xml +++ b/packages/SystemUI/res/values-ar/strings.xml @@ -1022,7 +1022,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"الانتقال إلى أعلى اليسار"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نقل إلى أسفل يمين الشاشة"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نقل إلى أسفل اليسار"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"تجاهل"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"عدم عرض المحادثة كفقاعة محادثة"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"الدردشة باستخدام فقاعات المحادثات"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"تظهر المحادثات الجديدة كرموز عائمة أو كفقاعات. انقر لفتح فقاعة المحادثة، واسحبها لتحريكها."</string> @@ -1086,9 +1087,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"مرّر سريعًا لرؤية المزيد."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"جارٍ تحميل الاقتراحات"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"إغلاق جلسة تشغيل الوسائط هذه"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"استئناف التشغيل"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غير نشط، تحقّق من التطبيق."</string> <string name="controls_error_retryable" msgid="864025882878378470">"حدث خطأ، جارٍ إعادة المحاولة…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"تمت إزالة الجهاز."</string> + <string name="controls_error_removed" msgid="6675638069846014366">"لم يتم العثور عليه."</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"عنصر التحكّم غير متوفّر"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"تعذّر الوصول إلى <xliff:g id="DEVICE">%1$s</xliff:g>. تحقّق من تطبيق <xliff:g id="APPLICATION">%2$s</xliff:g> للتأكّد من أن عنصر التحكّم لا يزال متوفّرًا وأنه لم يتم تغيير إعدادات التطبيق."</string> + <string name="controls_open_app" msgid="483650971094300141">"فتح التطبيق"</string> <string name="controls_error_generic" msgid="352500456918362905">"يتعذّر تحميل الحالة."</string> <string name="controls_error_failed" msgid="960228639198558525">"حدث خطأ، يُرجى إعادة المحاولة."</string> <string name="controls_in_progress" msgid="4421080500238215939">"قيد التقدم"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index e3fd2cb16ec2..c3d1e78f74e5 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"শীৰ্ষৰ সোঁফালে নিয়ক"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"বুটামটো বাওঁফালে নিয়ক"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"তলৰ সোঁফালে নিয়ক"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"অগ্ৰাহ্য কৰক"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"বাৰ্তালাপ বাবল নকৰিব"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles ব্যৱহাৰ কৰি চাট কৰক"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন বাৰ্তালাপ উপঙি থকা চিহ্নসমূহ অথবা bubbles হিচাপে প্ৰদর্শিত হয়। Bubbles খুলিবলৈ টিপক। এইটো স্থানান্তৰ কৰিবলৈ টানি নিয়ক।"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"অধিক চাবলৈ ছোৱাইপ কৰক"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"চুপাৰিছসমূহ ল’ড কৰি থকা হৈছে"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া ছেশ্বনটো বন্ধ কৰক"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"পুনৰ আৰম্ভ কৰক"</string> <string name="controls_error_timeout" msgid="794197289772728958">"সক্ৰিয় নহয়, এপ্টো পৰীক্ষা কৰক"</string> <string name="controls_error_retryable" msgid="864025882878378470">"আসোঁৱাহ, পুনৰ চেষ্টা কৰি আছে…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইচটো আঁতৰোৱা হৈছে"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"বিচাৰি পোৱা নগ’ল"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"নিয়ন্ত্ৰণটো উপলব্ধ নহয়"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> এক্সেছ কৰিব পৰা নগ’ল। নিয়ন্ত্ৰণটো এতিয়াও উপলব্ধ আৰু এপ্টোৰ ছেটিংসমূহ সলনি কৰা হোৱা নাই বুলি নিশ্চিত কৰিবলৈ <xliff:g id="APPLICATION">%2$s</xliff:g> এপ্টো পৰীক্ষা কৰক।"</string> + <string name="controls_open_app" msgid="483650971094300141">"এপ্টো খোলক"</string> <string name="controls_error_generic" msgid="352500456918362905">"স্থিতি ল’ড কৰিব নোৱাৰি"</string> <string name="controls_error_failed" msgid="960228639198558525">"আসোঁৱাহ হৈছে, আকৌ চেষ্টা কৰক"</string> <string name="controls_in_progress" msgid="4421080500238215939">"চলি আছে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 0adee8c23d0e..3919fe314361 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuxarıya sağa köçürün"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Aşağıya sola köçürün"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Aşağıya sağa köçürün"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kənarlaşdırın"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Söhbətdən gələn bildirişi göstərməyin"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Yumrucuqlardan istifadə edərək söhbət edin"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni söhbətlər üzən nişanlar və ya yumrucuqlar kimi görünür. Yumrucuğu açmaq üçün toxunun. Hərəkət etdirmək üçün sürüşdürün."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Digərlərini görmək üçün sürüşdürün"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tövsiyələr yüklənir"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Bu media sessiyasını bağlayın"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Davam edin"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Aktiv deyil, tətbiqi yoxlayın"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Xəta, yenidən cəhd edilir…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz silindi"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Tapılmadı"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Nəzarət əlçatan deyil"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına giriş mümkün olmadı. <xliff:g id="APPLICATION">%2$s</xliff:g> tətbiqini yoxlayaraq nəzarətin hələ də əlçatan olduğuna və tətbiq ayarlarının dəyişmədiyinə əmin olun."</string> + <string name="controls_open_app" msgid="483650971094300141">"Tətbiqi açın"</string> <string name="controls_error_generic" msgid="352500456918362905">"Statusu yükləmək alınmadı"</string> <string name="controls_error_failed" msgid="960228639198558525">"Xəta, yenidən cəhd edin"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Davam edir"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 868d1cb64b0b..f2a6d65bd051 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -1007,9 +1007,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premesti gore desno"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premesti dole levo"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premesti dole desno"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne koristi oblačiće za konverzaciju"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte pomoću oblačića"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ćaskajte u oblačićima"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nove konverzacije se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da biste otvorili oblačić. Prevucite da biste ga premestili."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrolišite oblačiće u bilo kom trenutku"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Dodirnite Upravljajte da biste isključili oblačiće iz ove aplikacije"</string> @@ -1068,9 +1069,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da biste videli još"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavaju se preporuke"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu sesiju medija"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno. Vidite aplikaciju"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Greška, pokušava se ponovo…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristupanje uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspelo. Pogledajte aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da biste se uverili da je kontrola još uvek dostupna i da se podešavanja aplikacije nisu promenila."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string> <string name="controls_error_generic" msgid="352500456918362905">"Učitavanje statusa nije uspelo"</string> <string name="controls_error_failed" msgid="960228639198558525">"Greška. Probajte ponovo"</string> <string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 04cd56a5c9e7..d34f089ec9aa 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -1012,9 +1012,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перамясціце правей і вышэй"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перамясціць лявей і ніжэй"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перамясціць правей і ніжэй"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Адхіліць"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не паказваць размову ў выглядзе ўсплывальных апавяшчэнняў"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Размаўляйце ў чаце, які паказвае ўсплывальныя апавяшчэнні"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Усплывальныя апавяшчэнні"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новыя размовы будуць паказвацца як рухомыя значкі ці ўсплывальныя апавяшчэнні. Націсніце, каб адкрыць усплывальнае апавяшчэнне. Перацягніце яго, каб перамясціць."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Кіруйце ўсплывальнымі апавяшчэннямі ў любы час"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Каб выключыць усплывальныя апавяшчэнні з гэтай праграмы, націсніце \"Кіраваць\""</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Правядзіце пальцам, каб убачыць больш інфармацыі"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загружаюцца рэкамендацыі"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Закрыць гэты сеанс мультымедыя"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Узнавіць"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактыўна, праверце праграму"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Памылка, паўторная спроба…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Прылада выдалена"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Не знойдзена"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Кіраванне недаступнае"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Не ўдалося атрымаць доступ да прылады \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Праверце, ці не змяніліся налады праграмы \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" і ці даступная ў ёй функцыя кіравання."</string> + <string name="controls_open_app" msgid="483650971094300141">"Адкрыць праграму"</string> <string name="controls_error_generic" msgid="352500456918362905">"Не ўдалося загрузіць стан"</string> <string name="controls_error_failed" msgid="960228639198558525">"Памылка, паўтарыце спробу"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Выконваецца"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 034217cc01f4..2388cf6167c0 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Преместване горе вдясно"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Преместване долу вляво"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Преместване долу вдясно"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отхвърляне"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Без балончета за разговора"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговаряне чрез балончета"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори се показват като плаващи икони, или балончета. Докоснете балонче, за да го отворите, или го плъзнете, за да го преместите."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Прекарайте пръст, за да видите повече"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Препоръките се зареждат"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Затваряне на тази сесия за мултимедия"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Възобновяване"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, проверете прилож."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Грешка. Извършва се нов опит…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Устройството бе премахнато"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Не е намерено"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е налице"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Няма достъп до <xliff:g id="DEVICE">%1$s</xliff:g>. Отворете приложението <xliff:g id="APPLICATION">%2$s</xliff:g> и проверете дали контролата още е налице и дали настройките му не са променени."</string> + <string name="controls_open_app" msgid="483650971094300141">"Към приложението"</string> <string name="controls_error_generic" msgid="352500456918362905">"Състоян. не може да се зареди"</string> <string name="controls_error_failed" msgid="960228639198558525">"Грешка. Опитайте отново"</string> <string name="controls_in_progress" msgid="4421080500238215939">"В ход"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 7482dfef749a..d5e827f6b618 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"উপরে ডানদিকে সরান"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"নিচে বাঁদিকে সরান"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"নিচে ডান দিকে সরান"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"খারিজ করুন"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"কথোপকথন বাবল হিসেবে দেখাবে না"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"বাবল ব্যবহার করে চ্যাট করুন"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"নতুন কথোপকথন ভেসে থাকা আইকন বা বাবল হিসেবে দেখানো হয়। বাবল খুলতে ট্যাপ করুন। সেটি সরাতে ধরে টেনে আনুন।"</string> @@ -1013,17 +1014,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"সিস্টেম নেভিগেশন আপডেট হয়েছে। পরিবর্তন করার জন্য সেটিংসে যান।"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"সিস্টেম নেভিগেশন আপডেট করতে সেটিংসে যান"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"স্ট্যান্ডবাই"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"কথোপকথনকে \'গুরুত্বপূর্ণ\' হিসেবে সেট করা হয়েছে"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"গুরুত্বপূর্ণ কথোপকথন:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"কথোপকথনের বিভাগের উপরে দেখান"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"লক স্ক্রিনে প্রোফাইল ছবি দেখান"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"অ্যাপের উপরে একটি ভাসমান বুদবুদ হিসেবে দেখা যাবে"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"বিরক্ত করবে না মোডে ব্যাঘাত ঘটাতে পারে"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"বুঝেছি"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"সেটিংস"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"ওভারলে উইন্ডো বড় করে দেখা"</string> <string name="magnification_window_title" msgid="4863914360847258333">"উইন্ডো বড় করে দেখা"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"উইন্ডো কন্ট্রোল বড় করে দেখা"</string> @@ -1065,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"আরও দেখতে সোয়াইপ করুন"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"সাজেশন লোড করা হচ্ছে"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"এই মিডিয়া সেশন বেছে নিন"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"আবার চালু করুন"</string> <string name="controls_error_timeout" msgid="794197289772728958">"বন্ধ আছে, অ্যাপ চেক করুন"</string> <string name="controls_error_retryable" msgid="864025882878378470">"সমস্যা, আবার চেষ্টা করা হচ্ছে…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ডিভাইস সরিয়ে দেওয়া হয়েছে"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"খুঁজে পাওয়া যায়নি"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"কন্ট্রোল উপলভ্য নেই"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ডিভাইস অ্যাক্সেস করা যায়নি। <xliff:g id="APPLICATION">%2$s</xliff:g> অ্যাপ চেক করে দেখুন যাতে এটি নিশ্চিত করে নিতে পারেন যে কন্ট্রোল এখনও উপলভ্য আছে এবং অ্যাপ সেটিংসে কোনও পরিবর্তন করা হয়নি।"</string> + <string name="controls_open_app" msgid="483650971094300141">"অ্যাপ খুলুন"</string> <string name="controls_error_generic" msgid="352500456918362905">"স্ট্যাটাস লোড করা যাচ্ছে না"</string> <string name="controls_error_failed" msgid="960228639198558525">"সমস্যা হয়েছে, আবার চেষ্টা করুন"</string> <string name="controls_in_progress" msgid="4421080500238215939">"চলছে"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index c049c5f08498..37397f959aea 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -92,13 +92,13 @@ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Obrađivanje snimka ekrana"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Obavještenje za sesiju snimanja ekrana je u toku"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Započeti snimanje?"</string> - <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, sistem Android može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string> + <string name="screenrecord_description" msgid="1123231719680353736">"Prilikom snimanja, Android sistem može snimiti sve osjetljive informacije koje su vidljive na vašem ekranu ili koje reproducirate na uređaju. To uključuje lozinke, informacije za plaćanje, fotografije, poruke i zvuk."</string> <string name="screenrecord_audio_label" msgid="6183558856175159629">"Snimi zvučni zapis"</string> <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Zvuk uređaja"</string> <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Zvuk s vašeg uređaja, naprimjer muzika, pozivi i melodije zvona"</string> <string name="screenrecord_mic_label" msgid="2111264835791332350">"Mikrofon"</string> <string name="screenrecord_device_audio_and_mic_label" msgid="1831323771978646841">"Zvuk i mikrofon uređaja"</string> - <string name="screenrecord_start" msgid="330991441575775004">"Počni"</string> + <string name="screenrecord_start" msgid="330991441575775004">"Započni"</string> <string name="screenrecord_ongoing_screen_only" msgid="4459670242451527727">"Snimanje ekrana"</string> <string name="screenrecord_ongoing_screen_and_audio" msgid="5351133763125180920">"Snimanje ekrana i zvuka"</string> <string name="screenrecord_taps_label" msgid="1595690528298857649">"Prikaži dodire na ekranu"</string> @@ -1009,7 +1009,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pomjerite gore desno"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pomjeri dolje lijevo"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pomjerite dolje desno"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nemoj prikazivati razgovor u oblačićima"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatajte koristeći oblačiće"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori se prikazuju kao plutajuće ikone ili oblačići. Dodirnite da otvorite oblačić. Prevucite da ga premjestite."</string> @@ -1070,9 +1071,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prevucite da vidite više"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvori ovu medijsku sesiju"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, vidite aplikaciju"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Greška, ponovni pokušaj…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Pristup uređaju <xliff:g id="DEVICE">%1$s</xliff:g> nije uspio. Provjerite aplikaciju <xliff:g id="APPLICATION">%2$s</xliff:g> da se uvjerite da je kontrola i dalje dostupna i da se postavke aplikacije nisu promijenile."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otvori aplikaciju"</string> <string name="controls_error_generic" msgid="352500456918362905">"Nije moguće učitati status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Greška, pokušajte ponovo"</string> <string name="controls_in_progress" msgid="4421080500238215939">"U toku"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index 506429c2cf79..2fdddf710e13 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mou a dalt a la dreta"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mou a baix a l\'esquerra"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mou a baix a la dreta"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Omet"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostris la conversa com a bombolla"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xateja utilitzant les bombolles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les converses noves es mostren com a icones flotants o bombolles. Toca per obrir una bombolla. Arrossega-la per moure-la."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Llisca per veure\'n més"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregant les recomanacions"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Tanca aquesta sessió multimèdia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reprèn"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiu; comprova l\'aplicació"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error. S\'està tornant a provar…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"El dispositiu s\'ha suprimit"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"No s\'ha trobat"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no està disponible"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"No s\'ha pogut accedir a <xliff:g id="DEVICE">%1$s</xliff:g>. Consulta l\'aplicació <xliff:g id="APPLICATION">%2$s</xliff:g> per assegurar-te que el control encara estigui disponible i que la configuració de l\'aplicació no hagi canviat."</string> + <string name="controls_open_app" msgid="483650971094300141">"Obre l\'aplicació"</string> <string name="controls_error_generic" msgid="352500456918362905">"No es pot carregar l\'estat"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error; torna-ho a provar"</string> <string name="controls_in_progress" msgid="4421080500238215939">"En curs"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index 48ab79e01643..18012b5e4280 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Přesunout vpravo nahoru"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Přesunout vlevo dolů"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Přesunout vpravo dolů"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavřít"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovat konverzaci v bublinách"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatujte pomocí bublin"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzace se zobrazují jako plovoucí ikony, neboli bubliny. Klepnutím bublinu otevřete. Přetažením ji posunete."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Přejetím prstem zobrazíte další položky"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítání doporučení"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zavřít tuto mediální relaci"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovat"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivní, zkontrolujte aplikaci"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Chyba. Nový pokus…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Zařízení bylo odebráno"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nenalezeno"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládání není k dispozici"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Zařízení <xliff:g id="DEVICE">%1$s</xliff:g> nelze použít. V aplikaci <xliff:g id="APPLICATION">%2$s</xliff:g> zkontrolujte, zda je ovládání stále k dispozici a zda se nezměnilo nastavení."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otevřít aplikaci"</string> <string name="controls_error_generic" msgid="352500456918362905">"Stav nelze načíst"</string> <string name="controls_error_failed" msgid="960228639198558525">"Chyba, zkuste to znovu"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Probíhá"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index 8d2d5c5f9adb..3f71e3d49137 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flyt op til højre"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flyt ned til venstre"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flyt ned til højre"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Afvis"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Vis ikke samtaler i bobler"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat ved hjælp af bobler"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som svævende ikoner eller bobler. Tryk for at åbne boblen. Træk for at flytte den."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Stryg for at se mere"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Indlæser anbefalinger"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Luk denne mediesession"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Genoptag"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Tjek appen"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Fejl. Prøver igen…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Enheden er fjernet"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ikke fundet"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Styringselement ikke tilgængeligt"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Der kunne ikke skaffes adgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Tjek <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for at sikre at styringselementet stadig er tilgængeligt, og at appens indstillinger ikke er blevet ændret."</string> + <string name="controls_open_app" msgid="483650971094300141">"Åbn app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Statussen kan ikke indlæses"</string> <string name="controls_error_failed" msgid="960228639198558525">"Der opstod en fejl. Prøv igen"</string> <string name="controls_in_progress" msgid="4421080500238215939">"I gang"</string> diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml index 50cb3f3f498e..075a496c244b 100644 --- a/packages/SystemUI/res/values-de/strings.xml +++ b/packages/SystemUI/res/values-de/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Nach rechts oben verschieben"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Nach unten links verschieben"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Nach unten rechts verschieben"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Schließen"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Unterhaltung nicht als Bubble anzeigen"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bubbles zum Chatten verwenden"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Neue Unterhaltungen erscheinen als unverankerte Symbole, \"Bubbles\" genannt. Wenn du die Bubble öffnen möchtest, tippe sie an. Wenn du sie verschieben möchtest, zieh an ihr."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Wischen, um weitere zu sehen"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Empfehlungen werden geladen"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Diese Mediensitzung schließen"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Fortsetzen"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv – sieh in der App nach"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Fehler. Neuer Versuch…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Gerät entfernt"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nicht gefunden"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Steuerelement nicht verfügbar"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Zugriff auf <xliff:g id="DEVICE">%1$s</xliff:g> nicht möglich. Prüfe, ob das Steuerelement in der App \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" noch verfügbar ist und die App-Einstellungen nicht geändert wurden."</string> + <string name="controls_open_app" msgid="483650971094300141">"App öffnen"</string> <string name="controls_error_generic" msgid="352500456918362905">"Status kann nicht geladen werden"</string> <string name="controls_error_failed" msgid="960228639198558525">"Fehler – versuch es noch mal"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Läuft"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index 6a32d57f950c..c8db318dfb65 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Μετακίνηση επάνω δεξιά"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Μετακίνηση κάτω αριστερά"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Μετακίνηση κάτω δεξιά"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Παράβλεψη"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Να μην γίνει προβολή της συζήτησης σε συννεφάκια."</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Συζητήστε χρησιμοποιώντας συννεφάκια."</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Οι νέες συζητήσεις εμφανίζονται ως κινούμενα εικονίδια ή φούσκες. Πατήστε για να ανοίξετε τη φούσκα. Σύρετε για να το μετακινήσετε."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Σύρετε για να δείτε περισσότερα."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Φόρτωση προτάσεων"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Κλείσιμο αυτής της περιόδου λειτουργίας μέσων."</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Συνέχιση"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ανενεργό, έλεγχος εφαρμογής"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Προέκυψε σφάλμα. Επανάληψη…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Η συσκευή καταργήθηκε"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Δεν βρέθηκε."</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Μη διαθέσιμο στοιχείο ελέγχου"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Δεν ήταν δυνατή η πρόσβαση στη συσκευή <xliff:g id="DEVICE">%1$s</xliff:g>. Ελέγξτε την εφαρμογή <xliff:g id="APPLICATION">%2$s</xliff:g> για να βεβαιωθείτε ότι το στοιχείο ελέγχου εξακολουθεί να είναι διαθέσιμο και ότι οι ρυθμίσεις της εφαρμογής δεν έχουν αλλάξει."</string> + <string name="controls_open_app" msgid="483650971094300141">"Άνοιγμα εφαρμογής"</string> <string name="controls_error_generic" msgid="352500456918362905">"Αδυναμία φόρτωσης κατάστασης"</string> <string name="controls_error_failed" msgid="960228639198558525">"Σφάλμα, προσπαθήστε ξανά."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Σε εξέλιξη"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 35f09af553d4..708f2f4f017a 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string> + <string name="controls_open_app" msgid="483650971094300141">"Open app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 8c8db6aefcbd..313c604953ea 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string> + <string name="controls_open_app" msgid="483650971094300141">"Open app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 35f09af553d4..708f2f4f017a 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string> + <string name="controls_open_app" msgid="483650971094300141">"Open app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 35f09af553d4..708f2f4f017a 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Device removed"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure that the control is still available and that the app settings haven’t changed."</string> + <string name="controls_open_app" msgid="483650971094300141">"Open app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index e514ccbd8e83..5d2e3eb16780 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -1002,7 +1002,7 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Move top right"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Move bottom left"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Move bottom right"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dismiss"</string> + <string name="bubble_dismiss_text" msgid="1314082410868930066">"Dismiss bubble"</string> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Don’t bubble conversation"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat using bubbles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"New conversations appear as floating icons, or bubbles. Tap to open bubble. Drag to move it."</string> @@ -1062,10 +1062,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe to see more"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Loading recommendations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Close this media session"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Resume"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactive, check app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, retrying…"</string> - <!-- no translation found for controls_error_removed (6299213591234723805) --> - <skip /> + <string name="controls_error_removed" msgid="6675638069846014366">"Not found"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Control is unavailable"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Couldn’t access <xliff:g id="DEVICE">%1$s</xliff:g>. Check the <xliff:g id="APPLICATION">%2$s</xliff:g> app to make sure the control is still available and that the app settings haven’t changed."</string> + <string name="controls_open_app" msgid="483650971094300141">"Open app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Can’t load status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, try again"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In progress"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index b1a742700297..db5b68c0dd15 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ubicar arriba a la derecha"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ubicar abajo a la izquierda"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ubicar abajo a la derecha"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar la conversación en burbujas"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat con burbujas"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como elementos flotantes o burbujas. Presiona para abrir la burbuja. Arrástrala para moverla."</string> @@ -1013,17 +1014,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"Se actualizó el sistema de navegación. Para hacer cambios, ve a Configuración."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"Ve a Configuración para actualizar la navegación del sistema"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"En espera"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"Se estableció la conversación como prioritaria"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias harán lo siguiente:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de conversaciones"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran una foto de perfil en pantalla de bloqueo"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbujas flotantes encima de apps"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Suspender No interrumpir"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"Configuración"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"Ventana superpuesta de ampliación"</string> <string name="magnification_window_title" msgid="4863914360847258333">"Ventana de ampliación"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"Controles de ampliación de la ventana"</string> @@ -1065,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más elementos"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Verifica la app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Hubo un error. Reintentando…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Se quitó el dispositivo"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"No se encontró"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible."</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"No se pudo acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Revisa la app de <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que el control siga estando disponible y de que no haya cambiado la configuración de la app."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string> <string name="controls_error_generic" msgid="352500456918362905">"No se pudo cargar el estado"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error. Vuelve a intentarlo."</string> <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index f210fbb48fec..1d8549a78efa 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -448,7 +448,7 @@ <string name="zen_alarms_introduction" msgid="3987266042682300470">"No te molestarán los sonidos ni las vibraciones, excepto las alarmas. Seguirás escuchando el contenido que quieras reproducir, como música, vídeos y juegos."</string> <string name="zen_priority_customize_button" msgid="4119213187257195047">"Personalizar"</string> <string name="zen_silence_introduction_voice" msgid="853573681302712348">"Esta opción bloqueará TODOS los sonidos y todas las vibraciones, por ejemplo, los vídeos, los juegos, las alarmas y la música. Seguirás pudiendo hacer llamadas."</string> - <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo permite bloquear TODOS los sonidos y todas las vibraciones (p. ej., los de alarmas, música, vídeos y juegos)."</string> + <string name="zen_silence_introduction" msgid="6117517737057344014">"Este modo bloquea TODOS los sonidos y todas las vibraciones, lo que incluye alarmas, música, vídeos y juegos."</string> <string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string> <string name="speed_bump_explanation" msgid="7248696377626341060">"Notificaciones menos urgente abajo"</string> <string name="notification_tap_again" msgid="4477318164947497249">"Toca de nuevo para abrir"</string> @@ -1002,10 +1002,11 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover arriba a la derecha"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover abajo a la izquierda."</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover abajo a la derecha"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cerrar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"No mostrar conversación en burbujas"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear mediante burbujas"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes o burbujas. Toca para abrir la burbuja. Arrastra para moverla."</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatea con burbujas"</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Las conversaciones nuevas aparecen como iconos flotantes llamadas \"burbujas\". Toca para abrir la burbuja. Arrastra para moverla."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Controla las burbujas en cualquier momento"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Toca Gestionar para desactivar las burbujas de esta aplicación"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Entendido"</string> @@ -1016,7 +1017,7 @@ <string name="priority_onboarding_title" msgid="2893070698479227616">"Conversación marcada como prioritaria"</string> <string name="priority_onboarding_behavior" msgid="5342816047020432929">"Las conversaciones prioritarias:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"Se muestran en la parte superior de la sección de conversaciones"</string> - <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran tu imagen de perfil en la pantalla de bloqueo"</string> + <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"Muestran la imagen de perfil en la pantalla de bloqueo"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"Aparecen como burbuja sobre las aplicaciones"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"Interrumpen el modo No molestar"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"Entendido"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Desliza el dedo para ver más"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendaciones"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Cerrar esta sesión multimedia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reanudar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo, comprobar aplicación"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error; reintentando…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo quitado"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"No se ha encontrado"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"El control no está disponible"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"No se ha podido acceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Comprueba que el control siga disponible en la aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> y que no se haya modificado su configuración."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string> <string name="controls_error_generic" msgid="352500456918362905">"No se ha podido cargar el estado"</string> <string name="controls_error_failed" msgid="960228639198558525">"Se ha producido un error. Vuelve a intentarlo."</string> <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index 0d640e13cee7..ede01b7f191c 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -92,7 +92,7 @@ <string name="screenrecord_background_processing_label" msgid="7244617554884238898">"Ekraanisalvestuse töötlemine"</string> <string name="screenrecord_channel_description" msgid="4147077128486138351">"Pooleli märguanne ekraanikuva salvestamise seansi puhul"</string> <string name="screenrecord_start_label" msgid="1750350278888217473">"Kas alustada salvestamist?"</string> - <string name="screenrecord_description" msgid="1123231719680353736">"Heli salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string> + <string name="screenrecord_description" msgid="1123231719680353736">"Salvestamise ajal võib Androidi süsteem jäädvustada tundlikku teavet, mis on ekraanikuval nähtav või mida seadmes esitatakse. See hõlmab paroole, makseteavet, fotosid, sõnumeid ja heli."</string> <string name="screenrecord_audio_label" msgid="6183558856175159629">"Heli salvestamine"</string> <string name="screenrecord_device_audio_label" msgid="9016927171280567791">"Seadme heli"</string> <string name="screenrecord_device_audio_description" msgid="4922694220572186193">"Seadmest pärinev heli, nt muusika, kõned ja helinad"</string> @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Teisalda üles paremale"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Teisalda alla vasakule"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Teisalda alla paremale"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loobu"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ära kuva vestlust mullina"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Vestelge mullide abil"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uued vestlused kuvatakse hõljuvate ikoonidena ehk mullidena. Puudutage mulli avamiseks. Lohistage mulli, et seda liigutada."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pühkige sõrmega, et näha rohkem"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Soovituste laadimine"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Sulge see meediaseanss"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Jätka"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Passiivne, vaadake rakendust"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Viga, proovitakse uuesti …"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Seade on eemaldatud"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ei leitud"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Juhtelement pole saadaval"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Seadmele <xliff:g id="DEVICE">%1$s</xliff:g> ei pääsenud juurde. Kontrollige rakendust <xliff:g id="APPLICATION">%2$s</xliff:g> ja veenduge, et juhtelement oleks endiselt saadaval ning rakenduse seaded poleks muutunud."</string> + <string name="controls_open_app" msgid="483650971094300141">"Ava rakendus"</string> <string name="controls_error_generic" msgid="352500456918362905">"Olekut ei saa laadida"</string> <string name="controls_error_failed" msgid="960228639198558525">"Ilmnes viga, proovige uuesti"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Pooleli"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index 1cb3148f73eb..641d031ef4aa 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Eraman goialdera, eskuinetara"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Eraman behealdera, ezkerretara"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Eraman behealdera, eskuinetara"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Baztertu"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ez erakutsi elkarrizketak burbuila gisa"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Txateatu burbuilen bidez"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Elkarrizketa berriak ikono gainerakor edo burbuila gisa agertzen dira. Sakatu burbuila irekitzeko. Arrasta ezazu mugitzeko."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasatu hatza aukera gehiago ikusteko"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Gomendioak kargatzen"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Itxi multimedia-saio hau"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Berrekin"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktibo; egiaztatu aplikazioa"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Errorea. Berriro saiatzen…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Gailua kendu da"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ez da aurkitu"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Ez dago erabilgarri kontrolatzeko aukera"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Ezin izan da atzitu <xliff:g id="DEVICE">%1$s</xliff:g>. Joan <xliff:g id="APPLICATION">%2$s</xliff:g> aplikaziora, eta ziurtatu kontrolatzeko aukera oraindik ere erabilgarri dagoela eta aplikazioaren ezarpenak ez direla aldatu."</string> + <string name="controls_open_app" msgid="483650971094300141">"Ireki aplikazioa"</string> <string name="controls_error_generic" msgid="352500456918362905">"Ezin da kargatu egoera"</string> <string name="controls_error_failed" msgid="960228639198558525">"Errorea. Saiatu berriro."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Abian"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 986015ed378c..eec54deb2b8e 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"انتقال به بالا سمت چپ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"انتقال به پایین سمت راست"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"انتقال به پایین سمت چپ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"رد کردن"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"مکالمه در حباب نشان داده نشود"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"گپ بااستفاده از ابزارک اعلان"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"مکالمههای جدید بهصورت نمادهای شناور یا ابزارک اعلان نشان داده شوند. برای باز کردن ابزارک اعلان ضربه بزنید. برای جابهجایی، آن را بکشید."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"برای دیدن موارد بیشتر، تند بکشید"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"درحال بار کردن توصیهها"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"بستن این جلسه رسانه"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ازسرگیری"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیرفعال، برنامه را بررسی کنید"</string> <string name="controls_error_retryable" msgid="864025882878378470">"خطا، درحال تلاش مجدد…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"دستگاه برداشته شد"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"پیدا نشد"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"کنترل دردسترس نیست"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"دسترسی به <xliff:g id="DEVICE">%1$s</xliff:g> ممکن نیست. برنامه <xliff:g id="APPLICATION">%2$s</xliff:g> را بررسی کنید تا مطمئن شوید کنترل هنوز دردسترس باشد و تنظیمات برنامه تغییر نکرده باشد."</string> + <string name="controls_open_app" msgid="483650971094300141">"بازکردن برنامه"</string> <string name="controls_error_generic" msgid="352500456918362905">"وضعیت بار نشد"</string> <string name="controls_error_failed" msgid="960228639198558525">"خطا، دوباره امتحان کنید"</string> <string name="controls_in_progress" msgid="4421080500238215939">"درحال انجام"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index be04730bc3a9..ee7ed70718a1 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Siirrä oikeaan yläreunaan"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Siirrä vasempaan alareunaan"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Siirrä oikeaan alareunaan"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ohita"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Älä näytä kuplia keskusteluista"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chattaile kuplien avulla"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Uudet keskustelut näkyvät kelluvina kuvakkeina tai kuplina. Avaa kupla napauttamalla. Siirrä sitä vetämällä."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pyyhkäise nähdäksesi lisää"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ladataan suosituksia"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Sulje tämä median käyttökerta"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Jatka"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Epäaktiivinen, tarkista sovellus"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Virhe, yritetään uudelleen…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Laite poistettu"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ei löydy"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Ohjain ei ole käytettävissä"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Ei pääsyä: <xliff:g id="DEVICE">%1$s</xliff:g>. Avaa <xliff:g id="APPLICATION">%2$s</xliff:g> ja tarkista, että ohjain on edelleen käytettävissä ja että sovelluksen asetukset eivät ole muuttuneet."</string> + <string name="controls_open_app" msgid="483650971094300141">"Avaa sovellus"</string> <string name="controls_error_generic" msgid="352500456918362905">"Tilaa ei voi ladata"</string> <string name="controls_error_failed" msgid="960228639198558525">"Virhe, yritä uudelleen"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Käynnissä"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index a80e2d3970db..c71ab7ee4894 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer dans coin sup. droit"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer dans coin inf. gauche"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer dans coin inf. droit"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Fermer"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher les conversations dans des bulles"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Clavarder en utilisant des bulles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes (de bulles). Touchez une bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayez l\'écran pour en afficher davantage"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations…"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifiez l\'appli"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erreur, nouvelle tentative…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"La commande n\'est pas accessible"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à <xliff:g id="DEVICE">%1$s</xliff:g>. Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours offerte et que les paramètres de l\'application n\'ont pas changé."</string> + <string name="controls_open_app" msgid="483650971094300141">"Ouvrir"</string> <string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string> <string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string> <string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index b95cf5790f13..4c69c865d1b5 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Déplacer en haut à droite"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Déplacer en bas à gauche"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Déplacer en bas à droite"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorer"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne pas afficher la conversations dans des bulles"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatter en utilisant des bulles"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Les nouvelles conversations s\'affichent sous forme d\'icônes flottantes ou bulles. Appuyez sur la bulle pour l\'ouvrir. Faites-la glisser pour la déplacer."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Balayer l\'écran pour voir plus d\'annonces"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Chargement des recommandations"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Fermer cette session multimédia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reprendre"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Délai expiré, vérifier l\'appli"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erreur. Nouvelle tentative…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Appareil supprimé"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Introuvable"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Commande indisponible"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossible d\'accéder à \"<xliff:g id="DEVICE">%1$s</xliff:g>\". Vérifiez l\'application <xliff:g id="APPLICATION">%2$s</xliff:g> pour vous assurer que la commande est toujours disponible et que les paramètres de l\'application n\'ont pas changé."</string> + <string name="controls_open_app" msgid="483650971094300141">"Ouvrir l\'application"</string> <string name="controls_error_generic" msgid="352500456918362905">"Impossible de charger l\'état"</string> <string name="controls_error_failed" msgid="960228639198558525">"Erreur. Veuillez réessayer."</string> <string name="controls_in_progress" msgid="4421080500238215939">"En cours"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 960e4169d4c6..d80bd95abf65 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover á parte superior dereita"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover á parte infer. esquerda"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover á parte inferior dereita"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non mostrar a conversa como burbulla"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatear usando burbullas"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"As conversas novas aparecen como iconas flotantes ou burbullas. Toca para abrir a burbulla e arrastra para movela."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Pasar o dedo para ver máis"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Cargando recomendacións"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Pechar esta sesión multimedia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactivo. Comproba a app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando de novo…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Quitouse o dispositivo"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Non se atopou"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"O control non está dispoñible"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Non se puido acceder a: <xliff:g id="DEVICE">%1$s</xliff:g>. Comproba a aplicación <xliff:g id="APPLICATION">%2$s</xliff:g> para asegurarte de que o control aínda estea dispoñible e que non se modificase a configuración da aplicación."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir aplicación"</string> <string name="controls_error_generic" msgid="352500456918362905">"Non se puido cargar o estado"</string> <string name="controls_error_failed" msgid="960228639198558525">"Erro. Téntao de novo"</string> <string name="controls_in_progress" msgid="4421080500238215939">"En curso"</string> diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml index 4936b7b7c2da..c641208055c1 100644 --- a/packages/SystemUI/res/values-gu/strings.xml +++ b/packages/SystemUI/res/values-gu/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ઉપર જમણે ખસેડો"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"નીચે ડાબે ખસેડો"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"નીચે જમણે ખસેડો"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"છોડી દો"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"વાતચીતને બબલ કરશો નહીં"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"બબલનો ઉપયોગ કરીને ચેટ કરો"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"નવી વાતચીત ફ્લોટિંગ આઇકન અથવા બબલ જેવી દેખાશે. બબલને ખોલવા માટે ટૅપ કરો. તેને ખસેડવા માટે ખેંચો."</string> @@ -1013,17 +1014,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"સિસ્ટમ નૅવિગેશન અપડેટ કર્યું. ફેરફારો કરવા માટે, સેટિંગ પર જાઓ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"સિસ્ટમ નૅવિગેશનને અપડેટ કરવા માટે સેટિંગ પર જાઓ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"સ્ટૅન્ડબાય"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"વાતચીતને પ્રાધાન્યતા ધરાવતી તરીકે સેટ કરી"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"પ્રાધાન્યતા ધરાવતી વાતચીતો:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"વાતચીત વિભાગની ટોચ પર બતાવો"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"લૉક સ્ક્રીન પર પ્રોફાઇલ ફોટો બતાવો"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ઍપની ટોચ પર તરતા બબલ તરીકે દેખાય છે"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ખલેલ પાડશો નહીં સેટિંગમાં હસ્તક્ષેપ કરી શકે છે"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"સમજાઈ ગયું"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"સેટિંગ"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"વિસ્તૃતીકરણ ઓવરલે વિંડો"</string> <string name="magnification_window_title" msgid="4863914360847258333">"વિસ્તૃતીકરણ વિંડો"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"વિસ્તૃતીકરણ વિંડોના નિયંત્રણો"</string> @@ -1065,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"વધુ જોવા માટે સ્વાઇપ કરો"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"સુઝાવ લોડ કરી રહ્યાં છીએ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"આ મીડિયા સત્રને બંધ કરો"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ફરી શરૂ કરો"</string> <string name="controls_error_timeout" msgid="794197289772728958">"નિષ્ક્રિય, ઍપને ચેક કરો"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ભૂલ, ફરી પ્રયાસ કરી રહ્યા છીએ…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ડિવાઇસ કાઢી નાખ્યું"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"મળ્યું નથી"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"નિયંત્રણ ઉપલબ્ધ નથી"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ને ઍક્સેસ કરી શક્યાં નહીં. નિયંત્રણ હજી પણ ઉપલબ્ધ છે અને તે કે ઍપના સેટિંગ બદલાયા નથી તેની ખાતરી કરવા માટે <xliff:g id="APPLICATION">%2$s</xliff:g> ઍપ ચેક કરો."</string> + <string name="controls_open_app" msgid="483650971094300141">"ઍપ ખોલો"</string> <string name="controls_error_generic" msgid="352500456918362905">"સ્ટેટસ લોડ કરી શકાતું નથી"</string> <string name="controls_error_failed" msgid="960228639198558525">"ભૂલ, ફરીથી પ્રયાસ કરો"</string> <string name="controls_in_progress" msgid="4421080500238215939">"પ્રક્રિયા ચાલુ છે"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 1fcfcc4746d9..428840742b45 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -1004,7 +1004,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सबसे ऊपर दाईं ओर ले जाएं"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"बाईं ओर सबसे नीचे ले जाएं"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"सबसे नीचे दाईं ओर ले जाएं"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"खारिज करें"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"बातचीत को बबल न करें"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल्स का इस्तेमाल करके चैट करें"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"नई बातचीत फ़्लोटिंग आइकॉन या बबल्स की तरह दिखेंगी. बबल को खोलने के लिए टैप करें. इसे एक जगह से दूसरी जगह ले जाने के लिए खींचें और छोड़ें."</string> @@ -1064,9 +1065,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ज़्यादा देखने के लिए स्वाइप करें"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सुझाव लोड हो रहे हैं"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"इस मीडिया सेशन को बंद करें"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"फिर से शुरू करें"</string> <string name="controls_error_timeout" msgid="794197289772728958">"काम नहीं कर रहा, ऐप जांचें"</string> <string name="controls_error_retryable" msgid="864025882878378470">"कोई गड़बड़ी हुई, फिर से कोशिश की जा रही है…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"डिवाइस हटाया गया"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"कंट्रोल नहीं मिला"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"कंट्रोल मौजूद नहीं है"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ऐक्सेस नहीं किया जा सका. <xliff:g id="APPLICATION">%2$s</xliff:g> ऐप्लिकेशन देखें, ताकि यह पक्का किया जा सके कि कंट्रोल अब भी मौजूद है और सेटिंग में कोई बदलाव नहीं हुआ है."</string> + <string name="controls_open_app" msgid="483650971094300141">"ऐप्लिकेशन खोलें"</string> <string name="controls_error_generic" msgid="352500456918362905">"स्थिति लोड नहीं की जा सकती"</string> <string name="controls_error_failed" msgid="960228639198558525">"गड़बड़ी हुई, फिर से कोशिश करें"</string> <string name="controls_in_progress" msgid="4421080500238215939">"जारी है"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index c918dca9d337..b8b784c36735 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -1007,7 +1007,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premjesti u gornji desni kut"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premjesti u donji lijevi kut"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premjestite u donji desni kut"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Odbaci"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Zaustavi razgovor u oblačićima"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatanje pomoću oblačića"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi razgovori pojavljuju se kao pomične ikone ili oblačići. Dodirnite za otvaranje oblačića. Povucite da biste ga premjestili."</string> @@ -1068,9 +1069,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Prijeđite prstom da vidite više"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Učitavanje preporuka"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zatvorite ovu medijsku sesiju"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Nastavi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, provjerite aplik."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Pogreška, pokušavamo ponovo…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Uređaj je uklonjen"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nije pronađeno"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrola nije dostupna"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nije moguće pristupiti uređaju: <xliff:g id="DEVICE">%1$s</xliff:g>. U aplikaciji <xliff:g id="APPLICATION">%2$s</xliff:g> provjerite je li kontrola i dalje dostupna te potvrdite da se postavke aplikacije nisu promijenile."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otvori apl."</string> <string name="controls_error_generic" msgid="352500456918362905">"Status se ne može učitati"</string> <string name="controls_error_failed" msgid="960228639198558525">"Pogreška, pokušajte ponovo"</string> <string name="controls_in_progress" msgid="4421080500238215939">"U tijeku"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index 2a991f1089e3..551fcd8b2975 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Áthelyezés fel és jobbra"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Áthelyezés le és balra"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Áthelyezés le és jobbra"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Elvetés"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ne jelenjen meg a beszélgetés buborékban"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Buborékokat használó csevegés"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Az új beszélgetések lebegő ikonként, vagyis buborékként jelennek meg. A buborék megnyitásához koppintson rá. Áthelyezéshez húzza a kívánt helyre."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Továbbiak megtekintéséhez csúsztasson"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Javaslatok betöltése…"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Médiamunkamenet bezárása"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Folytatás"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktív, ellenőrizze az appot"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Hiba, újrapróbálkozás…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Eszköz eltávolítva"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nem található"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Nem hozzáférhető vezérlő"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nem lehet hozzáférni a következőhöz: <xliff:g id="DEVICE">%1$s</xliff:g>. Ellenőrizze a(z) <xliff:g id="APPLICATION">%2$s</xliff:g> alkalmazást, és győződjön meg arról, hogy a vezérlő továbbra is rendelkezésre áll, illetve nem változtak az alkalmazás beállításai."</string> + <string name="controls_open_app" msgid="483650971094300141">"App megnyitása"</string> <string name="controls_error_generic" msgid="352500456918362905">"Állapot betöltése sikertelen"</string> <string name="controls_error_failed" msgid="960228639198558525">"Hiba történt. Próbálja újra."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Folyamatban"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index 908231a72772..730f1155502b 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Տեղափոխել վերև՝ աջ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Տեղափոխել ներքև՝ ձախ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Տեղափոխել ներքև՝ աջ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Փակել"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Զրույցը չցուցադրել ամպիկի տեսքով"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Զրուցել ամպիկների միջոցով"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Նոր խոսակցությունները կհայտնվեն լողացող պատկերակների կամ ամպիկների տեսքով։ Հպեք՝ ամպիկը բացելու համար։ Քաշեք՝ այն տեղափոխելու համար։"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Սահեցրեք մատը՝ ավելին իմանալու համար"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Բեռնման խորհուրդներ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Փակել աշխատաշրջանը"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Շարունակել"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Ակտիվ չէ, ստուգեք հավելվածը"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Սխալ. նորից ենք փորձում…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Սարքը հեռացված է"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Չի գտնվել"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Կառավարման տարրը հասանելի չէ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> սարքն անհասանելի է։ Ստուգեք <xliff:g id="APPLICATION">%2$s</xliff:g> հավելվածը՝ համոզվելու, որ կառավարման տարրը դեռ հասանելի է և հավելվածի կարգավորումները չեն փոխվել։"</string> + <string name="controls_open_app" msgid="483650971094300141">"Բացել հավելվածը"</string> <string name="controls_error_generic" msgid="352500456918362905">"Չհաջողվեց բեռնել կարգավիճակը"</string> <string name="controls_error_failed" msgid="960228639198558525">"Սխալ առաջացավ։ Նորից փորձեք։"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Ընթացքի մեջ է"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index 2e11e423575f..3614cb4d88c0 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pindahkan ke kanan atas"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pindahkan ke kiri bawah"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pindahkan ke kanan bawah"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Tutup"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan gunakan percakapan balon"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat dalam tampilan balon"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Percakapan baru muncul sebagai ikon mengambang, atau balon. Ketuk untuk membuka balon. Tarik untuk memindahkannya."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Geser untuk melihat selengkapnya"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuat rekomendasi"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Lanjutkan"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nonaktif, periksa aplikasi"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Error, mencoba lagi..."</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Perangkat dihapus"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemukan"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol tidak tersedia"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa aplikasi <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kontrol masih tersedia dan bahwa setelan aplikasi tidak berubah."</string> + <string name="controls_open_app" msgid="483650971094300141">"Buka aplikasi"</string> <string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuat status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Error, coba lagi"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Dalam proses"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 773bda713760..224164c012e5 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Færa efst til hægri"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Færa neðst til vinstri"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Færðu neðst til hægri"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hunsa"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ekki setja samtal í blöðru"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Spjalla með blöðrum"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Ný samtöl birtast sem fljótandi tákn eða blöðrur. Ýttu til að opna blöðru. Dragðu hana til að færa."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Strjúktu til að sjá meira"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Hleður tillögum"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Loka þessari efnislotu"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Halda áfram"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Óvirkt, athugaðu forrit"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Villa, reynir aftur…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Tæki fjarlægt"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Fannst ekki"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Stýring er ekki tiltæk"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Ekki tókst að tengjast <xliff:g id="DEVICE">%1$s</xliff:g>. Athugaðu <xliff:g id="APPLICATION">%2$s</xliff:g> forritið til að ganga úr skugga um að stýringin sé enn í boði og að stillingum forritsins hafi ekki verið breytt."</string> + <string name="controls_open_app" msgid="483650971094300141">"Opna forrit"</string> <string name="controls_error_generic" msgid="352500456918362905">"Ekki er hægt að hlaða stöðu"</string> <string name="controls_error_failed" msgid="960228639198558525">"Villa, reyndu aftur"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Í gangi"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 0844284ac7a4..f9fcda4b3eca 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -721,7 +721,7 @@ <string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta le funzionalità delle conversazioni"</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Nessuna bolla recente"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate verranno visualizzate qui"</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Le bolle recenti e ignorate appariranno qui"</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Impossibile modificare queste notifiche."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Qui non è possibile configurare questo gruppo di notifiche"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Notifica inviata al proxy"</string> @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sposta in alto a destra"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sposta in basso a sinistra"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sposta in basso a destra"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignora"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Non utilizzare bolle per la conversazione"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta utilizzando le bolle"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Le nuove conversazioni vengono visualizzate come icone mobili o bolle. Tocca per aprire la bolla. Trascinala per spostarla."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Scorri per vedere altro"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Caricamento dei consigli"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Chiudi questa sessione multimediale"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Riprendi"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inattivo, controlla l\'app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Errore. Nuovo tentativo…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo rimosso"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Controllo non trovato"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Il controllo non è disponibile"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Impossibile accedere a: <xliff:g id="DEVICE">%1$s</xliff:g>. Verifica nell\'app <xliff:g id="APPLICATION">%2$s</xliff:g> che il controllo sia ancora disponibile e che le impostazioni dell\'app non siano cambiate."</string> + <string name="controls_open_app" msgid="483650971094300141">"Apri app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Impossibile caricare lo stato"</string> <string name="controls_error_failed" msgid="960228639198558525">"Errore. Riprova"</string> <string name="controls_in_progress" msgid="4421080500238215939">"In corso"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index f23254abdc69..172919c497e3 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"העברה לפינה הימנית העליונה"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"העברה לפינה השמאלית התחתונה"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"העברה לפינה הימנית התחתונה"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"סגירה"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"אין להציג בועות לשיחה"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"לדבר בצ\'אט באמצעות בועות"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"שיחות חדשות מופיעות כסמלים צפים, או בועות. יש להקיש כדי לפתוח בועה. יש לגרור כדי להזיז אותה."</string> @@ -1023,17 +1024,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"הניווט במערכת עודכן. אפשר לערוך שינויים דרך ההגדרות."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"יש לעבור להגדרות כדי לעדכן את הניווט במערכת"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"המתנה"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"השיחה הוגדרה כבעלת עדיפות גבוהה"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"שיחות בעדיפות גבוהה:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"מופיעות בחלק העליון של קטע השיחות"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"מציגות תמונת פרופיל במסך הנעילה"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"מופיעות כבועה צפה מעל האפליקציות שלך"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"גוברות על ההגדרה \'נא לא להפריע\'"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"הבנתי"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"הגדרות"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"חלון ליצירת שכבת-על להגדלה"</string> <string name="magnification_window_title" msgid="4863914360847258333">"חלון הגדלה"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"בקרות של חלון ההגדלה"</string> @@ -1077,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"יש להחליק כדי להציג עוד פריטים"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"בטעינת המלצות"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"סגירת הסשן הזה של המדיה"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"המשך"</string> <string name="controls_error_timeout" msgid="794197289772728958">"לא פעיל, יש לבדוק את האפליקציה"</string> <string name="controls_error_retryable" msgid="864025882878378470">"שגיאה, מתבצע ניסיון חוזר…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"המכשיר הוסר"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"לא נמצא"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"הפקד לא זמין"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"לא ניתן להתחבר אל <xliff:g id="DEVICE">%1$s</xliff:g>. יש לבדוק את האפליקציה <xliff:g id="APPLICATION">%2$s</xliff:g> כדי לוודא שהפקד עדיין זמין ושהגדרות האפליקציה לא השתנו."</string> + <string name="controls_open_app" msgid="483650971094300141">"לפתיחת האפליקציה"</string> <string name="controls_error_generic" msgid="352500456918362905">"לא ניתן לטעון את הסטטוס"</string> <string name="controls_error_failed" msgid="960228639198558525">"שגיאה, יש לנסות שוב"</string> <string name="controls_in_progress" msgid="4421080500238215939">"בתהליך"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 6e7555a9d32c..a2bb39cd9e6b 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -1002,9 +1002,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"右上に移動"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"左下に移動"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"右下に移動"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"閉じる"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"会話をバブルで表示しない"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでのバブルの使用"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"チャットでバブルを使う"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"新しい会話はフローティング アイコン(バブル)として表示されます。タップするとバブルが開きます。ドラッグしてバブルを移動できます。"</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"いつでもバブルを管理"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"このアプリからのバブルをオフにするには、[管理] をタップしてください"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"スワイプすると他の構造が表示されます"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"候補を読み込んでいます"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"このメディア セッションを閉じる"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"再開"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無効: アプリをご確認ください"</string> <string name="controls_error_retryable" msgid="864025882878378470">"エラー。再試行しています…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"デバイスを削除しました"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"見つかりませんでした"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"コントロールを使用できません"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"「<xliff:g id="DEVICE">%1$s</xliff:g>」にアクセスできませんでした<xliff:g id="APPLICATION">%2$s</xliff:g> アプリで、コントロールが使用可能な状態でアプリの設定が変更されていないことをご確認ください。"</string> + <string name="controls_open_app" msgid="483650971094300141">"アプリを開く"</string> <string name="controls_error_generic" msgid="352500456918362905">"ステータスを読み込めません"</string> <string name="controls_error_failed" msgid="960228639198558525">"エラー: もう一度お試しください"</string> <string name="controls_in_progress" msgid="4421080500238215939">"処理中"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 4aea87bc4938..37b5ec98797e 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"გადაანაცვლეთ ზევით და მარჯვნივ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ქვევით და მარცხნივ გადატანა"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"გადაანაცვ. ქვემოთ და მარჯვნივ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"დახურვა"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"აიკრძალოს საუბრის ბუშტები"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ჩეთი ბუშტების გამოყენებით"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ახალი საუბრები გამოჩნდება როგორც მოტივტივე ხატულები ან ბუშტები. შეეხეთ ბუშტის გასახსნელად. გადაიტანეთ ჩავლებით."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"გადაფურცლეთ მეტის სანახავად"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"მიმდინარეობს რეკომენდაციების ჩატვირთვა"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ამ მედია სესიის დახურვა"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"გაგრძელება"</string> <string name="controls_error_timeout" msgid="794197289772728958">"არააქტიურია, გადაამოწმეთ აპი"</string> <string name="controls_error_retryable" msgid="864025882878378470">"შეცდომა, ხელახალი მცდელობა…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"მოწყობილობა ამოიშალა"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ვერ მოიძებნა"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"კონტროლი მიუწვდომელია"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-ზე წვდომა ვერ მოხერხდა. შეამოწმეთ <xliff:g id="APPLICATION">%2$s</xliff:g> აპი, რათა დარწმუნდეთ, რომ კონტროლი კვლავაც ხელმისაწვდომია და რომ აპის პარამეტრები არ შეცვლილა."</string> + <string name="controls_open_app" msgid="483650971094300141">"აპის გახსნა"</string> <string name="controls_error_generic" msgid="352500456918362905">"სტატუსი ვერ იტვირთება"</string> <string name="controls_error_failed" msgid="960228639198558525">"შეცდომა, ისევ ცადეთ"</string> <string name="controls_in_progress" msgid="4421080500238215939">"მუშავდება"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index bb4ee6b0916e..73f0e6c7af7d 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -274,7 +274,7 @@ <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"Ұшақ режимі өшірілді."</string> <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"Ұшақ режимі қосылды."</string> <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"үнсіз"</string> - <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"тек дабылдар"</string> + <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"оятқыштар ғана"</string> <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"Мазаламау."</string> <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\"Мазаламау\" режимі өшірілді."</string> <string name="accessibility_quick_settings_dnd_changed_on" msgid="186315911607486129">"\"Мазаламау\" режимі қосылды."</string> @@ -344,7 +344,7 @@ <string name="quick_settings_header_onboarding_text" msgid="1918085351115504765">"Басқа опцияларды көру үшін белгішелерді түртіп ұстап тұрыңыз"</string> <string name="quick_settings_dnd_label" msgid="7728690179108024338">"Мазаламау"</string> <string name="quick_settings_dnd_priority_label" msgid="6251076422352664571">"Маңыздылары ғана"</string> - <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Тек дабылдар"</string> + <string name="quick_settings_dnd_alarms_label" msgid="1241780970469630835">"Оятқыштар ғана"</string> <string name="quick_settings_dnd_none_label" msgid="8420869988472836354">"Толық тыныштық"</string> <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string> <string name="quick_settings_bluetooth_multiple_devices_label" msgid="6595808498429809855">"Bluetooth (<xliff:g id="NUMBER">%d</xliff:g> құрылғылары)"</string> @@ -462,7 +462,7 @@ <string name="interruption_level_none_with_warning" msgid="8394434073508145437">"Толық тыныштық. Экранды оқу құралдары да өшеді."</string> <string name="interruption_level_none" msgid="219484038314193379">"Толық тыныштық"</string> <string name="interruption_level_priority" msgid="661294280016622209">"Маңыздылары ғана"</string> - <string name="interruption_level_alarms" msgid="2457850481335846959">"Тек дабылдар"</string> + <string name="interruption_level_alarms" msgid="2457850481335846959">"Оятқыштар ғана"</string> <string name="interruption_level_none_twoline" msgid="8579382742855486372">"Толық\nтыныштық"</string> <string name="interruption_level_priority_twoline" msgid="8523482736582498083">"Тек\nбасымдық"</string> <string name="interruption_level_alarms_twoline" msgid="2045067991335708767">"Тек\nдабылдар"</string> @@ -721,7 +721,7 @@ <string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> әңгімелесу функцияларын қолдамайды."</string> <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"Жақындағы қалқыма хабарлар жоқ"</string> - <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Жақында ашылған және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string> + <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"Соңғы және жабылған қалқыма хабарлар осы жерде көрсетіледі."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"Бұл хабарландыруларды өзгерту мүмкін емес."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Мұндай хабарландырулар бұл жерде конфигурацияланбайды."</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Прокси-сервер арқылы жіберілген хабарландыру"</string> @@ -1002,9 +1002,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жоғары оң жаққа жылжыту"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төменгі сол жаққа жылжыту"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төменгі оң жаққа жылжыту"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабу"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Әңгіменің қалқыма хабары көрсетілмесін"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Сөйлесуге арналған қалқыма хабарлар"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Қалқыма хабарлар арқылы сөйлесу"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңа әңгімелер қалқыма белгішелер немесе хабарлар түрінде көрсетіледі. Қалқыма хабарды ашу үшін түртіңіз. Жылжыту үшін сүйреңіз."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Қалқыма хабарларды реттеу"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Бұл қолданбадан қалқыма хабарларды өшіру үшін \"Басқару\" түймесін түртіңіз."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Толығырақ ақпарат алу үшін сырғытыңыз."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Жүктеуге қатысты ұсыныстар"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Мультимедиа сеансын жабу"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Жалғастыру"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Өшірулі. Қолданба тексеріңіз."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Қате, әрекет қайталануда…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Құрылғы өшірілді."</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Табылмады"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Басқару элементтері қолжетімді емес"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ашылмады. Басқару элементтерінің әлі қолжетімді екенін және қолданба параметрлерінің өзгермегенін тексеру үшін <xliff:g id="APPLICATION">%2$s</xliff:g> қолданбасын қараңыз."</string> + <string name="controls_open_app" msgid="483650971094300141">"Қолданбаны ашу"</string> <string name="controls_error_generic" msgid="352500456918362905">"Күйді жүктеу мүмкін емес."</string> <string name="controls_error_failed" msgid="960228639198558525">"Қате шықты. Қайталап көріңіз."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Орындалуда"</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index c00549c71fb1..47fd544912ea 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ផ្លាស់ទីទៅផ្នែកខាងលើខាងស្ដាំ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងឆ្វេង"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ផ្លាស់ទីទៅផ្នែកខាងក្រោមខាងស្ដាំ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ច្រានចោល"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"កុំបង្ហាញការសន្ទនាជាពពុះ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ជជែកដោយប្រើពពុះ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ការសន្ទនាថ្មីៗបង្ហាញជាពពុះ ឬរូបអណ្ដែត។ ចុច ដើម្បីបើកពពុះ។ អូស ដើម្បីផ្លាស់ទីពពុះនេះ។"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"អូសដើម្បីមើលច្រើនទៀត"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"កំពុងផ្ទុកការណែនាំ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"បិទវគ្គមេឌៀនេះ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"បន្ត"</string> <string name="controls_error_timeout" msgid="794197289772728958">"អសកម្ម ពិនិត្យមើលកម្មវិធី"</string> <string name="controls_error_retryable" msgid="864025882878378470">"បញ្ហា កំពុងព្យាយាមម្ដងទៀត…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"បានលុបឧបករណ៍"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"រកមិនឃើញទេ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"មិនអាចគ្រប់គ្រងបានទេ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"មិនអាចចូលប្រើ <xliff:g id="DEVICE">%1$s</xliff:g> បានទេ។ សូមពិនិត្យមើលកម្មវិធី <xliff:g id="APPLICATION">%2$s</xliff:g> ដើម្បីប្រាកដថានៅតែអាចគ្រប់គ្រងបាន ហើយថាការកំណត់កម្មវិធីនេះមិនបានផ្លាស់ប្ដូរឡើយ។"</string> + <string name="controls_open_app" msgid="483650971094300141">"បើកកម្មវិធី"</string> <string name="controls_error_generic" msgid="352500456918362905">"មិនអាចផ្ទុកស្ថានភាពបានទេ"</string> <string name="controls_error_failed" msgid="960228639198558525">"មានបញ្ហា សូមព្យាយាមម្តងទៀត"</string> <string name="controls_in_progress" msgid="4421080500238215939">"កំពុងដំណើរការ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 7b707b5b61d9..afa60524fca6 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ಬಲ ಮೇಲ್ಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ಸ್ಕ್ರೀನ್ನ ಎಡ ಕೆಳಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ಕೆಳಗಿನ ಬಲಭಾಗಕ್ಕೆ ಸರಿಸಿ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ವಜಾಗೊಳಿಸಿ"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ಸಂಭಾಷಣೆಯನ್ನು ಬಬಲ್ ಮಾಡಬೇಡಿ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ಬಬಲ್ಸ್ ಬಳಸಿ ಚಾಟ್ ಮಾಡಿ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ಹೊಸ ಸಂಭಾಷಣೆಗಳು ತೇಲುವ ಐಕಾನ್ಗಳು ಅಥವಾ ಬಬಲ್ಸ್ ಆಗಿ ಗೋಚರಿಸುತ್ತವೆ. ಬಬಲ್ ತೆರೆಯಲು ಟ್ಯಾಪ್ ಮಾಡಿ. ಅದನ್ನು ಡ್ರ್ಯಾಗ್ ಮಾಡಲು ಎಳೆಯಿರಿ."</string> @@ -1013,17 +1014,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ ಅಪ್ಡೇಟ್ ಮಾಡಲಾಗಿದೆ ಬದಲಾವಣೆಗಳನ್ನು ಮಾಡಲು, ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ."</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"ಸಿಸ್ಟಂ ನ್ಯಾವಿಗೇಷನ್ ಅಪ್ಡೇಟ್ ಮಾಡಲು ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಹೋಗಿ"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"ಸ್ಟ್ಯಾಂಡ್ಬೈ"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"ಸಂವಾದವನ್ನು ಆದ್ಯತೆಯಾಗಿ ಹೊಂದಿಸಲಾಗಿದೆ"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ಆದ್ಯತೆಯ ಸಂವಾದಗಳು:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸಿ"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"ಲಾಕ್ ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ತೋರಿಸಿ"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ಆ್ಯಪ್ಗಳ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್ನಂತೆ ಗೋಚರಿಸಲಿ"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ಅಡಚಣೆ ಮಾಡಬೇಡ ಅನ್ನು ಅಡ್ಡಿಪಡಿಸಿ"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"ಅರ್ಥವಾಯಿತು"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"ವರ್ಧನೆಯ ಓವರ್ಲೇ ವಿಂಡೋ"</string> <string name="magnification_window_title" msgid="4863914360847258333">"ವರ್ಧನೆಯ ವಿಂಡೋ"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"ವರ್ಧನೆಯ ವಿಂಡೋ ನಿಯಂತ್ರಣಗಳು"</string> @@ -1065,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ಇನ್ನಷ್ಟು ನೋಡಲು ಸ್ವೈಪ್ ಮಾಡಿ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ಶಿಫಾರಸುಗಳು ಲೋಡ್ ಆಗುತ್ತಿವೆ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ಈ ಮಾಧ್ಯಮ ಸೆಶನ್ ಅನ್ನು ಮುಚ್ಚಿರಿ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ಪುನರಾರಂಭಿಸಿ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ನಿಷ್ಕ್ರಿಯ, ಆ್ಯಪ್ ಪರಿಶೀಲಿಸಿ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ದೋಷ, ಮರುಪ್ರಯತ್ನಿಸಲಾಗುತ್ತಿದೆ…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ಸಾಧನವನ್ನು ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ಕಂಡುಬಂದಿಲ್ಲ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ನಿಯಂತ್ರಣ ಲಭ್ಯವಿಲ್ಲ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಯಂತ್ರಣ ಈಗಲೂ ಲಭ್ಯವಿದೆಯೇ ಮತ್ತು <xliff:g id="APPLICATION">%2$s</xliff:g> ಆ್ಯಪ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬದಲಾಯಿಸಲಾಗಿಲ್ಲ ಎಂಬುದನ್ನು ಖಚಿತಪಡಿಸಿಕೊಳ್ಳಲು ಆ್ಯಪ್ ಅನ್ನು ಪರಿಶೀಲಿಸಿ."</string> + <string name="controls_open_app" msgid="483650971094300141">"ಆ್ಯಪ್ ತೆರೆಯಿರಿ"</string> <string name="controls_error_generic" msgid="352500456918362905">"ಸ್ಥಿತಿ ಲೋಡ್ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ"</string> <string name="controls_error_failed" msgid="960228639198558525">"ದೋಷ, ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ಪ್ರಗತಿಯಲ್ಲಿದೆ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 263c4dd56037..a75c230cd681 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -720,7 +720,7 @@ <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string> <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string> <string name="no_shortcut" msgid="8257177117568230126">"<xliff:g id="APP_NAME">%1$s</xliff:g> 앱은 대화 기능을 지원하지 않습니다."</string> - <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근에 닫은 대화창 없음"</string> + <string name="bubble_overflow_empty_title" msgid="3120029421991510842">"최근 대화창 없음"</string> <string name="bubble_overflow_empty_subtitle" msgid="2030874469510497397">"최근 대화창과 내가 닫은 대화창이 여기에 표시됩니다."</string> <string name="notification_unblockable_desc" msgid="2073030886006190804">"이 알림은 수정할 수 없습니다."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"이 알림 그룹은 여기에서 설정할 수 없습니다."</string> @@ -1002,9 +1002,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"오른쪽 상단으로 이동"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"왼쪽 하단으로 이동"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"오른쪽 하단으로 이동"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"닫기"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"대화를 대화창으로 표시하지 않음"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창을 사용하여 채팅하세요"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"대화창으로 채팅하기"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"새로운 대화가 플로팅 아이콘인 대화창으로 표시됩니다. 대화창을 열려면 탭하세요. 드래그하여 이동할 수 있습니다."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"언제든지 대화창을 제어하세요"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"이 앱에서 대화창을 사용 중지하려면 관리를 탭하세요."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"자세히 보려면 스와이프하세요."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"추천 제어 기능 로드 중"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"이 미디어 세션 닫기"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"다시 시작"</string> <string name="controls_error_timeout" msgid="794197289772728958">"비활성. 앱을 확인하세요."</string> <string name="controls_error_retryable" msgid="864025882878378470">"오류 발생, 다시 시도 중…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"기기가 삭제됨"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"찾을 수 없음"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"컨트롤을 사용할 수 없음"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>에 액세스할 수 없습니다. <xliff:g id="APPLICATION">%2$s</xliff:g> 앱에서 컨트롤을 계속 사용할 수 있는지와 앱 설정이 변경되지 않았는지 확인하세요."</string> + <string name="controls_open_app" msgid="483650971094300141">"앱 열기"</string> <string name="controls_error_generic" msgid="352500456918362905">"통계를 로드할 수 없음"</string> <string name="controls_error_failed" msgid="960228639198558525">"오류. 다시 시도하세요."</string> <string name="controls_in_progress" msgid="4421080500238215939">"진행 중"</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index dcd10cc566f7..a0f532acf9da 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Жогорку оң жакка жылдырыңыз"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Төмөнкү сол жакка жылдыруу"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Төмөнкү оң жакка жылдырыңыз"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Жабуу"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Жазышуу калкып чыкма билдирмеде көрүнбөсүн"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Калкып чыкма билдирмелер аркылуу маектешүү"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Жаңы жазышуулар калкыма сүрөтчөлөр же калкып чыкма билдирмелер болуп көрүнөт. Калкып чыкма билдирмелерди ачуу үчүн таптап коюңуз. Жылдыруу үчүн сүйрөңүз."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Дагы көрүү үчүн экранды сүрүп коюңуз"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Сунуштар жүктөлүүдө"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Бул медиа сеансын жабуу"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Улантуу"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Жигерсиз. Колдонмону текшериңиз"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Ката, дагы аракет жасалууда…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Түзмөктү көзөмөлдөө өчүрүлдү"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Табылган жок"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Көзөмөл жеткиликтүү эмес"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> түзмөгүнө кирүү мүмкүнчүлүгү жок. <xliff:g id="APPLICATION">%2$s</xliff:g> колдонмосуна өтүп, көзөмөл жеткиликтүү экенин жана колдонмонун жөндөөлөрү өзгөрбөгөнүн текшериңиз."</string> + <string name="controls_open_app" msgid="483650971094300141">"Колдонмону ачуу"</string> <string name="controls_error_generic" msgid="352500456918362905">"Абалы жүктөлгөн жок"</string> <string name="controls_error_failed" msgid="960228639198558525">"Ката, кайталап көрүңүз"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Аткарылууда"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index a7e9d8d3a810..829d39aac864 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ຍ້າຍຂວາເທິງ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ຍ້າຍຊ້າຍລຸ່ມ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ຍ້າຍຂວາລຸ່ມ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ປິດໄວ້"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ຢ່າໃຊ້ຟອງໃນການສົນທະນາ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ສົນທະນາໂດຍໃຊ້ຟອງ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ການສົນທະນາໃໝ່ຈະປາກົດເປັນໄອຄອນ ຫຼື ຟອງແບບລອຍ. ແຕະເພື່ອເປີດຟອງ. ລາກເພື່ອຍ້າຍມັນ."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ປັດເພື່ອເບິ່ງເພີ່ມເຕີມ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ກຳລັງໂຫຼດຄຳແນະນຳ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ປິດເຊດຊັນມີເດຍນີ້"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ສືບຕໍ່"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ບໍ່ເຮັດວຽກ, ກະລຸນາກວດສອບແອັບ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ຜິດພາດ, ກໍາລັງລອງໃໝ່…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ລຶບອຸປະກອນອອກແລ້ວ"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ບໍ່ພົບ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ບໍ່ສາມາດໃຊ້ການຄວບຄຸມໄດ້"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"ບໍ່ສາມາດເຂົ້າເຖິງ <xliff:g id="DEVICE">%1$s</xliff:g> ໄດ້. ກະລຸນາກວດສອບແອັບ <xliff:g id="APPLICATION">%2$s</xliff:g> ເພື່ອເບິ່ງວ່າຍັງສາມາດໃຊ້ການຄວບຄຸມໄດ້ຫຼືບໍ່ ແລະ ຍັງບໍ່ໄດ້ປ່ຽນການຕັ້ງຄ່າແອັບເທື່ອ."</string> + <string name="controls_open_app" msgid="483650971094300141">"ເປີດແອັບ"</string> <string name="controls_error_generic" msgid="352500456918362905">"ບໍ່ສາມາດໂຫຼດສະຖານະໄດ້"</string> <string name="controls_error_failed" msgid="960228639198558525">"ຜິດພາດ, ກະລຸນາລອງໃໝ່"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ກຳລັງດຳເນີນການຢູ່"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index a0903193dd83..de793947a037 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Perkelti į viršų dešinėje"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Perkelti į apačią kairėje"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Perkelti į apačią dešinėje"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Atmesti"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerodyti pokalbio burbule"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Pokalbis naudojant burbulus"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nauji pokalbiai rodomi kaip slankiosios piktogramos arba burbulus. Palieskite, kad atidarytumėte burbulą. Vilkite, kad perkeltumėte."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Perbraukite, kad peržiūrėtumėte daugiau"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Įkeliamos rekomendacijos"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Uždaryti šį medijos seansą"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Tęsti"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktyvu, patikrinkite progr."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Klaida, bandoma iš naujo…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Įrenginys pašalintas"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nerasta"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Valdiklis nepasiekiamas"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepavyko pasiekti: <xliff:g id="DEVICE">%1$s</xliff:g>. Eikite į programą „<xliff:g id="APPLICATION">%2$s</xliff:g>“ ir įsitikinkite, kad valdiklis vis dar pasiekiamas ir kad programos nustatymai nepakeisti."</string> + <string name="controls_open_app" msgid="483650971094300141">"Atidaryti programą"</string> <string name="controls_error_generic" msgid="352500456918362905">"Nepavyko įkelti būsenos"</string> <string name="controls_error_failed" msgid="960228639198558525">"Klaida, bandykite dar kartą"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Vyksta"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index f107de9c14c6..ba6b8954f655 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -1007,7 +1007,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Pārvietot augšpusē pa labi"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Pārvietot apakšpusē pa kreisi"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Pārvietot apakšpusē pa labi"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Nerādīt"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nerādīt sarunu burbuļos"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Tērzēšana, izmantojot burbuļus"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Jaunas sarunas tiek rādītas kā peldošas ikonas vai burbuļi. Pieskarieties, lai atvērtu burbuli. Velciet, lai to pārvietotu."</string> @@ -1068,9 +1069,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Velciet, lai skatītu citus vienumus"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Notiek ieteikumu ielāde"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Aizvērt multivides sesiju"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Atsākt"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktīva, pārbaudiet lietotni"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Radās kļūda. Mēģina vēlreiz…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Ierīce ir noņemta."</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Netika atrasta"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Vadīkla nav pieejama"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nevarēja piekļūt ierīcei “<xliff:g id="DEVICE">%1$s</xliff:g>”. Lietotnē <xliff:g id="APPLICATION">%2$s</xliff:g> pārbaudiet, vai vadīkla joprojām ir pieejama un vai nav mainīti lietotnes iestatījumi."</string> + <string name="controls_open_app" msgid="483650971094300141">"Atvērt lietotni"</string> <string name="controls_error_generic" msgid="352500456918362905">"Nevar ielādēt statusu."</string> <string name="controls_error_failed" msgid="960228639198558525">"Radās kļūda. Mēģiniet vēlreiz."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Sākta"</string> diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml index 0361eed3c2de..522cebd8ea6c 100644 --- a/packages/SystemUI/res/values-mk/strings.xml +++ b/packages/SystemUI/res/values-mk/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести долу лево"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести долу десно"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Отфрли"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не прикажувај го разговорот во балончиња"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Разговор во балончиња"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новите разговори ќе се појавуваат како лебдечки икони или балончиња. Допрете за отворање на балончето. Повлечете за да го преместите."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Повлечете за да видите повеќе"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Се вчитуваат препораки"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Затвори ја аудиовизуелнава сесија"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Продолжи"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивна, провери апликација"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Грешка, повторен обид…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Уредот е отстранет"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Не е најдено"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Контролата не е достапна"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Не може да се пристапи до <xliff:g id="DEVICE">%1$s</xliff:g>. Проверете ја апликацијата <xliff:g id="APPLICATION">%2$s</xliff:g> за да се осигурите дека контролата е сè уште достапна и дека поставките за апликацијата не се сменети."</string> + <string name="controls_open_app" msgid="483650971094300141">"Отвори ја апликација"</string> <string name="controls_error_generic" msgid="352500456918362905">"Не може да се вчита статусот"</string> <string name="controls_error_failed" msgid="960228639198558525">"Грешка, обидете се повторно"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Во тек"</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index 5c80eb32a9b8..03e826f54e45 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"മുകളിൽ വലതുഭാഗത്തേക്ക് നീക്കുക"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ചുവടെ ഇടതുഭാഗത്തേക്ക് നീക്കുക"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ചുവടെ വലതുഭാഗത്തേക്ക് നീക്കുക"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ഡിസ്മിസ് ചെയ്യുക"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"സംഭാഷണം ബബിൾ ചെയ്യരുത്"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ബബിളുകൾ ഉപയോഗിച്ച് ചാറ്റ് ചെയ്യുക"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"പുതിയ സംഭാഷണങ്ങൾ ഫ്ലോട്ടിംഗ് ഐക്കണുകളോ ബബിളുകളോ ആയി ദൃശ്യമാവുന്നു. ബബിൾ തുറക്കാൻ ടാപ്പ് ചെയ്യു. ഇത് നീക്കാൻ വലിച്ചിടുക."</string> @@ -1065,9 +1066,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"കൂടുതൽ കാണാൻ സ്വൈപ്പ് ചെയ്യുക"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"നിർദ്ദേശങ്ങൾ ലോഡ് ചെയ്യുന്നു"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ഈ മീഡിയ സെഷൻ അടയ്ക്കുക"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"പുനരാരംഭിക്കുക"</string> <string name="controls_error_timeout" msgid="794197289772728958">"നിഷ്ക്രിയം, ആപ്പ് പരിശോധിക്കൂ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"പിശക്, വീണ്ടും ശ്രമിക്കുന്നു…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ഉപകരണം നീക്കം ചെയ്തു"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"കണ്ടെത്തിയില്ല"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"നിയന്ത്രണം ലഭ്യമല്ല"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ആക്സസ് ചെയ്യാനായില്ല. നിയന്ത്രണം ഇപ്പോഴും ലഭ്യമാണെന്നും ആപ്പ് ക്രമീകരണം മാറ്റിയിട്ടില്ലെന്നും ഉറപ്പാക്കാൻ <xliff:g id="APPLICATION">%2$s</xliff:g> ആപ്പ് പരിശോധിക്കുക."</string> + <string name="controls_open_app" msgid="483650971094300141">"ആപ്പ് തുറക്കുക"</string> <string name="controls_error_generic" msgid="352500456918362905">"നില ലോഡ് ചെയ്യാനാകുന്നില്ല"</string> <string name="controls_error_failed" msgid="960228639198558525">"പിശക്, വീണ്ടും ശ്രമിക്കുക"</string> <string name="controls_in_progress" msgid="4421080500238215939">"പുരോഗതിയിലാണ്"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index f04df527dfe5..9a15e98fa763 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Баруун дээш зөөх"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Зүүн доош зөөх"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Баруун доош зөөх"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Үл хэрэгсэх"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Харилцан яриаг бүү бөмбөлөг болго"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Бөмбөлөг ашиглан чатлаарай"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Шинэ харилцан яриа нь хөвөгч дүрс тэмдэг эсвэл бөмбөлөг хэлбэрээр харагддаг. Бөмбөлгийг нээхийн тулд товшино уу. Түүнийг зөөхийн тулд чирнэ үү."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Илүү ихийг харахын тулд шударна уу"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Зөвлөмжүүдийг ачаалж байна"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Медианы энэ харилцан үйлдлийг хаах"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Үргэлжлүүлэх"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Идэвхгүй байна, аппыг шалгана уу"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Алдаа, дахин оролдож байна…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Төхөөрөмжийг хассан"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Олдсонгүй"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Хяналт боломжгүй байна"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>-д хандаж чадсангүй. Хяналт боломжтой хэвээр байгаа бөгөөд аппын тохиргоог өөрчлөөгүй эсэхийг нягтлахын тулд <xliff:g id="APPLICATION">%2$s</xliff:g> аппыг шалгана уу."</string> + <string name="controls_open_app" msgid="483650971094300141">"Аппыг нээх"</string> <string name="controls_error_generic" msgid="352500456918362905">"Статус ачаалах боломжгүй"</string> <string name="controls_error_failed" msgid="960228639198558525">"Алдаа гарав, дахин оролдоно уу"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Үргэлжилж байна"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 8994141167e3..cbc50b90e300 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"वर उजवीकडे हलवा"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"तळाशी डावीकडे हलवा"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"तळाशी उजवीकडे हलवा"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"डिसमिस करा"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"संभाषणाला बबल करू नका"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबल वापरून चॅट करा"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"नवीन संभाषणे फ्लोटिंग आयकन किंवा बबल म्हणून दिसतात. बबल उघडण्यासाठी टॅप करा. हे हलवण्यासाठी ड्रॅग करा."</string> @@ -1065,9 +1066,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"अधिक पाहण्यासाठी स्वाइप करा"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"शिफारशी लोड करत आहे"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"हे मीडिया सेशन बंद करा"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"पुन्हा सुरू करा"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय, ॲप तपासा"</string> <string name="controls_error_retryable" msgid="864025882878378470">"एरर, पुन्हा प्रयत्न करत आहे…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"डिव्हाइस काढून टाकले आहे"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"आढळले नाही"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"नियंत्रण उपलब्ध नाही"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> अॅक्सेस करता आले नाही. नियंत्रण अजूनही उपलब्ध असल्याची आणि ॲपची सेटिंग्ज बदलली नसल्याची खात्री करण्यासाठी <xliff:g id="APPLICATION">%2$s</xliff:g> ॲप तपासा."</string> + <string name="controls_open_app" msgid="483650971094300141">"अॅप उघडा"</string> <string name="controls_error_generic" msgid="352500456918362905">"स्थिती लोड करू शकत नाही"</string> <string name="controls_error_failed" msgid="960228639198558525">"एरर, पुन्हा प्रयत्न करा"</string> <string name="controls_in_progress" msgid="4421080500238215939">"प्रगतीपथावर आहे"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index a251c3d8b9c8..f89d5a0a4d4a 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Alihkan ke atas sebelah kanan"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Alihkan ke bawah sebelah kiri"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Alihkan ke bawah sebelah kanan"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ketepikan"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Jangan jadikan perbualan dalam bentuk gelembung"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bersembang menggunakan gelembung"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Perbualan baharu muncul sebagai ikon terapung atau gelembung. Ketik untuk membuka gelembung. Seret untuk mengalihkan gelembung tersebut."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Leret untuk melihat selanjutnya"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Memuatkan cadangan"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Tutup sesi media ini"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Sambung semula"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Tidak aktif, semak apl"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Ralat, mencuba semula…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Peranti dialih keluar"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Tidak ditemui"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kawalan tidak tersedia"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Tidak dapat mengakses <xliff:g id="DEVICE">%1$s</xliff:g>. Periksa apl <xliff:g id="APPLICATION">%2$s</xliff:g> untuk memastikan kawalan masih tersedia dan tetapan apl tidak berubah."</string> + <string name="controls_open_app" msgid="483650971094300141">"Buka apl"</string> <string name="controls_error_generic" msgid="352500456918362905">"Tidak dapat memuatkan status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Ralat, cuba lagi"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Sedang berlangsung"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index 810388db843c..dc70e80a7125 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ညာဘက်ထိပ်သို့ ရွှေ့ပါ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ဘယ်အောက်ခြေသို့ ရွှေ့ရန်"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ညာအောက်ခြေသို့ ရွှေ့ပါ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ပယ်ရန်"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"စကားဝိုင်းကို ပူဖောင်းကွက် မပြုလုပ်ပါနှင့်"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ပူဖောင်းကွက် သုံး၍ ချတ်လုပ်ခြင်း"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"စကားဝိုင်းအသစ်များကို မျောနေသည့် သင်္ကေတများ သို့မဟုတ် ပူဖောင်းကွက်များအဖြစ် မြင်ရပါမည်။ ပူဖောင်းကွက်ကိုဖွင့်ရန် တို့ပါ။ ရွှေ့ရန် ၎င်းကို ဖိဆွဲပါ။"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ပိုမိုကြည့်ရှုရန် ပွတ်ဆွဲပါ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"အကြံပြုချက်များ ဖွင့်နေသည်"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ဤမီဒီယာစက်ရှင်ကို ပိတ်ပါ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ဆက်လုပ်ရန်"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ရပ်နေသည်၊ အက်ပ်ကို စစ်ဆေးပါ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"မှားသွားသည်၊ ပြန်စမ်းနေသည်…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"စက်ကို ဖယ်ရှားထားသည်"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"မတွေ့ပါ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ထိန်းချုပ်၍ မရတော့ပါ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> အသုံးပြု၍ မရပါ။ ထိန်းချုပ်၍ ရသေးကြောင်းနှင့် အက်ပ်ဆက်တင်များ ပြောင်းမထားကြောင်း သေချာစေရန် <xliff:g id="APPLICATION">%2$s</xliff:g> အက်ပ်ကို စစ်ဆေးပါ။"</string> + <string name="controls_open_app" msgid="483650971094300141">"အက်ပ်ဖွင့်ရန်"</string> <string name="controls_error_generic" msgid="352500456918362905">"အခြေအနေကို ဖွင့်၍မရပါ"</string> <string name="controls_error_failed" msgid="960228639198558525">"မှားသွားသည်၊ ပြန်စမ်းကြည့်ပါ"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ဆောင်ရွက်နေသည်"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index b208cf2c63e6..53806a7e4daa 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -1002,10 +1002,11 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytt til øverst til høyre"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytt til nederst til venstre"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytt til nederst til høyre"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Avvis"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ikke vis samtaler i bobler"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chat med bobler"</string> - <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner, eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string> + <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nye samtaler vises som flytende ikoner eller bobler. Trykk for å åpne bobler. Dra for å flytte dem."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Kontrollér bobler når som helst"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Trykk på Administrer for å slå av bobler for denne appen"</string> <string name="bubbles_user_education_got_it" msgid="8282812431953161143">"Greit"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Sveip for å se flere"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Laster inn anbefalinger"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Lukk denne medieøkten"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Gjenoppta"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv. Sjekk appen"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Feil. Prøver igjen …"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Enheten er fjernet"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ikke funnet"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrollen er utilgjengelig"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Fikk ikke tilgang til <xliff:g id="DEVICE">%1$s</xliff:g>. Sjekk <xliff:g id="APPLICATION">%2$s</xliff:g>-appen for å sjekke at kontrollen fremdeles er tilgjengelig, og at appinnstillingene ikke er endret."</string> + <string name="controls_open_app" msgid="483650971094300141">"Åpne appen"</string> <string name="controls_error_generic" msgid="352500456918362905">"Kan ikke laste inn status"</string> <string name="controls_error_failed" msgid="960228639198558525">"En feil oppsto. Prøv på nytt"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index abfb4c870825..19cf233fa092 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"सिरानमा दायाँतिर सार्नुहोस्"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"पुछारमा बायाँतिर सार्नुहोस्"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"पुछारमा दायाँतिर सार्नुहोस्"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"हटाउनुहोस्"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"वार्तालाप बबलको रूपमा नदेखाइयोस्"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"बबलहरू प्रयोग गरी कुराकानी गर्नुहोस्"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"नयाँ वार्तालापहरू तैरने आइकन वा बबलका रूपमा देखिन्छन्। बबल खोल्न ट्याप गर्नुहोस्। बबल सार्न सो बबललाई ड्र्याग गर्नुहोस्।"</string> @@ -1065,9 +1066,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"थप हेर्न स्वाइप गर्नुहोस्"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"सिफारिसहरू लोड गर्दै"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"यो मिडिया सत्र बन्द गर्नुहोस्"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"सुचारु गर्नुहोस्"</string> <string name="controls_error_timeout" msgid="794197289772728958">"निष्क्रिय छ, एप जाँच गर्नु…"</string> <string name="controls_error_retryable" msgid="864025882878378470">"त्रुटि भयो, फेरि प्रयास गर्दै…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"यन्त्र हटाइयो"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"फेला परेन"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"नियन्त्रण सुविधा उपलब्ध छैन"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> माथि पहुँच राख्न सकिएन। यो नियन्त्रण सुविधा अझै पनि उपलब्ध छ र <xliff:g id="APPLICATION">%2$s</xliff:g> एपका सेटिङ परिवर्तन गरिएका छैनन् भन्ने कुरा सुनिश्चित गर्न यो एप जाँच्नुहोस्।"</string> + <string name="controls_open_app" msgid="483650971094300141">"एप खोल्नुहोस्"</string> <string name="controls_error_generic" msgid="352500456918362905">"वस्तुस्थिति लोड गर्न सकिएन"</string> <string name="controls_error_failed" msgid="960228639198558525">"त्रुटि भयो, फेरि प्रयास गर्नु…"</string> <string name="controls_in_progress" msgid="4421080500238215939">"कार्य हुँदै छ"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index f578c2dcbb6f..21e66ab67cd8 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Naar rechtsboven verplaatsen"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Naar linksonder verplaatsen"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Naar rechtsonder verplaatsen"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Sluiten"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Gesprekken niet in bubbels weergeven"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatten met bubbels"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nieuwe gesprekken worden weergegeven als zwevende iconen of \'bubbels\'. Tik om een bubbel te openen. Sleep om de bubbel te verplaatsen."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swipe om meer te zien"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Aanbevelingen laden"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Deze mediasessie sluiten"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Hervatten"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactief, check de app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Fout. Opnieuw proberen…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Apparaat verwijderd"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Niet gevonden"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Beheeroptie niet beschikbaar"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Kan geen toegang krijgen tot <xliff:g id="DEVICE">%1$s</xliff:g>. Check de <xliff:g id="APPLICATION">%2$s</xliff:g>-app om na te gaan of de beheeroptie nog steeds beschikbaar is en of de app-instellingen niet zijn gewijzigd."</string> + <string name="controls_open_app" msgid="483650971094300141">"App openen"</string> <string name="controls_error_generic" msgid="352500456918362905">"Kan status niet laden"</string> <string name="controls_error_failed" msgid="960228639198558525">"Fout, probeer het opnieuw"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Bezig"</string> diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml index 27a04dda60b5..f575f9868427 100644 --- a/packages/SystemUI/res/values-or/strings.xml +++ b/packages/SystemUI/res/values-or/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ଉପର-ଡାହାଣକୁ ନିଅନ୍ତୁ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ତଳ ବାମକୁ ନିଅନ୍ତୁ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ତଳ ଡାହାଣକୁ ନିଅନ୍ତୁ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ଖାରଜ କରନ୍ତୁ"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ବାର୍ତ୍ତାଳାପକୁ ବବଲ୍ କରନ୍ତୁ ନାହିଁ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ବବଲଗୁଡ଼ିକୁ ବ୍ୟବହାର କରି ଚାଟ୍ କରନ୍ତୁ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ନୂଆ ବାର୍ତ୍ତାଳାପଗୁଡ଼ିକ ଫ୍ଲୋଟିଂ ଆଇକନ୍ କିମ୍ବା ବବଲ୍ ଭାବେ ଦେଖାଯିବ। ବବଲ୍ ଖୋଲିବାକୁ ଟାପ୍ କରନ୍ତୁ। ଏହାକୁ ମୁଭ୍ କରିବାକୁ ଟାଣନ୍ତୁ।"</string> @@ -1065,9 +1066,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ଅଧିକ ଦେଖିବାକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ସୁପାରିଶଗୁଡ଼ିକ ଲୋଡ୍ କରାଯାଉଛି"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ଏହି ମିଡିଆ ସେସନ୍ ବନ୍ଦ କରନ୍ତୁ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ପୁଣି ଆରମ୍ଭ କରନ୍ତୁ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ନିଷ୍କ୍ରିୟ ଅଛି, ଆପ ଯାଞ୍ଚ କରନ୍ତୁ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ତ୍ରୁଟି, ପୁଣି ଚେଷ୍ଟା କରୁଛି…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ଡିଭାଇସ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ମିଳୁ ନାହିଁ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ନିୟନ୍ତ୍ରଣ ଉପଲବ୍ଧ ନାହିଁ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>କୁ ଆକ୍ସେସ୍ କରିହେଲା ନାହିଁ। ନିୟନ୍ତ୍ରଣ ଏବେ ବି ଉପଲବ୍ଧ ଅଛି ଏବଂ ଆପ୍ ସେଟିଂସ୍ ବଦଳାଯାଇ ନାହିଁ ବୋଲି ସୁନିଶ୍ଚିତ କରିବାକୁ <xliff:g id="APPLICATION">%2$s</xliff:g> ଆପ୍ ଯାଞ୍ଚ କରନ୍ତୁ।"</string> + <string name="controls_open_app" msgid="483650971094300141">"ଆପ୍ ଖୋଲନ୍ତୁ"</string> <string name="controls_error_generic" msgid="352500456918362905">"ସ୍ଥିତି ଲୋଡ୍ କରାଯାଇପାରିବ ନାହିଁ"</string> <string name="controls_error_failed" msgid="960228639198558525">"ତ୍ରୁଟି ହୋଇଛି, ପୁଣି ଚେଷ୍ଟା କର"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ପ୍ରଗତିରେ ଅଛି"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index b8bf05b96b2d..3389a18c8f9c 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -273,7 +273,7 @@ <string name="accessibility_quick_settings_airplane_on" msgid="8106176561295294255">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ।"</string> <string name="accessibility_quick_settings_airplane_changed_off" msgid="8880183481476943754">"ਏਅਰਪਲੇਨ ਮੋਡ ਬੰਦ ਹੈ।"</string> <string name="accessibility_quick_settings_airplane_changed_on" msgid="6327378061894076288">"ਏਅਰਪਲੇਨ ਮੋਡ ਚਾਲੂ ਹੋਇਆ"</string> - <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਸੰਪੂਰਨ ਖਾਮੋਸ਼ੀ"</string> + <string name="accessibility_quick_settings_dnd_none_on" msgid="3235552940146035383">"ਪੂਰਾ ਸ਼ਾਂਤ"</string> <string name="accessibility_quick_settings_dnd_alarms_on" msgid="3375848309132140014">"ਸਿਰਫ਼ ਅਲਾਰਮ"</string> <string name="accessibility_quick_settings_dnd" msgid="2415967452264206047">"ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ।"</string> <string name="accessibility_quick_settings_dnd_changed_off" msgid="1457150026842505799">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਨੂੰ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string> @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ਉੱਪਰ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ਹੇਠਾਂ ਵੱਲ ਖੱਬੇ ਲਿਜਾਓ"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ਹੇਠਾਂ ਵੱਲ ਸੱਜੇ ਲਿਜਾਓ"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ਖਾਰਜ ਕਰੋ"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ਗੱਲਬਾਤ \'ਤੇ ਬਬਲ ਨਾ ਲਾਓ"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"ਬਬਲ ਵਰਤਦੇ ਹੋਏ ਚੈਟ ਕਰੋ"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"ਨਵੀਆਂ ਗੱਲਾਂਬਾਤਾਂ ਫਲੋਟਿੰਗ ਪ੍ਰਤੀਕਾਂ ਜਾਂ ਬਬਲ ਦੇ ਰੂਪ ਵਿੱਚ ਦਿਸਦੀਆਂ ਹਨ। ਬਬਲ ਨੂੰ ਖੋਲ੍ਹਣ ਲਈ ਟੈਪ ਕਰੋ। ਇਸਨੂੰ ਲਿਜਾਣ ਲਈ ਘਸੀਟੋ।"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"ਹੋਰ ਦੇਖਣ ਲਈ ਸਵਾਈਪ ਕਰੋ"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"ਸਿਫ਼ਾਰਸ਼ਾਂ ਲੋਡ ਹੋ ਰਹੀਆਂ ਹਨ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ਇਸ ਮੀਡੀਆ ਸੈਸ਼ਨ ਨੂੰ ਬੰਦ ਕਰੋ"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"ਮੁੜ-ਚਾਲੂ ਕਰੋ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ਅਕਿਰਿਆਸ਼ੀਲ, ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ"</string> <string name="controls_error_retryable" msgid="864025882878378470">"ਗੜਬੜ, ਮੁੜ ਕੋਸ਼ਿਸ਼ ਹੋ ਰਹੀ ਹੈ…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"ਡੀਵਾਈਸ ਹਟਾਇਆ ਗਿਆ"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ਨਹੀਂ ਮਿਲਿਆ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ਕੰਟਰੋਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ਤੱਕ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ। ਇਹ ਪੱਕਾ ਕਰਨ ਲਈ <xliff:g id="APPLICATION">%2$s</xliff:g> ਐਪ ਦੀ ਜਾਂਚ ਕਰੋ ਕਿ ਕੰਟਰੋਲ ਹਾਲੇ ਵੀ ਉਪਲਬਧ ਹੈ ਅਤੇ ਐਪ ਸੈਟਿੰਗ ਬਦਲੀ ਨਹੀਂ ਹੈ।"</string> + <string name="controls_open_app" msgid="483650971094300141">"ਐਪ ਖੋਲ੍ਹੋ"</string> <string name="controls_error_generic" msgid="352500456918362905">"ਸਥਿਤੀ ਲੋਡ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕਦੀ"</string> <string name="controls_error_failed" msgid="960228639198558525">"ਗੜਬੜ, ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ਜਾਰੀ ਹੈ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index 8b56f8d259fd..e85b76f228ac 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Przenieś w prawy górny róg"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Przenieś w lewy dolny róg"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Przenieś w prawy dolny róg"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zamknij"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nie wyświetlaj rozmowy jako dymku"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Czatuj, korzystając z dymków"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nowe rozmowy będą wyświetlane jako pływające ikony lub dymki. Kliknij, by otworzyć dymek. Przeciągnij, by go przenieść."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Przesuń palcem, by zobaczyć więcej"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Wczytuję rekomendacje"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zamknij tę sesję multimediów"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Wznów"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nieaktywny, sprawdź aplikację"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Błąd, próbuję jeszcze raz…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Usunięto urządzenie"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nie znaleziono"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Element jest niedostępny"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nie udało się połączyć z urządzeniem: <xliff:g id="DEVICE">%1$s</xliff:g>. Sprawdź aplikację <xliff:g id="APPLICATION">%2$s</xliff:g>, aby upewnić się, że element sterujący jest wciąż dostępny i ustawienia aplikacji się nie zmieniły."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otwórz aplikację"</string> <string name="controls_error_generic" msgid="352500456918362905">"Nie udało się wczytać stanu"</string> <string name="controls_error_failed" msgid="960228639198558525">"Błąd, spróbuj ponownie"</string> <string name="controls_in_progress" msgid="4421080500238215939">"W toku"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index 5a2005ef1b5f..2259c305022e 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index dec586ef5d29..d90b8b2eeb13 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover parte superior direita"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover p/ parte infer. esquerda"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover parte inferior direita"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ignorar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não apresentar a conversa em balões"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse no chat através de balões"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"As novas conversas aparecem como ícones flutuantes ou balões. Toque para abrir o balão. Arraste para o mover."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize rapidamente para ver mais."</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"A carregar recomendações…"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Fechar esta sessão multimédia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativa. Consulte a app."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erro. A tentar novamente…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido."</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado."</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"O controlo está indisponível"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível aceder a <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique a app <xliff:g id="APPLICATION">%2$s</xliff:g> para se certificar de que o controlo ainda está disponível e que as definições da mesma não foram alteradas."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Impossível carregar o estado."</string> <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Em curso"</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index 5a2005ef1b5f..2259c305022e 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mover para canto superior direito"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mover para canto inferior esquerdo"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mover para canto inferior direito"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Dispensar"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Não criar balões de conversa"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Converse usando balões"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novas conversas aparecerão como ícones flutuantes, ou balões. Toque para abrir o balão. Arraste para movê-lo."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Deslize para ver mais"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Carregando recomendações"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Encerrar esta sessão de mídia"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Retomar"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inativo, verifique o app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Erro. Tentando novamente…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispositivo removido"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Não encontrado"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"O controle está indisponível"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Não foi possível acessar <xliff:g id="DEVICE">%1$s</xliff:g>. Verifique o app <xliff:g id="APPLICATION">%2$s</xliff:g> para garantir que o controle ainda esteja disponível e as configurações não tenham sido modificadas."</string> + <string name="controls_open_app" msgid="483650971094300141">"Abrir app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Falha ao carregar o status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Erro. Tente novamente"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Em andamento"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index ee844d0b1a59..c90c04c666b1 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -1007,7 +1007,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Mutați în dreapta sus"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Mutați în stânga jos"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Mutați în dreapta jos"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Închideți"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nu afișați conversația în balon"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Discutați pe chat folosind baloanele"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Conversațiile noi apar ca pictograme flotante sau baloane. Atingeți pentru a deschide balonul. Trageți pentru a-l muta."</string> @@ -1068,9 +1069,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Glisați pentru a vedea mai multe"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Se încarcă recomandările"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Închideți această sesiune media"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Reia"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inactiv, verificați aplicația"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Eroare, se încearcă din nou…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Dispozitivul a fost eliminat"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nu s-a găsit"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Comanda este indisponibilă"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nu s-a putut accesa <xliff:g id="DEVICE">%1$s</xliff:g>. Accesați aplicația <xliff:g id="APPLICATION">%2$s</xliff:g> pentru a vă asigura de disponibilitatea comenzii și că setările aplicației nu s-au schimbat."</string> + <string name="controls_open_app" msgid="483650971094300141">"Deschideți aplicația"</string> <string name="controls_error_generic" msgid="352500456918362905">"Starea nu se poate încărca"</string> <string name="controls_error_failed" msgid="960228639198558525">"Eroare, încercați din nou"</string> <string name="controls_in_progress" msgid="4421080500238215939">"În curs"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index 902d948815e5..35f4b745830a 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перенести в правый верхний угол"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перенести в левый нижний угол"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перенести в правый нижний угол"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрыть"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показывать всплывающие чаты для разговоров"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Всплывающие чаты для разговоров"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Новые разговоры будут появляться в виде плавающих значков, или всплывающих чатов. Чтобы открыть чат, нажмите на него, а чтобы переместить – перетащите."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Проведите по экрану, чтобы увидеть больше"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Загрузка рекомендаций…"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Закрыть этот мультимедийный сеанс"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Возобновить"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Нет ответа. Проверьте приложение."</string> <string name="controls_error_retryable" msgid="864025882878378470">"Ошибка. Повторная попытка…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Устройство удалено."</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Не найдено."</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Управление недоступно"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Нет доступа к устройству (<xliff:g id="DEVICE">%1$s</xliff:g>). Проверьте, доступно ли управление в приложении \"<xliff:g id="APPLICATION">%2$s</xliff:g>\" и не изменились ли настройки этого приложения."</string> + <string name="controls_open_app" msgid="483650971094300141">"Открыть приложение"</string> <string name="controls_error_generic" msgid="352500456918362905">"Не удалось загрузить статус."</string> <string name="controls_error_failed" msgid="960228639198558525">"Ошибка. Повторите попытку."</string> <string name="controls_in_progress" msgid="4421080500238215939">"Выполняется"</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index c49843cac397..be88cbafe59b 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ඉහළ දකුණට ගෙන යන්න"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"පහළ වමට ගෙන යන්න"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"පහළ දකුණට ගෙන යන්න"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ඉවතලන්න"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"සංවාදය බුබුලු නොදමන්න"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"බුබුලු භාවිතයෙන් කතාබහ කරන්න"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"නව සංවාද පාවෙන අයිකන හෝ බුබුලු ලෙස දිස් වේ. බුබුල විවෘත කිරීමට තට්ටු කරන්න. එය ගෙන යාමට අදින්න."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"තව බැලීමට ස්වයිප් කරන්න"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"නිර්දේශ පූරණය කරමින්"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"මෙම මාධ්ය සැසිය වසන්න"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"නැවත පටන් ගන්න"</string> <string name="controls_error_timeout" msgid="794197289772728958">"අක්රියයි, යෙදුම පරීක්ෂා කරන්න"</string> <string name="controls_error_retryable" msgid="864025882878378470">"දෝෂයකි, නැවත උත්සාහ කරමින්…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"උපාංගය ඉවත් කර ඇත"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"හමු නොවිණි"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"පාලනය ලබා ගත නොහැකිය"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> වෙත ප්රවේශ විය නොහැකි විය. පාලනය තිබෙන බව සහ යෙදුම් සැකසීම් වෙනස් වී ඇති බව සහතික කර ගැනීමට <xliff:g id="APPLICATION">%2$s</xliff:g> යෙදුම පරීක්ෂා කරන්න."</string> + <string name="controls_open_app" msgid="483650971094300141">"යෙදුම විවෘත කරන්න"</string> <string name="controls_error_generic" msgid="352500456918362905">"තත්ත්වය පූරණය කළ නොහැකිය"</string> <string name="controls_error_failed" msgid="960228639198558525">"දෝෂයකි, නැවත උත්සාහ කරන්න"</string> <string name="controls_in_progress" msgid="4421080500238215939">"ප්රගතියේ පවතී"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index 920fdd13be90..e0ba13dbfd98 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Presunúť doprava nahor"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Presunúť doľava nadol"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Presunúť doprava nadol"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Zavrieť"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Nezobrazovať konverzáciu ako bublinu"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Čet pomocou bublín"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nové konverzácie sa zobrazujú ako plávajúce ikony či bubliny. Bublinu otvoríte klepnutím. Premiestnite ju presunutím."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Potiahnutím zobrazíte ďalšie položky"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Načítavajú sa odporúčania"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zavrieť túto reláciu média"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Pokračovať"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktívne, preverte aplikáciu"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Chyba, skúša sa znova…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Zariadenie je odstránené"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nenájdené"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Ovládanie nie je k dispozícii"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nepodarilo sa získať prístup k zariadeniu <xliff:g id="DEVICE">%1$s</xliff:g>. V aplikácii <xliff:g id="APPLICATION">%2$s</xliff:g> skontrolujte, či je ovládanie stále k dispozícii a či sa nezmenili nastavenia."</string> + <string name="controls_open_app" msgid="483650971094300141">"Otvoriť aplikáciu"</string> <string name="controls_error_generic" msgid="352500456918362905">"Stav sa nepodarilo načítať"</string> <string name="controls_error_failed" msgid="960228639198558525">"Chyba, skúste to znova"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Prebieha"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 0b6d3a77281c..7066e8dc1612 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -1012,7 +1012,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Premakni zgoraj desno"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Premakni spodaj levo"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Premakni spodaj desno"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Opusti"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Pogovora ne prikaži v oblačku"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Klepet z oblački"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Novi pogovori so prikazani kot lebdeče ikone ali oblački. Če želite odpreti oblaček, se ga dotaknite. Če ga želite premakniti, ga povlecite."</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Če si želite ogledati več, povlecite"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nalaganje priporočil"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Zapri to sejo predstavnosti"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Nadaljuj"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Neaktivno, poglejte aplikacijo"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Napaka, vnovični poskus …"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Naprava je bila odstranjena"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ni mogoče najti"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolnik ni na voljo"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Ni bilo mogoče dostopiti do: <xliff:g id="DEVICE">%1$s</xliff:g>. Preverite aplikacijo <xliff:g id="APPLICATION">%2$s</xliff:g> in se prepričajte, da je kontrolnik še vedno na voljo ter da se nastavitve aplikacije niso spremenile."</string> + <string name="controls_open_app" msgid="483650971094300141">"Odpri aplikacijo"</string> <string name="controls_error_generic" msgid="352500456918362905">"Stanja ni mogoče naložiti"</string> <string name="controls_error_failed" msgid="960228639198558525">"Napaka, poskusite znova"</string> <string name="controls_in_progress" msgid="4421080500238215939">"V teku"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index a5147505ce5d..a23a85bf97fa 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Lëviz lart djathtas"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Zhvendos poshtë majtas"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Lëvize poshtë djathtas"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Hiq"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Mos e vendos bisedën në flluskë"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bisedo duke përdorur flluskat"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Bisedat e reja shfaqen si ikona pluskuese ose flluska. Trokit për të hapur flluskën. Zvarrit për ta zhvendosur."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Rrëshqit shpejt për të shikuar më shumë"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Po ngarkon rekomandimet"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Mbyll këtë sesion të medias"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Vazhdo"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Joaktive, kontrollo aplikacionin"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Gabim, po provohet përsëri"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Pajisja u hoq"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Nuk u gjet"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrolli është i padisponueshëm"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Nuk mundi të qasej te <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollo aplikacionin <xliff:g id="APPLICATION">%2$s</xliff:g> për t\'u siguruar që kontrolli të jetë ende i disponueshëm dhe që cilësimet e aplikacionit të mos kenë ndryshuar."</string> + <string name="controls_open_app" msgid="483650971094300141">"Hap aplikacionin"</string> <string name="controls_error_generic" msgid="352500456918362905">"Statusi nuk mund të ngarkohet"</string> <string name="controls_error_failed" msgid="960228639198558525">"Gabim, provo sërish"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Në vazhdim"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index 7855ec197f20..fde6413e4b97 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -1007,9 +1007,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Премести горе десно"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Премести доле лево"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Премести доле десно"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Одбаци"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не користи облачиће за конверзацију"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте помоћу облачића"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Ћаскајте у облачићима"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нове конверзације се приказују као плутајуће иконе или облачићи. Додирните да бисте отворили облачић. Превуците да бисте га преместили."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Контролишите облачиће у било ком тренутку"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Додирните Управљајте да бисте искључили облачиће из ове апликације"</string> @@ -1068,9 +1069,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Превуците да бисте видели још"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Учитавају се препоруке"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Затворите ову сесију медија"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Настави"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно. Видите апликацију"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Грешка, покушава се поново…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Уређај је уклоњен"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Није пронађено"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Контрола није доступна"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Приступање уређају <xliff:g id="DEVICE">%1$s</xliff:g> није успело. Погледајте апликацију <xliff:g id="APPLICATION">%2$s</xliff:g> да бисте се уверили да је контрола још увек доступна и да се подешавања апликације нису променила."</string> + <string name="controls_open_app" msgid="483650971094300141">"Отвори апликацију"</string> <string name="controls_error_generic" msgid="352500456918362905">"Учитавање статуса није успело"</string> <string name="controls_error_failed" msgid="960228639198558525">"Грешка. Пробајте поново"</string> <string name="controls_in_progress" msgid="4421080500238215939">"У току"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index e6fb28e22385..af3839bc8e8b 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Flytta högst upp till höger"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Flytta längst ned till vänster"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Flytta längst ned till höger"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Stäng"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Visa inte konversationen i bubblor"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Chatta med bubblor"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Nya konversationer visas som flytande ikoner, så kallade bubblor. Tryck på bubblan om du vill öppna den. Dra den om du vill flytta den."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Svep om du vill se mer"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Rekommendationer läses in"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Stäng den här sessionen"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Återuppta"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Inaktiv, kolla appen"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Fel, försöker igen …"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Enheten har tagits bort"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Hittades inte"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Styrning är inte tillgänglig"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Det gick inte att komma åt <xliff:g id="DEVICE">%1$s</xliff:g>. Kontrollera att enheten fortfarande är tillgänglig för styrning och att appinställningarna inte har ändrats i <xliff:g id="APPLICATION">%2$s</xliff:g>-appen."</string> + <string name="controls_open_app" msgid="483650971094300141">"Öppna appen"</string> <string name="controls_error_generic" msgid="352500456918362905">"Ingen status lästes in"</string> <string name="controls_error_failed" msgid="960228639198558525">"Fel, försök igen"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Pågår"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index c7962f91e1e9..f5ec81bf8fec 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sogeza juu kulia"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sogeza chini kushoto"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sogeza chini kulia"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Ondoa"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Usiweke viputo kwenye mazungumzo"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Piga gumzo ukitumia viputo"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Mazungumzo mapya huonekena kama aikoni au viputo vinavyoelea. Gusa ili ufungue kiputo. Buruta ili ukisogeze."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Telezesha kidole ili uone zaidi"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Inapakia mapendekezo"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Funga kipindi hiki cha maudhui"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Endelea"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Haitumiki, angalia programu"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Hitilafu, inajaribu tena…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Kifaa kimeondolewa"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Hakipatikani"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kidhibiti hakipatikani"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Imeshindwa kufikia <xliff:g id="DEVICE">%1$s</xliff:g>. Angalia programu ya <xliff:g id="APPLICATION">%2$s</xliff:g> ili uhakikishe kuwa bado kidhibiti kipo na kuwa mipangilio ya programu haijabadilika."</string> + <string name="controls_open_app" msgid="483650971094300141">"Fungua programu"</string> <string name="controls_error_generic" msgid="352500456918362905">"Imeshindwa kupakia hali"</string> <string name="controls_error_failed" msgid="960228639198558525">"Hitilafu, jaribu tena"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Inaendelea"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index edd8bde78cb6..4a32ecf8d229 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"மேலே வலப்புறமாக நகர்த்து"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"கீழே இடப்புறமாக நகர்த்து"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"கீழே வலதுபுறமாக நகர்த்து"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"மூடுக"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"உரையாடலைக் குமிழாக்காதே"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"குமிழ்களைப் பயன்படுத்தி அரட்டையடியுங்கள்"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"புதிய உரையாடல்கள் மிதக்கும் ஐகான்களாகவோ குமிழ்களாகவோ தோன்றும். குமிழைத் திறக்க தட்டவும். நகர்த்த இழுக்கவும்."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"மேலும் பார்க்க ஸ்வைப் செய்யவும்"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"பரிந்துரைகளை ஏற்றுகிறது"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"இந்த மீடியா அமர்வை மூடுக"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"தொடர்க"</string> <string name="controls_error_timeout" msgid="794197289772728958">"செயலில் இல்லை , சரிபார்க்கவும்"</string> <string name="controls_error_retryable" msgid="864025882878378470">"பிழை, மீண்டும் முயல்கிறது…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"சாதனம் அகற்றப்பட்டது"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"இல்லை"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"கட்டுப்பாடு இல்லை"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> சாதனத்தை அணுக இயலவில்லை. இப்போதும் கட்டுப்பாடு உள்ளது என்பதையும் ஆப்ஸ் அமைப்புகள் மாறவில்லை என்பதையும் உறுதிப்படுத்த <xliff:g id="APPLICATION">%2$s</xliff:g> ஆப்ஸைப் பார்க்கவும்."</string> + <string name="controls_open_app" msgid="483650971094300141">"ஆப்ஸைத் திற"</string> <string name="controls_error_generic" msgid="352500456918362905">"நிலையைக் காட்ட முடியவில்லை"</string> <string name="controls_error_failed" msgid="960228639198558525">"பிழை, மீண்டும் முயலவும்"</string> <string name="controls_in_progress" msgid="4421080500238215939">"செயல்பாட்டிலுள்ளது"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index a08d0d487b6a..73754a20cccc 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ఎగువ కుడివైపునకు జరుపు"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"దిగువ ఎడమవైపునకు తరలించు"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"దిగవు కుడివైపునకు జరుపు"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"విస్మరించు"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"సంభాషణను బబుల్ చేయవద్దు"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"బబుల్స్ను ఉపయోగించి చాట్ చేయండి"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"కొత్త సంభాషణలు తేలియాడే చిహ్నాలుగా లేదా బబుల్స్ లాగా కనిపిస్తాయి. బబుల్ని తెరవడానికి నొక్కండి. తరలించడానికి లాగండి."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"మరిన్నింటిని చూడటం కోసం స్వైప్ చేయండి"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"సిఫార్సులు లోడ్ అవుతున్నాయి"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ఈ మీడియా సెషన్ని మూసివేయండి"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"కొనసాగించండి"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ఇన్యాక్టివ్, యాప్ చెక్ చేయండి"</string> <string name="controls_error_retryable" msgid="864025882878378470">"లోపం, మళ్లీ ప్రయత్నిస్తోంది..."</string> - <string name="controls_error_removed" msgid="6299213591234723805">"పరికరం తీసివేయబడింది"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"కనుగొనబడలేదు"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"కంట్రోల్ అందుబాటులో లేదు"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>ను యాక్సెస్ చేయడం సాధ్యపడలేదు. <xliff:g id="APPLICATION">%2$s</xliff:g> యాప్ను తనిఖీ చేసి, కంట్రోల్ ఇప్పటికీ అందుబాటులో ఉందని, యాప్ సెట్టింగ్లు మారలేదని నిర్ధారించుకోండి."</string> + <string name="controls_open_app" msgid="483650971094300141">"యాప్ను తెరువు"</string> <string name="controls_error_generic" msgid="352500456918362905">"స్థితిని లోడ్ చేయడం సాధ్యపడదు"</string> <string name="controls_error_failed" msgid="960228639198558525">"ఎర్రర్, మళ్లీ ప్రయత్నించండి"</string> <string name="controls_in_progress" msgid="4421080500238215939">"పురోగతిలో ఉంది"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 5638f2a51596..d61533d0be01 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"ย้ายไปด้านขวาบน"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"ย้ายไปด้านซ้ายล่าง"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"ย้ายไปด้านขาวล่าง"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"ปิด"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"ไม่ต้องแสดงการสนทนาเป็นบับเบิล"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"แชทโดยใช้บับเบิล"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"การสนทนาใหม่ๆ จะปรากฏเป็นไอคอนแบบลอยหรือบับเบิล แตะเพื่อเปิดบับเบิล ลากเพื่อย้ายที่"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"เลื่อนเพื่อดูเพิ่มเติม"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"กำลังโหลดคำแนะนำ"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"ปิดเซสชันสื่อนี้"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"เล่นต่อ"</string> <string name="controls_error_timeout" msgid="794197289772728958">"ไม่มีการใช้งาน โปรดตรวจสอบแอป"</string> <string name="controls_error_retryable" msgid="864025882878378470">"มีข้อผิดพลาด กำลังลองอีกครั้ง…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"นำอุปกรณ์ออกแล้ว"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"ไม่พบ"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"ใช้การควบคุมไม่ได้"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"เข้าถึง <xliff:g id="DEVICE">%1$s</xliff:g> ไม่ได้ ตรวจสอบแอป <xliff:g id="APPLICATION">%2$s</xliff:g> ให้แน่ใจว่ายังใช้การควบคุมได้และการตั้งค่าของแอปไม่เปลี่ยนแปลง"</string> + <string name="controls_open_app" msgid="483650971094300141">"เปิดแอป"</string> <string name="controls_error_generic" msgid="352500456918362905">"โหลดสถานะไม่ได้"</string> <string name="controls_error_failed" msgid="960228639198558525">"พบข้อผิดพลาด โปรดลองอีกครั้ง"</string> <string name="controls_in_progress" msgid="4421080500238215939">"กำลังดำเนินการ"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index b9b379c5833a..041214f2111e 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Ilipat sa kanan sa itaas"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Ilipat sa kaliwa sa ibaba"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Ilipat sa kanan sa ibaba"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"I-dismiss"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Huwag ipakita sa bubble ang mga pag-uusap"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Makipag-chat gamit ang mga bubble"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Lumalabas bilang mga nakalutang na icon o bubble ang mga bagong pag-uusap. I-tap para buksan ang bubble. I-drag para ilipat ito."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Mag-swipe para tumingin ng higit pa"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Nilo-load ang rekomendasyon"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Isara ang session ng media na ito"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Ituloy"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Hindi aktibo, tingnan ang app"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Nagka-error, sinusubukan ulit…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Inalis ang device"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Hindi nahanap"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Hindi available ang kontrol"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Hindi ma-access ang <xliff:g id="DEVICE">%1$s</xliff:g>. Tingnan ang <xliff:g id="APPLICATION">%2$s</xliff:g> app para matiyak na available pa rin ang kontrol at hindi nabago ang mga setting ng app."</string> + <string name="controls_open_app" msgid="483650971094300141">"Buksan ang app"</string> <string name="controls_error_generic" msgid="352500456918362905">"Hindi ma-load ang status"</string> <string name="controls_error_failed" msgid="960228639198558525">"Nagka-error, subukan ulit"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Isinasagawa"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index 48268e7aa888..e4892cf934a3 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Sağ üste taşı"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Sol alta taşı"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Sağ alta taşı"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Kapat"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Görüşmeyi baloncuk olarak görüntüleme"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Baloncukları kullanarak sohbet edin"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yeni görüşmeler kayan simgeler veya baloncuk olarak görünür. Açmak için baloncuğa dokunun. Baloncuğu taşımak için sürükleyin."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Diğer öğeleri görmek için hızlıca kaydırın"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Öneriler yükleniyor"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Bu medya oturumunu kapat"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Devam ettir"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Devre dışı, uygulamaya bakın"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Hata, yeniden deneniyor…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Cihaz kaldırıldı"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Bulunamadı"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Kontrol kullanılamıyor"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> cihazına erişilemedi Kontrolün hâlâ kullanılabilir olduğundan ve uygulama ayarlarının değişmediğinden emin olmak için <xliff:g id="APPLICATION">%2$s</xliff:g> uygulamasını kontrol edin."</string> + <string name="controls_open_app" msgid="483650971094300141">"Uygulama aç"</string> <string name="controls_error_generic" msgid="352500456918362905">"Durum yüklenemiyor"</string> <string name="controls_error_failed" msgid="960228639198558525">"Hata, yeniden deneyin"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Devam ediyor"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 38a478cfb85d..4c39f43a8845 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -1012,9 +1012,10 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Перемістити праворуч угору"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Перемістити ліворуч униз"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Перемістити праворуч униз"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Закрити"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Не показувати спливаючі чати для розмов"</string> - <string name="bubbles_user_education_title" msgid="5547017089271445797">"Чат зі спливаючими сповіщеннями"</string> + <string name="bubbles_user_education_title" msgid="5547017089271445797">"Спливаючий чат"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Нові повідомлення чату з\'являються у вигляді спливаючих значків. Щоб відкрити чат, натисніть його, а щоб перемістити – перетягніть."</string> <string name="bubbles_user_education_manage_title" msgid="2848511858160342320">"Налаштовуйте спливаючі чати будь-коли"</string> <string name="bubbles_user_education_manage" msgid="1391639189507036423">"Натисніть \"Налаштувати\", щоб вимкнути спливаючі чати від цього додатка"</string> @@ -1074,9 +1075,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Гортайте, щоб переглянути інші"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Завантаження рекомендацій"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Закрити цей сеанс медіа"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Відновити"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Неактивно, перейдіть у додаток"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Помилка. Повторна спроба…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Пристрій вилучено"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Не знайдено"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Елемент керування недоступний"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g>: немає доступу. Перевірте в додатку <xliff:g id="APPLICATION">%2$s</xliff:g>, чи його налаштування не змінились і чи елемент керування доступний."</string> + <string name="controls_open_app" msgid="483650971094300141">"Відкрити додаток"</string> <string name="controls_error_generic" msgid="352500456918362905">"Не вдалося завантажити статус"</string> <string name="controls_error_failed" msgid="960228639198558525">"Помилка. Спробуйте знову"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Виконується"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index ac99a7ba21e6..feb894a56eb0 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"اوپر دائیں جانب لے جائيں"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"نیچے بائیں جانب لے جائیں"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"نیچے دائیں جانب لے جائیں"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"برخاست کریں"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"بلبلہ گفتگو نہ کریں"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"بلبلے کے ذریعے چیٹ کریں"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"نئی گفتگوئیں فلوٹنگ آئیکن یا بلبلے کے طور پر ظاہر ہوں گی۔ بلبلہ کھولنے کے لیے تھپتھپائیں۔ اسے منتقل کرنے کے لیے گھسیٹیں۔"</string> @@ -1013,17 +1014,14 @@ <string name="notification_content_system_nav_changed" msgid="5077913144844684544">"سسٹم نیویگیشن اپ ڈیٹ کیا گیا۔ تبدیلیاں کرنے کے لیے، ترتیبات پر جائیں۔"</string> <string name="notification_content_gesture_nav_available" msgid="4431460803004659888">"سسٹم نیویگیشن اپ ڈیٹ کرنے کے لیے ترتیبات پر جائیں"</string> <string name="inattentive_sleep_warning_title" msgid="3891371591713990373">"اسٹینڈ بائی"</string> - <!-- no translation found for priority_onboarding_title (2893070698479227616) --> - <skip /> - <!-- no translation found for priority_onboarding_behavior (5342816047020432929) --> - <skip /> + <string name="priority_onboarding_title" msgid="2893070698479227616">"گفتگو کو ترجیح پر سیٹ کیا گیا"</string> + <string name="priority_onboarding_behavior" msgid="5342816047020432929">"ترجیحی گفتگوئیں یہ ہوگی:"</string> <string name="priority_onboarding_show_at_top_text" msgid="1678400241025513541">"گفتگو کے سیکشن میں سب سے اوپر دکھائیں"</string> <string name="priority_onboarding_show_avatar_text" msgid="5756291381124091508">"مقفل سکرین پر پروفائل کی تصویر دکھائیں"</string> <string name="priority_onboarding_appear_as_bubble_text" msgid="4227039772250263122">"ایپس کے سب سے اوپر فلوٹنگ بلبلہ کے طور پر ظاہر ہوں"</string> <string name="priority_onboarding_ignores_dnd_text" msgid="2918952762719600529">"ڈسٹرب نہ کریں میں مداخلت کریں"</string> <string name="priority_onboarding_done_button_title" msgid="4569550984286506007">"سمجھ آ گئی"</string> - <!-- no translation found for priority_onboarding_settings_button_title (6663601574303585927) --> - <skip /> + <string name="priority_onboarding_settings_button_title" msgid="6663601574303585927">"ترتیبات"</string> <string name="magnification_overlay_title" msgid="6584179429612427958">"میگنیفیکیشن اوورلے ونڈو"</string> <string name="magnification_window_title" msgid="4863914360847258333">"میگنیفکیشن ونڈو"</string> <string name="magnification_controls_title" msgid="8421106606708891519">"میگنیفکیشن ونڈو کنٹرولز"</string> @@ -1065,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"مزید دیکھنے کیلئے سوائپ کریں"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"تجاویز لوڈ ہو رہی ہیں"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"اس میڈیا سیشن کو بند کریں"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"دوبارہ شروع کریں"</string> <string name="controls_error_timeout" msgid="794197289772728958">"غیر فعال، ایپ چیک کریں"</string> <string name="controls_error_retryable" msgid="864025882878378470">"خرابی، دوبارہ کوشش کی جا رہی ہے…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"آلہ ہٹا دیا گیا"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"نہیں ملا"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"کنٹرول دستیاب نہیں ہے"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> تک رسائی حاصل نہیں ہو سکی۔ اس بات کو یقینی بنانے کے لیے کہ کنٹرول ابھی بھی دستیاب ہے اور ایپ کی ترتیبات تبدیل نہیں ہوئی، تو <xliff:g id="APPLICATION">%2$s</xliff:g> ایپ چیک کریں۔"</string> + <string name="controls_open_app" msgid="483650971094300141">"ایپ کھولیں"</string> <string name="controls_error_generic" msgid="352500456918362905">"صورتحال لوڈ نہیں ہو سکتی"</string> <string name="controls_error_failed" msgid="960228639198558525">"خرابی، دوبارہ کوشش کریں"</string> <string name="controls_in_progress" msgid="4421080500238215939">"پیشرفت میں"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index 518f60c5cfec..1145fa7b92df 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -725,7 +725,7 @@ <string name="notification_unblockable_desc" msgid="2073030886006190804">"Bu bildirishnomalarni tahrirlash imkonsiz."</string> <string name="notification_multichannel_desc" msgid="7414593090056236179">"Ushbu bildirishnomalar guruhi bu yerda sozlanmaydi"</string> <string name="notification_delegate_header" msgid="1264510071031479920">"Ishonchli bildirishnoma"</string> - <string name="notification_channel_dialog_title" msgid="6856514143093200019">"<xliff:g id="APP_NAME">%1$s</xliff:g> ilovasining barcha bildirishnomalari"</string> + <string name="notification_channel_dialog_title" msgid="6856514143093200019">"Barcha <xliff:g id="APP_NAME">%1$s</xliff:g> bildirishnomalari"</string> <string name="see_more_title" msgid="7409317011708185729">"Yana"</string> <string name="appops_camera" msgid="5215967620896725715">"Bu ilova kameradan foydalanmoqda."</string> <string name="appops_microphone" msgid="8805468338613070149">"Bu ilova mikrofondan foydalanmoqda."</string> @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Yuqori oʻngga surish"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Quyi chapga surish"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Quyi oʻngga surish"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Yopish"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Suhbatlar bulutchalar shaklida chiqmasin"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Bulutchalar yordamida subhatlashish"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Yangi xabarlar qalqib chiquvchi belgilar yoki bulutchalar kabi chiqadi. Xabarni ochish uchun bildirishnoma ustiga bosing. Xabarni qayta joylash uchun bildirishnomani suring."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Batafsil axborot olish uchun suring"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Tavsiyalar yuklanmoqda"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Bu media seansni yopish"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Davom etish"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Nofaol. Ilovani tekshiring"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Xato, qayta urinilmoqda…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Qurilma olib tashlandi"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Topilmadi"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Boshqarish imkonsiz"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"<xliff:g id="DEVICE">%1$s</xliff:g> ochilmadi. <xliff:g id="APPLICATION">%2$s</xliff:g> ilovasining sozlamalari oʻzgarmaganini va hali ham boshqarishga ruxsat borligini tekshiring."</string> + <string name="controls_open_app" msgid="483650971094300141">"Ilovani ochish"</string> <string name="controls_error_generic" msgid="352500456918362905">"Holat axboroti yuklanmadi"</string> <string name="controls_error_failed" msgid="960228639198558525">"Xato, qayta urining"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Bajarilmoqda"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 00e0cf7a1136..8cd238c8529a 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Chuyển lên trên cùng bên phải"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Chuyển tới dưới cùng bên trái"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Chuyển tới dưới cùng bên phải"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Loại bỏ"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Dừng trò chuyện bằng bong bóng"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Trò chuyện bằng bong bóng trò chuyện"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Các cuộc trò chuyện mới hiển thị dưới dạng biểu tượng nổi hoặc bong bóng trò chuyện. Nhấn để mở bong bóng trò chuyện. Kéo để di chuyển bong bóng trò chuyện."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Vuốt để xem thêm"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Đang tải các đề xuất"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Đóng phiên đa phương tiện này"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Tiếp tục"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Không hoạt động, hãy kiểm tra ứng dụng"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Lỗi, đang thử lại…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Đã xóa thiết bị"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Không tìm thấy"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Không có chức năng điều khiển"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Không thể sử dụng <xliff:g id="DEVICE">%1$s</xliff:g>. Hãy kiểm tra ứng dụng <xliff:g id="APPLICATION">%2$s</xliff:g> để đảm bảo rằng vẫn chức năng điều khiển vẫn dùng được và thông tin cài đặt của ứng dụng chưa thay đổi."</string> + <string name="controls_open_app" msgid="483650971094300141">"Mở ứng dụng"</string> <string name="controls_error_generic" msgid="352500456918362905">"Không tải được trạng thái"</string> <string name="controls_error_failed" msgid="960228639198558525">"Lỗi, hãy thử lại"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Đang thực hiện"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 2664830bc71a..86f43c9d55f0 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上角"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下角"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下角"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"关闭"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不以对话泡形式显示对话"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用对话泡聊天"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"新对话会以浮动图标或对话泡形式显示。点按即可打开对话泡。拖动即可移动对话泡。"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑动可查看更多结构"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在加载推荐内容"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"关闭此媒体会话"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"继续播放"</string> <string name="controls_error_timeout" msgid="794197289772728958">"无效,请检查应用"</string> <string name="controls_error_retryable" msgid="864025882878378470">"出现错误,正在重试…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"设备已移除"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"未找到"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"控件不可用"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"无法访问<xliff:g id="DEVICE">%1$s</xliff:g>。请查看<xliff:g id="APPLICATION">%2$s</xliff:g>应用,确保其中仍有该控件,并且应用设置没有更改。"</string> + <string name="controls_open_app" msgid="483650971094300141">"打开应用"</string> <string name="controls_error_generic" msgid="352500456918362905">"无法加载状态"</string> <string name="controls_error_failed" msgid="960228639198558525">"出现错误,请重试"</string> <string name="controls_in_progress" msgid="4421080500238215939">"正在进行"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index 34b76904d8ef..6d9ee9913981 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移去右上角"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移去左下角"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移去右下角"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要透過小視窗顯示對話"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用小視窗進行即時通訊"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"新對話會以浮動圖示 (小視窗) 顯示。輕按即可開啟小視窗。拖曳即可移動小視窗。"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動以查看更多"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"關閉此媒體版面"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_error_timeout" msgid="794197289772728958">"已停用,請檢查應用程式"</string> <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"已移除裝置"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"找不到"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制功能"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取 <xliff:g id="DEVICE">%1$s</xliff:g>。請檢查 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確定控制功能仍可使用,同時應用程式設定並無變更。"</string> + <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string> <string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string> <string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string> <string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 5f3911a29178..11e2be069a2f 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"移至右上方"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"移至左下方"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"移至右下方"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"關閉"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"不要以對話框形式顯示對話"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"使用對話框進行即時通訊"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"新的對話會以浮動圖示或對話框形式顯示。輕觸即可開啟對話框,拖曳則可移動對話框。"</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"滑動即可查看其他結構"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"正在載入建議控制項"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"關閉這個媒體工作階段"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"繼續播放"</string> <string name="controls_error_timeout" msgid="794197289772728958">"無效,請查看應用程式"</string> <string name="controls_error_retryable" msgid="864025882878378470">"發生錯誤,正在重試…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"裝置已遭到移除"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"找不到控制項"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"無法使用控制項"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"無法存取「<xliff:g id="DEVICE">%1$s</xliff:g>」。請查看 <xliff:g id="APPLICATION">%2$s</xliff:g> 應用程式,確認當中是否仍有相關控制項,且應用程式設定沒有任何異動。"</string> + <string name="controls_open_app" msgid="483650971094300141">"開啟應用程式"</string> <string name="controls_error_generic" msgid="352500456918362905">"無法載入狀態"</string> <string name="controls_error_failed" msgid="960228639198558525">"發生錯誤,請再試一次"</string> <string name="controls_in_progress" msgid="4421080500238215939">"進行中"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 9b56c2039c44..358792161575 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -1002,7 +1002,8 @@ <string name="bubble_accessibility_action_move_top_right" msgid="6916868852433483569">"Hambisa phezulu ngakwesokudla"</string> <string name="bubble_accessibility_action_move_bottom_left" msgid="6339015902495504715">"Hambisa inkinobho ngakwesokunxele"</string> <string name="bubble_accessibility_action_move_bottom_right" msgid="7471571700628346212">"Hambisa inkinobho ngakwesokudla"</string> - <string name="bubble_dismiss_text" msgid="7071770411580452911">"Cashisa"</string> + <!-- no translation found for bubble_dismiss_text (1314082410868930066) --> + <skip /> <string name="bubbles_dont_bubble_conversation" msgid="1033040343437428822">"Ungayibhamuzi ingxoxo"</string> <string name="bubbles_user_education_title" msgid="5547017089271445797">"Xoxa usebenzisa amabhamuza"</string> <string name="bubbles_user_education_description" msgid="1160281719576715211">"Izingxoxo ezintsha zivela njengezithonjana ezintantayo, noma amabhamuza. Thepha ukuze uvule ibhamuza. Hudula ukuze ulihambise."</string> @@ -1062,9 +1063,13 @@ <string name="controls_structure_tooltip" msgid="4355922222944447867">"Swayipha ukuze ubone okuningi"</string> <string name="controls_seeding_in_progress" msgid="3033855341410264148">"Ilayisha izincomo"</string> <string name="controls_media_close_session" msgid="9023534788828414585">"Vala leseshini yemidiya"</string> + <string name="controls_media_resume" msgid="1933520684481586053">"Qalisa kabusha"</string> <string name="controls_error_timeout" msgid="794197289772728958">"Akusebenzi, hlola uhlelo lokusebenza"</string> <string name="controls_error_retryable" msgid="864025882878378470">"Iphutha, iyazama futhi…"</string> - <string name="controls_error_removed" msgid="6299213591234723805">"Idivayisi isusiwe"</string> + <string name="controls_error_removed" msgid="6675638069846014366">"Ayitholakali"</string> + <string name="controls_error_removed_title" msgid="1207794911208047818">"Ukulawula akutholakali"</string> + <string name="controls_error_removed_message" msgid="2885911717034750542">"Ayikwazanga ukufinyelela ku-<xliff:g id="DEVICE">%1$s</xliff:g>. Hlola uhlelo lokusebenza le-<xliff:g id="APPLICATION">%2$s</xliff:g> ukuqinisekisa ukuthi ukulawula kusatholakala nokuthi amasethingi wohlelo lokusebenza awakashintshi."</string> + <string name="controls_open_app" msgid="483650971094300141">"Vula uhlelo"</string> <string name="controls_error_generic" msgid="352500456918362905">"Ayikwazi ukulayisha isimo"</string> <string name="controls_error_failed" msgid="960228639198558525">"Iphutha, zama futhi"</string> <string name="controls_in_progress" msgid="4421080500238215939">"Iyaqhubeka"</string> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 820615a6098d..48ff5c681853 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -1256,7 +1256,7 @@ <string name="manage_notifications_history_text">History</string> <!-- Section title for notifications that have recently appeared. [CHAR LIMIT=40] --> - <string name="notification_section_header_incoming">Incoming</string> + <string name="notification_section_header_incoming">New</string> <!-- Section title for notifications that do not vibrate or make noise. [CHAR LIMIT=40] --> <string name="notification_section_header_gentle">Silent</string> diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java index 9d8c54501c02..f639c880c97a 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java @@ -141,14 +141,6 @@ public class KeyguardSliceView extends LinearLayout implements View.OnClickListe mLayoutTransition.setAnimateParentHierarchy(false); } - // Temporary workaround to allow KeyguardStatusView to inflate a copy for Universal Smartspace. - // Eventually the existing copy will be reparented instead, and we won't need this. - public KeyguardSliceView(Context context, AttributeSet attributeSet) { - this(context, attributeSet, Dependency.get(ActivityStarter.class), - Dependency.get(ConfigurationController.class), Dependency.get(TunerService.class), - context.getResources()); - } - @Override protected void onFinishInflate() { super.onFinishInflate(); diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java index a181ce4b000a..5a1c9976f021 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java @@ -18,10 +18,7 @@ package com.android.keyguard; import android.app.ActivityManager; import android.app.IActivityManager; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.res.Resources; import android.graphics.Color; import android.os.Handler; @@ -43,8 +40,6 @@ import androidx.core.graphics.ColorUtils; import com.android.internal.widget.LockPatternUtils; import com.android.systemui.Dependency; import com.android.systemui.R; -import com.android.systemui.shared.system.SurfaceViewRequestReceiver; -import com.android.systemui.shared.system.UniversalSmartspaceUtils; import com.android.systemui.statusbar.policy.ConfigurationController; import java.io.FileDescriptor; @@ -127,21 +122,6 @@ public class KeyguardStatusView extends GridLayout implements } }; - private final BroadcastReceiver mUniversalSmartspaceBroadcastReceiver = - new BroadcastReceiver() { - private final SurfaceViewRequestReceiver mReceiver = new SurfaceViewRequestReceiver(); - - @Override - public void onReceive(Context context, Intent i) { - // TODO(b/148159743): Restrict to Pixel Launcher. - if (UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW.equals(i.getAction())) { - mReceiver.onReceive(context, - i.getBundleExtra(UniversalSmartspaceUtils.INTENT_BUNDLE_KEY), - inflate(mContext, R.layout.keyguard_status_area, null)); - } - } - }; - public KeyguardStatusView(Context context) { this(context, null, 0); } @@ -336,8 +316,6 @@ public class KeyguardStatusView extends GridLayout implements super.onAttachedToWindow(); Dependency.get(KeyguardUpdateMonitor.class).registerCallback(mInfoCallback); Dependency.get(ConfigurationController.class).addCallback(this); - getContext().registerReceiver(mUniversalSmartspaceBroadcastReceiver, - new IntentFilter(UniversalSmartspaceUtils.ACTION_REQUEST_SMARTSPACE_VIEW)); } @Override @@ -345,7 +323,6 @@ public class KeyguardStatusView extends GridLayout implements super.onDetachedFromWindow(); Dependency.get(KeyguardUpdateMonitor.class).removeCallback(mInfoCallback); Dependency.get(ConfigurationController.class).removeCallback(this); - getContext().unregisterReceiver(mUniversalSmartspaceBroadcastReceiver); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java index 1dd6409b8582..dbe5a77965be 100644 --- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java +++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java @@ -34,6 +34,7 @@ import android.view.KeyEvent; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.WindowManager; import android.view.animation.Interpolator; import android.widget.FrameLayout; @@ -632,6 +633,7 @@ public class AuthContainerView extends LinearLayout windowFlags, PixelFormat.TRANSLUCENT); lp.privateFlags |= WindowManager.LayoutParams.SYSTEM_FLAG_SHOW_FOR_ALL_USERS; + lp.setFitInsetsTypes(lp.getFitInsetsTypes() & ~WindowInsets.Type.ime()); lp.setTitle("BiometricPrompt"); lp.token = windowToken; return lp; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index 97a73043aa08..7f78ddf2cf1c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -303,10 +303,10 @@ class Bubble implements BubbleViewProvider { mDotPath = info.dotPath; if (mExpandedView != null) { - mExpandedView.update(/* bubble */ this); + mExpandedView.update(this /* bubble */); } if (mIconView != null) { - mIconView.setRenderedBubble(/* bubble */ this); + mIconView.setRenderedBubble(this /* bubble */); } } @@ -548,13 +548,13 @@ class Bubble implements BubbleViewProvider { } private boolean shouldSuppressNotification() { - if (mEntry == null) return false; + if (mEntry == null) return true; return mEntry.getBubbleMetadata() != null && mEntry.getBubbleMetadata().isNotificationSuppressed(); } boolean shouldAutoExpand() { - if (mEntry == null) return false; + if (mEntry == null) return mShouldAutoExpand; Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata(); return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand; } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index cf793f021a29..35cac4d9d63d 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -156,6 +156,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi private final ShadeController mShadeController; private final FloatingContentCoordinator mFloatingContentCoordinator; private final BubbleDataRepository mDataRepository; + private BubbleLogger mLogger = new BubbleLoggerImpl(); private BubbleData mBubbleData; private ScrimView mBubbleScrim; @@ -317,6 +318,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi BubbleDataRepository dataRepository, SysUiState sysUiState, INotificationManager notificationManager, + @Nullable IStatusBarService statusBarService, WindowManager windowManager) { dumpManager.registerDumpable(TAG, this); mContext = context; @@ -387,8 +389,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mSurfaceSynchronizer = synchronizer; mWindowManager = windowManager; - mBarService = IStatusBarService.Stub.asInterface( - ServiceManager.getService(Context.STATUS_BAR_SERVICE)); + mBarService = statusBarService == null + ? IStatusBarService.Stub.asInterface( + ServiceManager.getService(Context.STATUS_BAR_SERVICE)) + : statusBarService; mBubbleScrim = new ScrimView(mContext); @@ -617,7 +621,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (mStackView == null) { mStackView = new BubbleStackView( mContext, mBubbleData, mSurfaceSynchronizer, mFloatingContentCoordinator, - mSysUiState, mNotificationShadeWindowController, this::onAllBubblesAnimatedOut, + mSysUiState, this::onAllBubblesAnimatedOut, this::onImeVisibilityChanged); mStackView.addView(mBubbleScrim); if (mExpandListener != null) { @@ -894,9 +898,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } void promoteBubbleFromOverflow(Bubble bubble) { + mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK); bubble.setInflateSynchronously(mInflateSynchronously); - setIsBubble(bubble, /* isBubble */ true); - mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory); + bubble.setShouldAutoExpand(true); + bubble.markUpdatedAt(System.currentTimeMillis()); + setIsBubble(bubble, true /* isBubble */); } /** @@ -910,20 +916,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi Bubble bubble = mBubbleData.getBubbleInStackWithKey(key); if (bubble != null) { mBubbleData.setSelectedBubble(bubble); + mBubbleData.setExpanded(true); } else { bubble = mBubbleData.getOverflowBubbleWithKey(key); if (bubble != null) { - bubble.setShouldAutoExpand(true); promoteBubbleFromOverflow(bubble); } else if (entry.canBubble()) { // It can bubble but it's not -- it got aged out of the overflow before it // was dismissed or opened, make it a bubble again. - setIsBubble(entry, true); - updateBubble(entry, true /* suppressFlyout */, false /* showInShade */); + setIsBubble(entry, true /* isBubble */, true /* autoExpand */); } } - - mBubbleData.setExpanded(true); } /** @@ -967,13 +970,17 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } void updateBubble(NotificationEntry notif, boolean suppressFlyout, boolean showInShade) { - // Lazy init stack view when a bubble is created - ensureStackViewCreated(); // If this is an interruptive notif, mark that it's interrupted if (notif.getImportance() >= NotificationManager.IMPORTANCE_HIGH) { notif.setInterruption(); } - Bubble bubble = mBubbleData.getOrCreateBubble(notif); + Bubble bubble = mBubbleData.getOrCreateBubble(notif, null /* persistedBubble */); + inflateAndAdd(bubble, suppressFlyout, showInShade); + } + + void inflateAndAdd(Bubble bubble, boolean suppressFlyout, boolean showInShade) { + // Lazy init stack view when a bubble is created + ensureStackViewCreated(); bubble.setInflateSynchronously(mInflateSynchronously); bubble.inflate( b -> { @@ -1119,7 +1126,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) { + private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble, + final boolean autoExpand) { Objects.requireNonNull(entry); if (isBubble) { entry.getSbn().getNotification().flags |= FLAG_BUBBLE; @@ -1127,7 +1135,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi entry.getSbn().getNotification().flags &= ~FLAG_BUBBLE; } try { - mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, 0); + int flags = 0; + if (autoExpand) { + flags = Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + flags |= Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE; + } + mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, flags); } catch (RemoteException e) { // Bad things have happened } @@ -1141,13 +1154,15 @@ public class BubbleController implements ConfigurationController.ConfigurationLi b.disable(FLAG_BUBBLE); } if (b.getEntry() != null) { - setIsBubble(b.getEntry(), isBubble); + // Updating the entry to be a bubble will trigger our normal update flow + setIsBubble(b.getEntry(), isBubble, b.shouldAutoExpand()); } else { - try { - mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0); - } catch (RemoteException e) { - // Bad things have happened - } + // If we have no entry to update, it's a persisted bubble so + // we need to add it to the stack ourselves + Bubble bubble = mBubbleData.getOrCreateBubble(null, b /* persistedBubble */); + inflateAndAdd(bubble, bubble.shouldAutoExpand() /* suppressFlyout */, + !bubble.shouldAutoExpand() /* showInShade */); + } } @@ -1199,7 +1214,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } } else { - if (bubble.isBubble() && bubble.showInShade()) { + if (bubble.isBubble()) { setIsBubble(bubble, false /* isBubble */); } if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 996a5553b5b2..24d44d5cb291 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -115,7 +115,7 @@ public class BubbleData { /** Bubbles that aged out to overflow. */ private final List<Bubble> mOverflowBubbles; /** Bubbles that are being loaded but haven't been added to the stack just yet. */ - private final List<Bubble> mPendingBubbles; + private final HashMap<String, Bubble> mPendingBubbles; private Bubble mSelectedBubble; private boolean mShowingOverflow; private boolean mExpanded; @@ -151,7 +151,7 @@ public class BubbleData { mContext = context; mBubbles = new ArrayList<>(); mOverflowBubbles = new ArrayList<>(); - mPendingBubbles = new ArrayList<>(); + mPendingBubbles = new HashMap<>(); mStateChange = new Update(mBubbles, mOverflowBubbles); mMaxBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_rendered); mMaxOverflowBubbles = mContext.getResources().getInteger(R.integer.bubbles_max_overflow); @@ -203,62 +203,46 @@ public class BubbleData { dispatchPendingChanges(); } - public void promoteBubbleFromOverflow(Bubble bubble, BubbleStackView stack, - BubbleIconFactory factory) { - if (DEBUG_BUBBLE_DATA) { - Log.d(TAG, "promoteBubbleFromOverflow: " + bubble); - } - mLogger.log(bubble, BubbleLogger.Event.BUBBLE_OVERFLOW_REMOVE_BACK_TO_STACK); - moveOverflowBubbleToPending(bubble); - // Preserve new order for next repack, which sorts by last updated time. - bubble.inflate( - b -> { - b.setShouldAutoExpand(true); - b.markUpdatedAt(mTimeSource.currentTimeMillis()); - notificationEntryUpdated(bubble, false /* suppressFlyout */, - true /* showInShade */); - }, - mContext, stack, factory, false /* skipInflation */); - } - void setShowingOverflow(boolean showingOverflow) { mShowingOverflow = showingOverflow; } - private void moveOverflowBubbleToPending(Bubble b) { - mOverflowBubbles.remove(b); - mPendingBubbles.add(b); - } - /** * Constructs a new bubble or returns an existing one. Does not add new bubbles to * bubble data, must go through {@link #notificationEntryUpdated(Bubble, boolean, boolean)} * for that. + * + * @param entry The notification entry to use, only null if it's a bubble being promoted from + * the overflow that was persisted over reboot. + * @param persistedBubble The bubble to use, only non-null if it's a bubble being promoted from + * the overflow that was persisted over reboot. */ - Bubble getOrCreateBubble(NotificationEntry entry) { - String key = entry.getKey(); - Bubble bubble = getBubbleInStackWithKey(entry.getKey()); - if (bubble != null) { - bubble.setEntry(entry); - } else { - bubble = getOverflowBubbleWithKey(key); - if (bubble != null) { - moveOverflowBubbleToPending(bubble); - bubble.setEntry(entry); - return bubble; - } - // Check for it in pending - for (int i = 0; i < mPendingBubbles.size(); i++) { - Bubble b = mPendingBubbles.get(i); - if (b.getKey().equals(entry.getKey())) { - b.setEntry(entry); - return b; - } + Bubble getOrCreateBubble(NotificationEntry entry, Bubble persistedBubble) { + String key = entry != null ? entry.getKey() : persistedBubble.getKey(); + Bubble bubbleToReturn = getBubbleInStackWithKey(key); + + if (bubbleToReturn == null) { + bubbleToReturn = getOverflowBubbleWithKey(key); + if (bubbleToReturn != null) { + // Promoting from overflow + mOverflowBubbles.remove(bubbleToReturn); + } else if (mPendingBubbles.containsKey(key)) { + // Update while it was pending + bubbleToReturn = mPendingBubbles.get(key); + } else if (entry != null) { + // New bubble + bubbleToReturn = new Bubble(entry, mSuppressionListener); + } else { + // Persisted bubble being promoted + bubbleToReturn = persistedBubble; } - bubble = new Bubble(entry, mSuppressionListener); - mPendingBubbles.add(bubble); } - return bubble; + + if (entry != null) { + bubbleToReturn.setEntry(entry); + } + mPendingBubbles.put(key, bubbleToReturn); + return bubbleToReturn; } /** @@ -270,7 +254,7 @@ public class BubbleData { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "notificationEntryUpdated: " + bubble); } - mPendingBubbles.remove(bubble); // No longer pending once we're here + mPendingBubbles.remove(bubble.getKey()); // No longer pending once we're here Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey()); suppressFlyout |= bubble.getEntry() == null || !bubble.getEntry().getRanking().visuallyInterruptive(); @@ -408,10 +392,8 @@ public class BubbleData { Log.d(TAG, "doRemove: " + key); } // If it was pending remove it - for (int i = 0; i < mPendingBubbles.size(); i++) { - if (mPendingBubbles.get(i).getKey().equals(key)) { - mPendingBubbles.remove(mPendingBubbles.get(i)); - } + if (mPendingBubbles.containsKey(key)) { + mPendingBubbles.remove(key); } int indexToRemove = indexForKey(key); if (indexToRemove == -1) { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index c3dcc0b3038c..db7980251daf 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -490,7 +490,7 @@ public class BubbleExpandedView extends LinearLayout { if (DEBUG_BUBBLE_EXPANDED_VIEW) { Log.d(TAG, "update: bubble=" + (bubble != null ? bubble.getKey() : "null")); } - boolean isNew = mBubble == null; + boolean isNew = mBubble == null || didBackingContentChange(bubble); if (isNew || bubble != null && bubble.getKey().equals(mBubble.getKey())) { mBubble = bubble; mSettingsIcon.setContentDescription(getResources().getString( @@ -523,6 +523,12 @@ public class BubbleExpandedView extends LinearLayout { } } + private boolean didBackingContentChange(Bubble newBubble) { + boolean prevWasIntentBased = mBubble != null && mPendingIntent != null; + boolean newIsIntentBased = newBubble.getBubbleIntent() != null; + return prevWasIntentBased != newIsIntentBased; + } + /** * Lets activity view know it should be shown / populated with activity content. */ diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 95c8d08841df..ba563466ca4e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -79,7 +79,6 @@ import androidx.dynamicanimation.animation.SpringForce; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ContrastColorUtil; -import com.android.internal.widget.ViewClippingUtil; import com.android.systemui.Interpolators; import com.android.systemui.Prefs; import com.android.systemui.R; @@ -292,20 +291,6 @@ public class BubbleStackView extends FrameLayout private ViewTreeObserver.OnDrawListener mSystemGestureExcludeUpdater = this::updateSystemGestureExcludeRects; - private ViewClippingUtil.ClippingParameters mClippingParameters = - new ViewClippingUtil.ClippingParameters() { - - @Override - public boolean shouldFinish(View view) { - return false; - } - - @Override - public boolean isClippingEnablingAllowed(View view) { - return !mIsExpanded; - } - }; - /** Float property that 'drags' the flyout. */ private final FloatPropertyCompat mFlyoutCollapseProperty = new FloatPropertyCompat("FlyoutCollapseSpring") { @@ -348,8 +333,6 @@ public class BubbleStackView extends FrameLayout @NonNull private final SurfaceSynchronizer mSurfaceSynchronizer; - private final NotificationShadeWindowController mNotificationShadeWindowController; - /** * Callback to run when the IME visibility changes - BubbleController uses this to update the * Bubbles window focusability flags with the WindowManager. @@ -682,7 +665,6 @@ public class BubbleStackView extends FrameLayout @Nullable SurfaceSynchronizer synchronizer, FloatingContentCoordinator floatingContentCoordinator, SysUiState sysUiState, - NotificationShadeWindowController notificationShadeWindowController, Runnable allBubblesAnimatedOutAction, Consumer<Boolean> onImeVisibilityChanged) { super(context); @@ -691,7 +673,6 @@ public class BubbleStackView extends FrameLayout mInflater = LayoutInflater.from(context); mSysUiState = sysUiState; - mNotificationShadeWindowController = notificationShadeWindowController; Resources res = getResources(); mMaxBubbles = res.getInteger(R.integer.bubbles_max_rendered); @@ -1399,7 +1380,6 @@ public class BubbleStackView extends FrameLayout mBubbleContainer.addView(bubble.getIconView(), 0, new FrameLayout.LayoutParams(WRAP_CONTENT, WRAP_CONTENT)); - ViewClippingUtil.setClippingDeactivated(bubble.getIconView(), true, mClippingParameters); animateInFlyoutForBubble(bubble); requestUpdate(); logBubbleEvent(bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__POSTED); @@ -1802,7 +1782,7 @@ public class BubbleStackView extends FrameLayout public void subtractObscuredTouchableRegion(Region touchableRegion, View view) { // If the notification shade is expanded, or the manage menu is open, we shouldn't let the // ActivityView steal any touch events from any location. - if (mNotificationShadeWindowController.getPanelExpanded() || mShowingManage) { + if (!mIsExpanded || mShowingManage) { touchableRegion.setEmpty(); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java index fd1f879e7f4b..3ef20444cb52 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/animation/StackAnimationController.java @@ -1034,13 +1034,13 @@ public class StackAnimationController extends mMagnetizedStack.getFlingToTargetMinVelocity() /* default */); final float maxVelocity = Settings.Secure.getFloat(contentResolver, "bubble_dismiss_stick_max_velocity", - mMagnetizedStack.getStickToTargetMaxVelocity() /* default */); + mMagnetizedStack.getStickToTargetMaxXVelocity() /* default */); final float targetWidth = Settings.Secure.getFloat(contentResolver, "bubble_dismiss_target_width_percent", mMagnetizedStack.getFlingToTargetWidthPercent() /* default */); mMagnetizedStack.setFlingToTargetMinVelocity(minVelocity); - mMagnetizedStack.setStickToTargetMaxVelocity(maxVelocity); + mMagnetizedStack.setStickToTargetMaxXVelocity(maxVelocity); mMagnetizedStack.setFlingToTargetWidthPercent(targetWidth); return mMagnetizedStack; diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java index d1d07f6ba4ce..097932e5f447 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/dagger/BubbleModule.java @@ -20,6 +20,7 @@ import android.app.INotificationManager; import android.content.Context; import android.view.WindowManager; +import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.bubbles.BubbleData; import com.android.systemui.bubbles.BubbleDataRepository; @@ -70,6 +71,7 @@ public interface BubbleModule { BubbleDataRepository bubbleDataRepository, SysUiState sysUiState, INotificationManager notifManager, + IStatusBarService statusBarService, WindowManager windowManager) { return new BubbleController( context, @@ -91,6 +93,7 @@ public interface BubbleModule { bubbleDataRepository, sysUiState, notifManager, + statusBarService, windowManager); } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index 07319207d9ab..45ba1e6012fe 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -190,11 +190,6 @@ interface ControlsController : UserAwareController { fun countFavoritesForComponent(componentName: ComponentName): Int /** - * TEMPORARY for testing - */ - fun resetFavorites() - - /** * Interface for structure to pass data to [ControlsFavoritingActivity]. */ interface LoadData { diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 93f0c7f41ce3..ebdcdccead90 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -524,13 +524,6 @@ class ControlsControllerImpl @Inject constructor ( } } - override fun resetFavorites() { - executor.execute { - Favorites.clear() - persistenceWrapper.storeFavorites(Favorites.getAllStructures()) - } - } - override fun refreshStatus(componentName: ComponentName, control: Control) { if (!confirmAvailability()) { Log.d(TAG, "Controls not available") diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index 9e7cf1ae6a42..353367ead7e6 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -87,9 +87,7 @@ class ControlViewHolder( deviceType: Int ): KClass<out Behavior> { return when { - status == Control.STATUS_UNKNOWN -> StatusBehavior::class - status == Control.STATUS_ERROR -> StatusBehavior::class - status == Control.STATUS_NOT_FOUND -> StatusBehavior::class + status != Control.STATUS_OK -> StatusBehavior::class deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class template is ToggleTemplate -> ToggleBehavior::class template is StatelessTemplate -> TouchBehavior::class @@ -123,7 +121,11 @@ class ControlViewHolder( private val onDialogCancel: () -> Unit = { lastChallengeDialog = null } val deviceType: Int - get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType + get() = cws.control?.let { it.deviceType } ?: cws.ci.deviceType + val controlStatus: Int + get() = cws.control?.let { it.status } ?: Control.STATUS_UNKNOWN + val controlTemplate: ControlTemplate + get() = cws.control?.let { it.controlTemplate } ?: ControlTemplate.NO_TEMPLATE init { val ld = layout.getBackground() as LayerDrawable @@ -140,14 +142,16 @@ class ControlViewHolder( cancelUpdate?.run() - val (controlStatus, template) = cws.control?.let { - title.setText(it.getTitle()) - subtitle.setText(it.getSubtitle()) - Pair(it.status, it.controlTemplate) - } ?: run { + // For the following statuses only, assume the title/subtitle could not be set properly + // by the app and instead use the last known information from favorites + if (controlStatus == Control.STATUS_UNKNOWN || controlStatus == Control.STATUS_NOT_FOUND) { title.setText(cws.ci.controlTitle) subtitle.setText(cws.ci.controlSubtitle) - Pair(Control.STATUS_UNKNOWN, ControlTemplate.NO_TEMPLATE) + } else { + cws.control?.let { + title.setText(it.title) + subtitle.setText(it.subtitle) + } } cws.control?.let { @@ -161,7 +165,8 @@ class ControlViewHolder( } isLoading = false - behavior = bindBehavior(behavior, findBehaviorClass(controlStatus, template, deviceType)) + behavior = bindBehavior(behavior, + findBehaviorClass(controlStatus, controlTemplate, deviceType)) updateContentDescription() } @@ -256,7 +261,13 @@ class ControlViewHolder( } internal fun applyRenderInfo(enabled: Boolean, offset: Int, animated: Boolean = true) { - val ri = RenderInfo.lookup(context, cws.componentName, deviceType, offset) + val deviceTypeOrError = if (controlStatus == Control.STATUS_OK || + controlStatus == Control.STATUS_UNKNOWN) { + deviceType + } else { + RenderInfo.ERROR_ICON + } + val ri = RenderInfo.lookup(context, cws.componentName, deviceTypeOrError, offset) val fg = context.resources.getColorStateList(ri.foreground, context.theme) val newText = nextStatusText nextStatusText = "" diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt index d31b6eb9d857..0f5aef7eeec1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -19,16 +19,13 @@ package com.android.systemui.controls.ui import android.animation.Animator import android.animation.AnimatorListenerAdapter import android.animation.ObjectAnimator -import android.app.AlertDialog import android.content.ComponentName import android.content.Context -import android.content.DialogInterface import android.content.Intent import android.content.SharedPreferences import android.content.res.Configuration import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable -import android.os.Process import android.service.controls.Control import android.util.Log import android.util.TypedValue @@ -36,7 +33,6 @@ import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.view.ViewGroup -import android.view.WindowManager import android.view.animation.AccelerateInterpolator import android.view.animation.DecelerateInterpolator import android.widget.AdapterView @@ -272,8 +268,7 @@ class ControlsUiControllerImpl @Inject constructor ( private fun createMenu() { val items = arrayOf( context.resources.getString(R.string.controls_menu_add), - context.resources.getString(R.string.controls_menu_edit), - "Reset" + context.resources.getString(R.string.controls_menu_edit) ) var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items) @@ -298,10 +293,6 @@ class ControlsUiControllerImpl @Inject constructor ( 0 -> startFavoritingActivity(view.context, selectedStructure) // 1: Edit controls 1 -> startEditingActivity(view.context, selectedStructure) - // 2: TEMPORARY for reset controls - 2 -> showResetConfirmation() - else -> Log.w(ControlsUiController.TAG, - "Unsupported index ($pos) on 'more' menu selection") } dismiss() } @@ -312,39 +303,6 @@ class ControlsUiControllerImpl @Inject constructor ( }) } - private fun showResetConfirmation() { - val builder = AlertDialog.Builder( - context, - android.R.style.Theme_DeviceDefault_Dialog_Alert - ).apply { - setMessage("For testing purposes: Would you like to " + - "reset your favorited device controls?") - setPositiveButton( - android.R.string.ok, - DialogInterface.OnClickListener { dialog, _ -> - val userHandle = Process.myUserHandle() - val userContext = context.createContextAsUser(userHandle, 0) - val prefs = userContext.getSharedPreferences( - "controls_prefs", Context.MODE_PRIVATE) - prefs.edit().remove("SeedingCompleted").apply() - controlsController.get().resetFavorites() - dialog.dismiss() - context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) - }) - setNegativeButton( - android.R.string.cancel, - DialogInterface.OnClickListener { - dialog, _ -> dialog.cancel() - } - ) - } - builder.create().apply { - getWindow().apply { - setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) - } - }.show() - } - private fun createDropDown(items: List<SelectionItem>) { items.forEach { RenderInfo.registerComponentIcon(it.componentName, it.icon) diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt index 09d41bdd6927..3f17a4fefd7e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/RenderInfo.kt @@ -35,6 +35,7 @@ data class RenderInfo( ) { companion object { const val APP_ICON_ID = -1 + const val ERROR_ICON = -1000 private val iconMap = SparseArray<Drawable>() private val appIconMap = ArrayMap<ComponentName, Drawable>() @@ -156,7 +157,8 @@ private val deviceIconMap = mapOf<Int, Int>( DeviceTypes.TYPE_CURTAIN to R.drawable.ic_device_blinds, DeviceTypes.TYPE_DOOR to R.drawable.ic_device_door, DeviceTypes.TYPE_SHUTTER to R.drawable.ic_device_window, - DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat + DeviceTypes.TYPE_HEATER to R.drawable.ic_device_thermostat, + RenderInfo.ERROR_ICON to R.drawable.ic_error_outline ).withDefault { R.drawable.ic_device_unknown } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index 5e5ebe92e559..bc95a2514c0b 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -779,7 +779,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @VisibleForTesting protected final class PowerOptionsAction extends SinglePressAction { private PowerOptionsAction() { - super(R.drawable.ic_lock_power_off, R.string.global_action_power_options); + super(com.android.systemui.R.drawable.ic_settings_power, + R.string.global_action_power_options); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java index 6b71f1e9d86f..1dbbb4d69493 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java @@ -19,6 +19,7 @@ import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; import android.content.res.Resources; +import android.util.LayoutDirection; import android.view.View; import android.view.View.MeasureSpec; import android.view.WindowManager; @@ -106,7 +107,11 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding); setWidth(width); - setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width); + if (getAnchorView().getLayoutDirection() == LayoutDirection.LTR) { + setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width); + } else { + setHorizontalOffset(mGlobalActionsSidePadding); + } } super.show(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java index 03b1ddca4648..7f7e1085d497 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipAnimationController.java @@ -17,7 +17,6 @@ package com.android.systemui.pip; import android.animation.Animator; -import android.animation.RectEvaluator; import android.animation.ValueAnimator; import android.annotation.IntDef; import android.content.Context; @@ -27,7 +26,6 @@ import android.view.animation.AnimationUtils; import android.view.animation.Interpolator; import com.android.internal.annotations.VisibleForTesting; -import com.android.systemui.Interpolators; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -76,12 +74,15 @@ public class PipAnimationController { || direction == TRANSITION_DIRECTION_TO_SPLIT_SCREEN; } + private final Interpolator mFastOutSlowInInterpolator; private final PipSurfaceTransactionHelper mSurfaceTransactionHelper; private PipTransitionAnimator mCurrentAnimator; @Inject PipAnimationController(Context context, PipSurfaceTransactionHelper helper) { + mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, + com.android.internal.R.interpolator.fast_out_slow_in); mSurfaceTransactionHelper = helper; } @@ -103,11 +104,10 @@ public class PipAnimationController { } @SuppressWarnings("unchecked") - PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds, - Rect sourceHintRect) { + PipTransitionAnimator getAnimator(SurfaceControl leash, Rect startBounds, Rect endBounds) { if (mCurrentAnimator == null) { mCurrentAnimator = setupPipTransitionAnimator( - PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); + PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); } else if (mCurrentAnimator.getAnimationType() == ANIM_TYPE_ALPHA && mCurrentAnimator.isRunning()) { // If we are still animating the fade into pip, then just move the surface and ensure @@ -122,7 +122,7 @@ public class PipAnimationController { } else { mCurrentAnimator.cancel(); mCurrentAnimator = setupPipTransitionAnimator( - PipTransitionAnimator.ofBounds(leash, startBounds, endBounds, sourceHintRect)); + PipTransitionAnimator.ofBounds(leash, startBounds, endBounds)); } return mCurrentAnimator; } @@ -133,7 +133,7 @@ public class PipAnimationController { private PipTransitionAnimator setupPipTransitionAnimator(PipTransitionAnimator animator) { animator.setSurfaceTransactionHelper(mSurfaceTransactionHelper); - animator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN); + animator.setInterpolator(mFastOutSlowInInterpolator); animator.setFloatValues(FRACTION_START, FRACTION_END); return animator; } @@ -331,7 +331,6 @@ public class PipAnimationController { @Override void onStartTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { getSurfaceTransactionHelper() - .resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()) .round(tx, leash, shouldApplyCornerRadius()); tx.show(leash); @@ -347,46 +346,35 @@ public class PipAnimationController { } static PipTransitionAnimator<Rect> ofBounds(SurfaceControl leash, - Rect startValue, Rect endValue, Rect sourceHintRect) { - // Just for simplicity we'll interpolate between the source rect hint insets and empty - // insets to calculate the window crop - final Rect initialStartValue = new Rect(startValue); - final Rect sourceHintRectInsets = sourceHintRect != null - ? new Rect(sourceHintRect.left - startValue.left, - sourceHintRect.top - startValue.top, - startValue.right - sourceHintRect.right, - startValue.bottom - sourceHintRect.bottom) - : null; - final Rect sourceInsets = new Rect(0, 0, 0, 0); - + Rect startValue, Rect endValue) { // construct new Rect instances in case they are recycled return new PipTransitionAnimator<Rect>(leash, ANIM_TYPE_BOUNDS, endValue, new Rect(startValue), new Rect(endValue)) { - private final RectEvaluator mRectEvaluator = new RectEvaluator(new Rect()); - private final RectEvaluator mInsetsEvaluator = new RectEvaluator(new Rect()); + private final Rect mTmpRect = new Rect(); + + private int getCastedFractionValue(float start, float end, float fraction) { + return (int) (start * (1 - fraction) + end * fraction + .5f); + } @Override void applySurfaceControlTransaction(SurfaceControl leash, SurfaceControl.Transaction tx, float fraction) { final Rect start = getStartValue(); final Rect end = getEndValue(); - Rect bounds = mRectEvaluator.evaluate(fraction, start, end); - setCurrentValue(bounds); + mTmpRect.set( + getCastedFractionValue(start.left, end.left, fraction), + getCastedFractionValue(start.top, end.top, fraction), + getCastedFractionValue(start.right, end.right, fraction), + getCastedFractionValue(start.bottom, end.bottom, fraction)); + setCurrentValue(mTmpRect); if (inScaleTransition()) { if (isOutPipDirection(getTransitionDirection())) { - getSurfaceTransactionHelper().scale(tx, leash, end, bounds); + getSurfaceTransactionHelper().scale(tx, leash, end, mTmpRect); } else { - getSurfaceTransactionHelper().scale(tx, leash, start, bounds); + getSurfaceTransactionHelper().scale(tx, leash, start, mTmpRect); } } else { - if (sourceHintRectInsets != null) { - Rect insets = mInsetsEvaluator.evaluate(fraction, sourceInsets, - sourceHintRectInsets); - getSurfaceTransactionHelper().scaleAndCrop(tx, leash, initialStartValue, - bounds, insets); - } else { - getSurfaceTransactionHelper().scale(tx, leash, start, bounds); - } + getSurfaceTransactionHelper().crop(tx, leash, mTmpRect); } tx.apply(); } @@ -402,11 +390,11 @@ public class PipAnimationController { @Override void onEndTransaction(SurfaceControl leash, SurfaceControl.Transaction tx) { + if (!inScaleTransition()) return; // NOTE: intentionally does not apply the transaction here. // this end transaction should get executed synchronously with the final // WindowContainerTransaction in task organizer - getSurfaceTransactionHelper() - .resetScale(tx, leash, getDestinationBounds()) + getSurfaceTransactionHelper().resetScale(tx, leash, getDestinationBounds()) .crop(tx, leash, getDestinationBounds()); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index 26576940740f..0d3a16ec1028 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -296,14 +296,6 @@ public class PipBoundsHandler { */ public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds, int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) { - // Calculate the snap fraction of the current stack along the old movement bounds - final Rect postChangeStackBounds = new Rect(oldBounds); - final float snapFraction = getSnapFraction(postChangeStackBounds); - - // Update the display layout, note that we have to do this on every rotation even if we - // aren't in PIP since we need to update the display layout to get the right resources - mDisplayLayout.rotateTo(mContext.getResources(), toRotation); - // Bail early if the event is not sent to current {@link #mDisplayInfo} if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) { return false; @@ -320,6 +312,13 @@ public class PipBoundsHandler { return false; } + // Calculate the snap fraction of the current stack along the old movement bounds + final Rect postChangeStackBounds = new Rect(oldBounds); + final float snapFraction = getSnapFraction(postChangeStackBounds); + + // Update the display layout + mDisplayLayout.rotateTo(mContext.getResources(), toRotation); + // Populate the new {@link #mDisplayInfo}. // The {@link DisplayInfo} queried from DisplayManager would be the one before rotation, // therefore, the width/height may require a swap first. diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java index 65ea887259be..fc41d2ea8862 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipSurfaceTransactionHelper.java @@ -44,7 +44,6 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf private final float[] mTmpFloat9 = new float[9]; private final RectF mTmpSourceRectF = new RectF(); private final RectF mTmpDestinationRectF = new RectF(); - private final Rect mTmpDestinationRect = new Rect(); @Inject public PipSurfaceTransactionHelper(Context context, ConfigurationController configController) { @@ -91,30 +90,7 @@ public class PipSurfaceTransactionHelper implements ConfigurationController.Conf mTmpDestinationRectF.set(destinationBounds); mTmpTransform.setRectToRect(mTmpSourceRectF, mTmpDestinationRectF, Matrix.ScaleToFit.FILL); tx.setMatrix(leash, mTmpTransform, mTmpFloat9) - .setPosition(leash, mTmpDestinationRectF.left, mTmpDestinationRectF.top); - return this; - } - - /** - * Operates the scale (setMatrix) on a given transaction and leash - * @return same {@link PipSurfaceTransactionHelper} instance for method chaining - */ - PipSurfaceTransactionHelper scaleAndCrop(SurfaceControl.Transaction tx, SurfaceControl leash, - Rect sourceBounds, Rect destinationBounds, Rect insets) { - mTmpSourceRectF.set(sourceBounds); - mTmpDestinationRect.set(sourceBounds); - mTmpDestinationRect.inset(insets); - // Scale by the shortest edge and offset such that the top/left of the scaled inset source - // rect aligns with the top/left of the destination bounds - final float scale = sourceBounds.width() <= sourceBounds.height() - ? (float) destinationBounds.width() / sourceBounds.width() - : (float) destinationBounds.height() / sourceBounds.height(); - final float left = destinationBounds.left - insets.left * scale; - final float top = destinationBounds.top - insets.top * scale; - mTmpTransform.setScale(scale, scale); - tx.setMatrix(leash, mTmpTransform, mTmpFloat9) - .setWindowCrop(leash, mTmpDestinationRect) - .setPosition(leash, left, top); + .setPosition(leash, destinationBounds.left, destinationBounds.top); return this; } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index 42e0c56d6cc8..c6f144aa57a1 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -143,10 +143,8 @@ public class PipTaskOrganizer extends TaskOrganizer implements case MSG_RESIZE_ANIMATE: { Rect currentBounds = (Rect) args.arg2; Rect toBounds = (Rect) args.arg3; - Rect sourceHintRect = (Rect) args.arg4; int duration = args.argi2; - animateResizePip(currentBounds, toBounds, sourceHintRect, - args.argi1 /* direction */, duration); + animateResizePip(currentBounds, toBounds, args.argi1 /* direction */, duration); if (updateBoundsCallback != null) { updateBoundsCallback.accept(toBounds); } @@ -296,8 +294,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements public void onTransactionReady(int id, SurfaceControl.Transaction t) { t.apply(); scheduleAnimateResizePip(mLastReportedBounds, destinationBounds, - null /* sourceHintRect */, direction, animationDurationMs, - null /* updateBoundsCallback */); + direction, animationDurationMs, null /* updateBoundsCallback */); mInPip = false; } }); @@ -360,8 +357,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements final Rect currentBounds = mTaskInfo.configuration.windowConfiguration.getBounds(); if (mOneShotAnimationType == ANIM_TYPE_BOUNDS) { - final Rect sourceHintRect = getValidSourceHintRect(info, currentBounds); - scheduleAnimateResizePip(currentBounds, destinationBounds, sourceHintRect, + scheduleAnimateResizePip(currentBounds, destinationBounds, TRANSITION_DIRECTION_TO_PIP, mEnterExitAnimationDuration, null /* updateBoundsCallback */); } else if (mOneShotAnimationType == ANIM_TYPE_ALPHA) { @@ -372,21 +368,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements } } - /** - * Returns the source hint rect if it is valid (if provided and is contained by the current - * task bounds). - */ - private Rect getValidSourceHintRect(ActivityManager.RunningTaskInfo info, Rect sourceBounds) { - final Rect sourceHintRect = info.pictureInPictureParams != null - && info.pictureInPictureParams.hasSourceBoundsHint() - ? info.pictureInPictureParams.getSourceRectHint() - : null; - if (sourceHintRect != null && sourceBounds.contains(sourceHintRect)) { - return sourceHintRect; - } - return null; - } - private void enterPipWithAlphaAnimation(Rect destinationBounds, long durationMs) { // If we are fading the PIP in, then we should move the pip to the final location as // soon as possible, but set the alpha immediately since the transaction can take a @@ -571,13 +552,13 @@ public class PipTaskOrganizer extends TaskOrganizer implements Log.d(TAG, "skip scheduleAnimateResizePip, entering pip deferred"); return; } - scheduleAnimateResizePip(mLastReportedBounds, toBounds, null /* sourceHintRect */, + scheduleAnimateResizePip(mLastReportedBounds, toBounds, TRANSITION_DIRECTION_NONE, duration, updateBoundsCallback); } private void scheduleAnimateResizePip(Rect currentBounds, Rect destinationBounds, - Rect sourceHintRect, @PipAnimationController.TransitionDirection int direction, - int durationMs, Consumer<Rect> updateBoundsCallback) { + @PipAnimationController.TransitionDirection int direction, int durationMs, + Consumer<Rect> updateBoundsCallback) { if (!mInPip) { // can be initiated in other component, ignore if we are no longer in PIP return; @@ -587,7 +568,6 @@ public class PipTaskOrganizer extends TaskOrganizer implements args.arg1 = updateBoundsCallback; args.arg2 = currentBounds; args.arg3 = destinationBounds; - args.arg4 = sourceHintRect; args.argi1 = direction; args.argi2 = durationMs; mUpdateHandler.sendMessage(mUpdateHandler.obtainMessage(MSG_RESIZE_ANIMATE, args)); @@ -687,8 +667,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements } final Rect destinationBounds = new Rect(originalBounds); destinationBounds.offset(xOffset, yOffset); - animateResizePip(originalBounds, destinationBounds, null /* sourceHintRect */, - TRANSITION_DIRECTION_SAME, durationMs); + animateResizePip(originalBounds, destinationBounds, TRANSITION_DIRECTION_SAME, durationMs); } private void resizePip(Rect destinationBounds) { @@ -766,7 +745,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements WindowOrganizer.applyTransaction(wct); } - private void animateResizePip(Rect currentBounds, Rect destinationBounds, Rect sourceHintRect, + private void animateResizePip(Rect currentBounds, Rect destinationBounds, @PipAnimationController.TransitionDirection int direction, int durationMs) { if (Looper.myLooper() != mUpdateHandler.getLooper()) { throw new RuntimeException("Callers should call scheduleAnimateResizePip() instead of " @@ -778,7 +757,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements return; } mPipAnimationController - .getAnimator(mLeash, currentBounds, destinationBounds, sourceHintRect) + .getAnimator(mLeash, currentBounds, destinationBounds) .setTransitionDirection(direction) .setPipAnimationCallback(mPipAnimationCallback) .setDuration(durationMs) diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java index 1ddb1f51670b..3cc9127068bf 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -30,6 +30,7 @@ import android.graphics.PixelFormat; import android.graphics.Point; import android.graphics.PointF; import android.graphics.Rect; +import android.graphics.drawable.TransitionDrawable; import android.os.Handler; import android.os.RemoteException; import android.util.Log; @@ -76,6 +77,9 @@ import java.io.PrintWriter; public class PipTouchHandler { private static final String TAG = "PipTouchHandler"; + /** Duration of the dismiss scrim fading in/out. */ + private static final int DISMISS_TRANSITION_DURATION_MS = 200; + // Allow dragging the PIP to a location to close it private final boolean mEnableDismissDragToEdge; // Allow PIP to resize to a slightly bigger state upon touch @@ -249,6 +253,8 @@ public class PipTouchHandler { mTargetView = new DismissCircleView(context); mTargetViewContainer = new FrameLayout(context); + mTargetViewContainer.setBackgroundDrawable( + context.getDrawable(R.drawable.floating_dismiss_gradient_transition)); mTargetViewContainer.setClipChildren(false); mTargetViewContainer.addView(mTargetView); @@ -553,6 +559,9 @@ public class PipTouchHandler { mMagneticTargetAnimator .spring(DynamicAnimation.TRANSLATION_Y, 0f, mTargetSpringConfig) .start(); + + ((TransitionDrawable) mTargetViewContainer.getBackground()).startTransition( + DISMISS_TRANSITION_DURATION_MS); } } @@ -565,6 +574,9 @@ public class PipTouchHandler { mTargetSpringConfig) .withEndActions(() -> mTargetViewContainer.setVisibility(View.GONE)) .start(); + + ((TransitionDrawable) mTargetViewContainer.getBackground()).reverseTransition( + DISMISS_TRANSITION_DURATION_MS); } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java index d7dd6f24ceb3..32ef063a55be 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ScreenRecordTile.java @@ -22,6 +22,7 @@ import android.text.TextUtils; import android.util.Log; import android.widget.Switch; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.qs.QSTile; @@ -41,14 +42,16 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> private ActivityStarter mActivityStarter; private long mMillisUntilFinished = 0; private Callback mCallback = new Callback(); + private UiEventLogger mUiEventLogger; @Inject public ScreenRecordTile(QSHost host, RecordingController controller, - ActivityStarter activityStarter) { + ActivityStarter activityStarter, UiEventLogger uiEventLogger) { super(host); mController = controller; mController.observe(this, mCallback); mActivityStarter = activityStarter; + mUiEventLogger = uiEventLogger; } @Override @@ -112,7 +115,6 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> } private void startCountdown() { - Log.d(TAG, "Starting countdown"); // Close QS, otherwise the permission dialog appears beneath it getHost().collapsePanels(); Intent intent = mController.getPromptIntent(); @@ -125,7 +127,6 @@ public class ScreenRecordTile extends QSTileImpl<QSTile.BooleanState> } private void stopRecording() { - Log.d(TAG, "Stopping recording from tile"); mController.stopRecording(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java index aa63b4077b1b..6a8c61491709 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailItemView.java @@ -95,14 +95,11 @@ public class UserDetailItemView extends LinearLayout { mAvatar.setDrawableWithBadge(picture, userId); } - public void setAvatarEnabled(boolean enabled) { - mAvatar.setEnabled(enabled); - } - public void setDisabledByAdmin(boolean disabled) { - mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE); - mName.setEnabled(!disabled); - mAvatar.setEnabled(!disabled); + if (mRestrictedPadlock != null) { + mRestrictedPadlock.setVisibility(disabled ? View.VISIBLE : View.GONE); + } + setEnabled(!disabled); } public void setEnabled(boolean enabled) { diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java index 89ce125ae985..fba7a22351e2 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java +++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java @@ -16,8 +16,12 @@ package com.android.systemui.qs.tiles; +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA; +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA; + import android.content.Context; import android.content.Intent; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; @@ -94,18 +98,21 @@ public class UserDetailView extends PseudoGridView { } String name = getName(mContext, item); if (item.picture == null) { - v.bind(name, getDrawable(mContext, item), item.resolveId()); + v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); } else { - v.bind(name, item.picture, item.info.id); + Drawable drawable = new BitmapDrawable(v.getResources(), item.picture); + drawable.setColorFilter( + item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); + v.bind(name, drawable, item.info.id); } v.setActivated(item.isCurrent); + v.setDisabledByAdmin(item.isDisabledByAdmin); + v.setEnabled(item.isSwitchToEnabled); + v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA); + if (item.isCurrent) { mCurrentUserView = v; } - v.setDisabledByAdmin(item.isDisabledByAdmin); - if (!item.isSwitchToEnabled) { - v.setEnabled(false); - } v.setTag(item); return v; } @@ -113,8 +120,14 @@ public class UserDetailView extends PseudoGridView { private static Drawable getDrawable(Context context, UserSwitcherController.UserRecord item) { Drawable icon = getIconDrawable(context, item); - int iconColorRes = item.isCurrent ? R.color.qs_user_switcher_selected_avatar_icon_color - : R.color.qs_user_switcher_avatar_icon_color; + int iconColorRes; + if (item.isCurrent) { + iconColorRes = R.color.qs_user_switcher_selected_avatar_icon_color; + } else if (!item.isSwitchToEnabled) { + iconColorRes = R.color.GM2_grey_600; + } else { + iconColorRes = R.color.qs_user_switcher_avatar_icon_color; + } icon.setTint(context.getResources().getColor(iconColorRes, context.getTheme())); int bgRes = item.isCurrent ? R.drawable.bg_avatar_selected : R.drawable.qs_bg_avatar; diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java index baa2dfdcebf3..8a012b8b06f1 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java +++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java @@ -577,10 +577,6 @@ public class OverviewProxyService extends CurrentUserTracker implements // Listen for nav bar mode changes mNavBarMode = navModeController.addListener(this); - // Listen for device provisioned/user setup - updateEnabledState(); - startTracking(); - // Listen for launcher package changes IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED); filter.addDataScheme("package"); @@ -601,6 +597,13 @@ public class OverviewProxyService extends CurrentUserTracker implements .commitUpdate(mContext.getDisplayId()); } }); + + // Listen for user setup + startTracking(); + + // Connect to the service + updateEnabledState(); + startConnectionToCurrentUser(); } @Override diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java new file mode 100644 index 000000000000..9dede4848914 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/Events.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenrecord; + +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; + +/** + * Events related to the SystemUI screen recorder + */ +public class Events { + + public enum ScreenRecordEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Screen recording was started") + SCREEN_RECORD_START(299), + @UiEvent(doc = "Screen recording was stopped from the quick settings tile") + SCREEN_RECORD_END_QS_TILE(300), + @UiEvent(doc = "Screen recording was stopped from the notification") + SCREEN_RECORD_END_NOTIFICATION(301); + + private final int mId; + ScreenRecordEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } +} diff --git a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java index 2ddd6aaf4c40..f2e8599536ca 100644 --- a/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java +++ b/packages/SystemUI/src/com/android/systemui/screenrecord/RecordingService.java @@ -36,6 +36,8 @@ import android.provider.Settings; import android.util.Log; import android.widget.Toast; +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.R; import com.android.systemui.dagger.qualifiers.LongRunning; @@ -63,22 +65,28 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private static final String ACTION_START = "com.android.systemui.screenrecord.START"; private static final String ACTION_STOP = "com.android.systemui.screenrecord.STOP"; + private static final String ACTION_STOP_NOTIF = + "com.android.systemui.screenrecord.STOP_FROM_NOTIF"; private static final String ACTION_SHARE = "com.android.systemui.screenrecord.SHARE"; private static final String ACTION_DELETE = "com.android.systemui.screenrecord.DELETE"; private final RecordingController mController; - private Notification.Builder mRecordingNotificationBuilder; private ScreenRecordingAudioSource mAudioSource; private boolean mShowTaps; private boolean mOriginalShowTaps; private ScreenMediaRecorder mRecorder; private final Executor mLongExecutor; + private final UiEventLogger mUiEventLogger; + private final NotificationManager mNotificationManager; @Inject - public RecordingService(RecordingController controller, @LongRunning Executor executor) { + public RecordingService(RecordingController controller, @LongRunning Executor executor, + UiEventLogger uiEventLogger, NotificationManager notificationManager) { mController = controller; mLongExecutor = executor; + mUiEventLogger = uiEventLogger; + mNotificationManager = notificationManager; } /** @@ -110,9 +118,6 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis String action = intent.getAction(); Log.d(TAG, "onStartCommand " + action); - NotificationManager notificationManager = - (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - switch (action) { case ACTION_START: mAudioSource = ScreenRecordingAudioSource @@ -135,10 +140,16 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis startRecording(); break; + case ACTION_STOP_NOTIF: case ACTION_STOP: + // only difference for actions is the log event + if (ACTION_STOP_NOTIF.equals(action)) { + mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION); + } else { + mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE); + } stopRecording(); - notificationManager.cancel(NOTIFICATION_RECORDING_ID); - saveRecording(notificationManager); + mNotificationManager.cancel(NOTIFICATION_RECORDING_ID); stopSelf(); break; @@ -154,7 +165,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); // Remove notification - notificationManager.cancel(NOTIFICATION_VIEW_ID); + mNotificationManager.cancel(NOTIFICATION_VIEW_ID); startActivity(Intent.createChooser(shareIntent, shareLabel) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); @@ -173,7 +184,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis Toast.LENGTH_LONG).show(); // Remove notification - notificationManager.cancel(NOTIFICATION_VIEW_ID); + mNotificationManager.cancel(NOTIFICATION_VIEW_ID); Log.d(TAG, "Deleted recording " + uri); break; } @@ -190,14 +201,20 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis super.onCreate(); } + @VisibleForTesting + protected ScreenMediaRecorder getRecorder() { + return mRecorder; + } + /** * Begin the recording session */ private void startRecording() { try { - mRecorder.start(); + getRecorder().start(); mController.updateState(true); createRecordingNotification(); + mUiEventLogger.log(Events.ScreenRecordEvent.SCREEN_RECORD_START); } catch (IOException | RemoteException e) { Toast.makeText(this, R.string.screenrecord_start_error, Toast.LENGTH_LONG) @@ -206,7 +223,8 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis } } - private void createRecordingNotification() { + @VisibleForTesting + protected void createRecordingNotification() { Resources res = getResources(); NotificationChannel channel = new NotificationChannel( CHANNEL_ID, @@ -214,9 +232,7 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis NotificationManager.IMPORTANCE_DEFAULT); channel.setDescription(getString(R.string.screenrecord_channel_description)); channel.enableVibration(true); - NotificationManager notificationManager = - (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); - notificationManager.createNotificationChannel(channel); + mNotificationManager.createNotificationChannel(channel); Bundle extras = new Bundle(); extras.putString(Notification.EXTRA_SUBSTITUTE_APP_NAME, @@ -226,7 +242,9 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis ? res.getString(R.string.screenrecord_ongoing_screen_only) : res.getString(R.string.screenrecord_ongoing_screen_and_audio); - mRecordingNotificationBuilder = new Notification.Builder(this, CHANNEL_ID) + + Intent stopIntent = getNotificationIntent(this); + Notification.Builder builder = new Notification.Builder(this, CHANNEL_ID) .setSmallIcon(R.drawable.ic_screenrecord) .setContentTitle(notificationTitle) .setContentText(getResources().getString(R.string.screenrecord_stop_text)) @@ -235,17 +253,28 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis .setColor(getResources().getColor(R.color.GM2_red_700)) .setOngoing(true) .setContentIntent( - PendingIntent.getService( - this, REQUEST_CODE, getStopIntent(this), + PendingIntent.getService(this, REQUEST_CODE, stopIntent, PendingIntent.FLAG_UPDATE_CURRENT)) .addExtras(extras); - notificationManager.notify(NOTIFICATION_RECORDING_ID, - mRecordingNotificationBuilder.build()); - Notification notification = mRecordingNotificationBuilder.build(); - startForeground(NOTIFICATION_RECORDING_ID, notification); + startForeground(NOTIFICATION_RECORDING_ID, builder.build()); } - private Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) { + @VisibleForTesting + protected Notification createProcessingNotification() { + Resources res = getApplicationContext().getResources(); + String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE + ? res.getString(R.string.screenrecord_ongoing_screen_only) + : res.getString(R.string.screenrecord_ongoing_screen_and_audio); + Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID) + .setContentTitle(notificationTitle) + .setContentText( + getResources().getString(R.string.screenrecord_background_processing_label)) + .setSmallIcon(R.drawable.ic_screenrecord); + return builder.build(); + } + + @VisibleForTesting + protected Notification createSaveNotification(ScreenMediaRecorder.SavedRecording recording) { Uri uri = recording.getUri(); Intent viewIntent = new Intent(Intent.ACTION_VIEW) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION) @@ -301,44 +330,39 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis private void stopRecording() { setTapsVisible(mOriginalShowTaps); - mRecorder.end(); + if (getRecorder() != null) { + getRecorder().end(); + saveRecording(); + } else { + Log.e(TAG, "stopRecording called, but recorder was null"); + } mController.updateState(false); } - private void saveRecording(NotificationManager notificationManager) { - Resources res = getApplicationContext().getResources(); - String notificationTitle = mAudioSource == ScreenRecordingAudioSource.NONE - ? res.getString(R.string.screenrecord_ongoing_screen_only) - : res.getString(R.string.screenrecord_ongoing_screen_and_audio); - Notification.Builder builder = new Notification.Builder(getApplicationContext(), CHANNEL_ID) - .setContentTitle(notificationTitle) - .setContentText( - getResources().getString(R.string.screenrecord_background_processing_label)) - .setSmallIcon(R.drawable.ic_screenrecord); - notificationManager.notify(NOTIFICATION_PROCESSING_ID, builder.build()); + private void saveRecording() { + mNotificationManager.notify(NOTIFICATION_PROCESSING_ID, createProcessingNotification()); mLongExecutor.execute(() -> { try { Log.d(TAG, "saving recording"); - Notification notification = createSaveNotification(mRecorder.save()); + Notification notification = createSaveNotification(getRecorder().save()); if (!mController.isRecording()) { Log.d(TAG, "showing saved notification"); - notificationManager.notify(NOTIFICATION_VIEW_ID, notification); + mNotificationManager.notify(NOTIFICATION_VIEW_ID, notification); } } catch (IOException e) { Log.e(TAG, "Error saving screen recording: " + e.getMessage()); Toast.makeText(this, R.string.screenrecord_delete_error, Toast.LENGTH_LONG) .show(); } finally { - notificationManager.cancel(NOTIFICATION_PROCESSING_ID); + mNotificationManager.cancel(NOTIFICATION_PROCESSING_ID); } }); } private void setTapsVisible(boolean turnOn) { int value = turnOn ? 1 : 0; - Settings.System.putInt(getApplicationContext().getContentResolver(), - Settings.System.SHOW_TOUCHES, value); + Settings.System.putInt(getContentResolver(), Settings.System.SHOW_TOUCHES, value); } /** @@ -350,6 +374,15 @@ public class RecordingService extends Service implements MediaRecorder.OnInfoLis return new Intent(context, RecordingService.class).setAction(ACTION_STOP); } + /** + * Get the recording notification content intent + * @param context + * @return + */ + protected static Intent getNotificationIntent(Context context) { + return new Intent(context, RecordingService.class).setAction(ACTION_STOP_NOTIF); + } + private static Intent getShareIntent(Context context, String path) { return new Intent(context, RecordingService.class).setAction(ACTION_SHARE) .putExtra(EXTRA_PATH, path); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java index a8c03243c117..5bee9a762f6f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationViewHierarchyManager.java @@ -60,7 +60,11 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle private final Handler mHandler; - /** Re-usable map of top-level notifications to their sorted children if any.*/ + /** + * Re-usable map of top-level notifications to their sorted children if any. + * If the top-level notification doesn't have children, its key will still exist in this map + * with its value explicitly set to null. + */ private final HashMap<NotificationEntry, List<NotificationEntry>> mTmpChildOrderMap = new HashMap<>(); @@ -212,10 +216,19 @@ public class NotificationViewHierarchyManager implements DynamicPrivacyControlle } orderedChildren.add(ent); } else { - // Top-level notif - mTmpChildOrderMap.put(ent, null); + // Top-level notif (either a summary or single notification) + + // A child may have already added its summary to mTmpChildOrderMap with a + // list of children. This can happen since there's no guarantee summaries are + // sorted before its children. + if (!mTmpChildOrderMap.containsKey(ent)) { + // mTmpChildOrderMap's keyset is used to iterate through all entries, so it's + // necessary to add each top-level notif as a key + mTmpChildOrderMap.put(ent, null); + } toShow.add(ent.getRow()); } + } ArrayList<ExpandableNotificationRow> viewsToRemove = new ArrayList<>(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt index fc6c2be1ce9a..1972b869ba25 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ConversationNotifications.kt @@ -19,13 +19,16 @@ package com.android.systemui.statusbar.notification import android.app.Notification import android.content.Context import android.content.pm.LauncherApps +import android.os.Handler import android.service.notification.NotificationListenerService.Ranking import android.service.notification.NotificationListenerService.RankingMap import com.android.internal.statusbar.NotificationVisibility import com.android.internal.widget.ConversationLayout +import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.notification.collection.NotificationEntry import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.NotificationContentView +import com.android.systemui.statusbar.notification.stack.StackStateAnimator import com.android.systemui.statusbar.phone.NotificationGroupManager import java.util.concurrent.ConcurrentHashMap import javax.inject.Inject @@ -62,7 +65,8 @@ class ConversationNotificationProcessor @Inject constructor( class ConversationNotificationManager @Inject constructor( private val notificationEntryManager: NotificationEntryManager, private val notificationGroupManager: NotificationGroupManager, - private val context: Context + private val context: Context, + @Main private val mainHandler: Handler ) { // Need this state to be thread safe, since it's accessed from the ui thread // (NotificationEntryListener) and a bg thread (NotificationContentInflater) @@ -72,32 +76,41 @@ class ConversationNotificationManager @Inject constructor( init { notificationEntryManager.addNotificationEntryListener(object : NotificationEntryListener { - override fun onNotificationRankingUpdated(rankingMap: RankingMap) { fun getLayouts(view: NotificationContentView) = sequenceOf(view.contractedChild, view.expandedChild, view.headsUpChild) val ranking = Ranking() - states.keys.asSequence() + val activeConversationEntries = states.keys.asSequence() .mapNotNull { notificationEntryManager.getActiveNotificationUnfiltered(it) } - .forEach { entry -> - if (rankingMap.getRanking(entry.sbn.key, ranking) && - ranking.isConversation) { - val important = ranking.channel.isImportantConversation - var changed = false - entry.row?.layouts?.asSequence() - ?.flatMap(::getLayouts) - ?.mapNotNull { it as? ConversationLayout } - ?.forEach { - if (important != it.isImportantConversation) { - it.setIsImportantConversation(important) - changed = true - } - } - if (changed) { - notificationGroupManager.updateIsolation(entry) - } + for (entry in activeConversationEntries) { + if (rankingMap.getRanking(entry.sbn.key, ranking) && ranking.isConversation) { + val important = ranking.channel.isImportantConversation + val layouts = entry.row?.layouts?.asSequence() + ?.flatMap(::getLayouts) + ?.mapNotNull { it as? ConversationLayout } + ?: emptySequence() + var changed = false + for (layout in layouts) { + if (important == layout.isImportantConversation) { + continue + } + changed = true + if (important && entry.isMarkedForUserTriggeredMovement) { + // delay this so that it doesn't animate in until after + // the notif has been moved in the shade + mainHandler.postDelayed({ + layout.setIsImportantConversation( + important, true /* animate */) + }, IMPORTANCE_ANIMATION_DELAY.toLong()) + } else { + layout.setIsImportantConversation(important) } } + if (changed) { + notificationGroupManager.updateIsolation(entry) + } + } + } } override fun onEntryInflated(entry: NotificationEntry) { @@ -177,9 +190,16 @@ class ConversationNotificationManager @Inject constructor( private fun resetBadgeUi(row: ExpandableNotificationRow): Unit = (row.layouts?.asSequence() ?: emptySequence()) - .flatMap { layout -> layout.allViews.asSequence()} + .flatMap { layout -> layout.allViews.asSequence() } .mapNotNull { view -> view as? ConversationLayout } .forEach { convoLayout -> convoLayout.setUnreadCount(0) } private data class ConversationState(val unreadCount: Int, val notification: Notification) + + companion object { + private const val IMPORTANCE_ANIMATION_DELAY = + StackStateAnimator.ANIMATION_DURATION_STANDARD + + StackStateAnimator.ANIMATION_DURATION_PRIORITY_CHANGE + + 100 + } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java index df3609bbc6b6..1c076c49249b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/provider/HighPriorityProvider.java @@ -23,6 +23,9 @@ import com.android.systemui.statusbar.notification.collection.GroupEntry; import com.android.systemui.statusbar.notification.collection.ListEntry; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.phone.NotificationGroupManager; + +import java.util.List; import javax.inject.Inject; import javax.inject.Singleton; @@ -36,10 +39,14 @@ import javax.inject.Singleton; @Singleton public class HighPriorityProvider { private final PeopleNotificationIdentifier mPeopleNotificationIdentifier; + private final NotificationGroupManager mGroupManager; @Inject - public HighPriorityProvider(PeopleNotificationIdentifier peopleNotificationIdentifier) { + public HighPriorityProvider( + PeopleNotificationIdentifier peopleNotificationIdentifier, + NotificationGroupManager groupManager) { mPeopleNotificationIdentifier = peopleNotificationIdentifier; + mGroupManager = groupManager; } /** @@ -74,13 +81,25 @@ public class HighPriorityProvider { private boolean hasHighPriorityChild(ListEntry entry) { + List<NotificationEntry> children = null; + if (entry instanceof GroupEntry) { - for (NotificationEntry child : ((GroupEntry) entry).getChildren()) { + // New notification pipeline + children = ((GroupEntry) entry).getChildren(); + } else if (entry.getRepresentativeEntry() != null + && mGroupManager.isGroupSummary(entry.getRepresentativeEntry().getSbn())) { + // Old notification pipeline + children = mGroupManager.getChildren(entry.getRepresentativeEntry().getSbn()); + } + + if (children != null) { + for (NotificationEntry child : children) { if (isHighPriority(child)) { return true; } } } + return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java index 87612f15ed3d..e445c9d73bbb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/AppOpsInfo.java @@ -188,7 +188,9 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon @Override public boolean handleCloseControls(boolean save, boolean force) { - mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false); + if (mMetricsLogger != null) { + mMetricsLogger.visibility(MetricsEvent.APP_OPS_GUTS, false); + } return false; } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java index e9d89589172e..f4afb91396b5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfo.java @@ -53,7 +53,6 @@ import android.transition.TransitionManager; import android.transition.TransitionSet; import android.util.AttributeSet; import android.util.Log; -import android.util.Slog; import android.view.LayoutInflater; import android.view.View; import android.view.accessibility.AccessibilityEvent; @@ -508,10 +507,10 @@ public class NotificationConversationInfo extends LinearLayout implements mBgHandler.post( new UpdateChannelRunnable(mINotificationManager, mPackageName, mAppUid, mSelectedAction, mNotificationChannel)); - mMainHandler.postDelayed(() -> { - mEntry.markForUserTriggeredMovement(true); - mVisualStabilityManager.temporarilyAllowReordering(); - }, StackStateAnimator.ANIMATION_DURATION_STANDARD); + mEntry.markForUserTriggeredMovement(true); + mMainHandler.postDelayed( + mVisualStabilityManager::temporarilyAllowReordering, + StackStateAnimator.ANIMATION_DURATION_STANDARD); } private boolean shouldShowPriorityOnboarding() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java index f1fe54ad4024..186ffa67f046 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/PartialConversationInfo.java @@ -148,8 +148,7 @@ public class PartialConversationInfo extends LinearLayout implements } private void bindHeader() { - bindConversationDetails(); - + bindPackage(); // Delegate bindDelegate(); } @@ -180,51 +179,6 @@ public class PartialConversationInfo extends LinearLayout implements }); } - private void bindConversationDetails() { - final TextView channelName = findViewById(R.id.parent_channel_name); - channelName.setText(mNotificationChannel.getName()); - - bindGroup(); - bindName(); - bindPackage(); - bindIcon(); - } - - private void bindName() { - TextView name = findViewById(R.id.name); - Bundle extras = mSbn.getNotification().extras; - CharSequence nameString = extras.getCharSequence(Notification.EXTRA_CONVERSATION_TITLE, ""); - if (TextUtils.isEmpty(nameString)) { - nameString = extras.getCharSequence(Notification.EXTRA_TITLE, ""); - } - name.setText(nameString); - } - - private void bindIcon() { - ImageView image = findViewById(R.id.conversation_icon); - if (mSbn.getNotification().extras.getBoolean(EXTRA_IS_GROUP_CONVERSATION, false)) { - // TODO: maybe use a generic group icon, or a composite of recent senders - image.setImageDrawable(mPkgIcon); - } else { - final List<Notification.MessagingStyle.Message> messages = - Notification.MessagingStyle.Message.getMessagesFromBundleArray( - (Parcelable[]) mSbn.getNotification().extras.get( - Notification.EXTRA_MESSAGES)); - - final Notification.MessagingStyle.Message latestMessage = - Notification.MessagingStyle.findLatestIncomingMessage(messages); - Icon personIcon = null; - if (latestMessage != null && latestMessage.getSenderPerson() != null) { - personIcon = latestMessage.getSenderPerson().getIcon(); - } - if (personIcon != null) { - image.setImageIcon(latestMessage.getSenderPerson().getIcon()); - } else { - image.setImageDrawable(mPkgIcon); - } - } - } - private void bindPackage() { ApplicationInfo info; try { @@ -241,6 +195,10 @@ public class PartialConversationInfo extends LinearLayout implements } catch (PackageManager.NameNotFoundException e) { mPkgIcon = mPm.getDefaultActivityIcon(); } + TextView name = findViewById(R.id.name); + name.setText(mAppName); + ImageView image = findViewById(R.id.icon); + image.setImageDrawable(mPkgIcon); } private void bindDelegate() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java index 4c9cb209424a..c747a7c300b7 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationHeaderViewWrapper.java @@ -262,7 +262,10 @@ public class NotificationHeaderViewWrapper extends NotificationViewWrapper { stack.push(mView); while (!stack.isEmpty()) { View child = stack.pop(); - if (child instanceof ImageView) { + if (child instanceof ImageView + // Skip the importance ring for conversations, disabled cropping is needed for + // its animation + && child.getId() != com.android.internal.R.id.conversation_icon_badge_ring) { ((ImageView) child).setCropToPadding(true); } else if (child instanceof ViewGroup){ ViewGroup group = (ViewGroup) child; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java index 325c8c0e506a..b11ed23c3aeb 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java @@ -146,6 +146,7 @@ import com.android.systemui.statusbar.phone.HeadsUpManagerPhone; import com.android.systemui.statusbar.phone.HeadsUpTouchHelper; import com.android.systemui.statusbar.phone.KeyguardBypassController; import com.android.systemui.statusbar.phone.LockscreenGestureLogger; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationGroupManager.OnGroupChangeListener; import com.android.systemui.statusbar.phone.NotificationIconAreaController; @@ -6633,6 +6634,7 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd MetricsEvent.ACTION_LS_SHADE, (int) (dragLengthY / mDisplayMetrics.density), 0 /* velocityDp - N/A */); + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_PULL_SHADE_OPEN); if (!mAmbientState.isDozing() || startingChild != null) { // We have notifications, go to locked shade. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java index 8c3420a522ec..83d398d3e7ae 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenGestureLogger.java @@ -20,6 +20,9 @@ import android.metrics.LogMaker; import android.util.ArrayMap; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; +import com.android.internal.logging.UiEventLoggerImpl; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.systemui.Dependency; import com.android.systemui.EventLogConstants; @@ -34,6 +37,56 @@ import javax.inject.Singleton; */ @Singleton public class LockscreenGestureLogger { + + /** + * Contains Lockscreen related Westworld UiEvent enums. + */ + public enum LockscreenUiEvent implements UiEventLogger.UiEventEnum { + @UiEvent(doc = "Lockscreen > Pull shade open") + LOCKSCREEN_PULL_SHADE_OPEN(539), + + @UiEvent(doc = "Lockscreen > Tap on lock, locks phone") + LOCKSCREEN_LOCK_TAP(540), + + @UiEvent(doc = "Lockscreen > Swipe down to open quick settings") + LOCKSCREEN_QUICK_SETTINGS_OPEN(541), + + @UiEvent(doc = "Swipe down to open quick settings when unlocked") + LOCKSCREEN_UNLOCKED_QUICK_SETTINGS_OPEN(542), + + @UiEvent(doc = "Lockscreen > Tap on lock, shows hint") + LOCKSCREEN_LOCK_SHOW_HINT(543), + + @UiEvent(doc = "Notification shade > Tap to open quick settings") + LOCKSCREEN_NOTIFICATION_SHADE_QUICK_SETTINGS_OPEN(544), + + @UiEvent(doc = "Lockscreen > Dialer") + LOCKSCREEN_DIALER(545), + + @UiEvent(doc = "Lockscreen > Camera") + LOCKSCREEN_CAMERA(546), + + @UiEvent(doc = "Lockscreen > Unlock gesture") + LOCKSCREEN_UNLOCK(547), + + @UiEvent(doc = "Lockscreen > Tap on notification, false touch rejection") + LOCKSCREEN_NOTIFICATION_FALSE_TOUCH(548), + + @UiEvent(doc = "Expand the notification panel while unlocked") + LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND(549); + + private final int mId; + + LockscreenUiEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } + private ArrayMap<Integer, Integer> mLegacyMap; private final MetricsLogger mMetricsLogger = Dependency.get(MetricsLogger.class); @@ -55,6 +108,13 @@ public class LockscreenGestureLogger { } /** + * Logs {@link LockscreenUiEvent}. + */ + public void log(LockscreenUiEvent lockscreenUiEvent) { + new UiEventLoggerImpl().log(lockscreenUiEvent); + } + + /** * Record the location of a swipe gesture, expressed as percentages of the whole screen * @param category the action * @param xPercent x-location / width * 100 diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java index 8a5c8b0898bc..5d3910b4c415 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/LockscreenLockIconController.java @@ -45,6 +45,7 @@ import com.android.systemui.statusbar.KeyguardIndicationController; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator; import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator.WakeUpListener; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.policy.AccessibilityController; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener; @@ -436,6 +437,7 @@ public class LockscreenLockIconController { private boolean handleLongClick(View view) { mLockscreenGestureLogger.write(MetricsProto.MetricsEvent.ACTION_LS_LOCK, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_LOCK_TAP); mKeyguardIndicationController.showTransientIndication( R.string.keyguard_indication_trust_disabled); mKeyguardUpdateMonitor.onLockIconPressed(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java index 26e80adafd3d..8954d98d0201 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java @@ -59,6 +59,7 @@ import android.content.res.Configuration; import android.database.ContentObserver; import android.graphics.PixelFormat; import android.graphics.Rect; +import android.graphics.RectF; import android.hardware.display.DisplayManager; import android.inputmethodservice.InputMethodService; import android.net.Uri; @@ -83,6 +84,7 @@ import android.view.MotionEvent; import android.view.Surface; import android.view.View; import android.view.ViewGroup; +import android.view.ViewTreeObserver; import android.view.WindowInsetsController.Appearance; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; @@ -94,6 +96,8 @@ import androidx.annotation.VisibleForTesting; import com.android.internal.accessibility.dialog.AccessibilityButtonChooserActivity; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEvent; +import com.android.internal.logging.UiEventLogger; import com.android.internal.logging.nano.MetricsProto.MetricsEvent; import com.android.internal.util.LatencyTracker; import com.android.internal.view.AppearanceRegion; @@ -217,11 +221,31 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback * original handle hidden and we'll flip the visibilities once the * {@link #mTasksFrozenListener} fires */ - private NavigationHandle mOrientationHandle; + private VerticalNavigationHandle mOrientationHandle; private WindowManager.LayoutParams mOrientationParams; private int mStartingQuickSwitchRotation; private int mCurrentRotation; private boolean mFixedRotationEnabled; + private ViewTreeObserver.OnGlobalLayoutListener mOrientationHandleGlobalLayoutListener; + private UiEventLogger mUiEventLogger; + + @com.android.internal.annotations.VisibleForTesting + public enum NavBarActionEvent implements UiEventLogger.UiEventEnum { + + @UiEvent(doc = "Assistant invoked via home button long press.") + NAVBAR_ASSIST_LONGPRESS(550); + + private final int mId; + + NavBarActionEvent(int id) { + mId = id; + } + + @Override + public int getId() { + return mId; + } + } /** Only for default display */ @Nullable @@ -364,7 +388,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback ShadeController shadeController, NotificationRemoteInputManager notificationRemoteInputManager, SystemActions systemActions, - @Main Handler mainHandler) { + @Main Handler mainHandler, + UiEventLogger uiEventLogger) { mAccessibilityManagerWrapper = accessibilityManagerWrapper; mDeviceProvisionedController = deviceProvisionedController; mStatusBarStateController = statusBarStateController; @@ -384,6 +409,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback mRecentsOptional = recentsOptional; mSystemActions = systemActions; mHandler = mainHandler; + mUiEventLogger = uiEventLogger; } // ----- Fragment Lifecycle Callbacks ----- @@ -519,6 +545,8 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback getContext().getSystemService(DisplayManager.class).unregisterDisplayListener(this); getBarTransitions().removeDarkIntensityListener(mOrientationHandleIntensityListener); mWindowManager.removeView(mOrientationHandle); + mOrientationHandle.getViewTreeObserver().removeOnGlobalLayoutListener( + mOrientationHandleGlobalLayoutListener); } } @@ -573,6 +601,20 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback PixelFormat.TRANSLUCENT); mWindowManager.addView(mOrientationHandle, mOrientationParams); mOrientationHandle.setVisibility(View.GONE); + mOrientationHandleGlobalLayoutListener = + () -> { + if (mStartingQuickSwitchRotation == -1) { + return; + } + + RectF boundsOnScreen = mOrientationHandle.computeHomeHandleBounds(); + mOrientationHandle.mapRectFromViewToScreenCoords(boundsOnScreen, true); + Rect boundsRounded = new Rect(); + boundsOnScreen.roundOut(boundsRounded); + mNavigationBarView.setOrientedHandleSamplingRegion(boundsRounded); + }; + mOrientationHandle.getViewTreeObserver().addOnGlobalLayoutListener( + mOrientationHandleGlobalLayoutListener); } private void orientSecondaryHomeHandle() { @@ -621,6 +663,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback } if (mNavigationBarView != null) { mNavigationBarView.setVisibility(View.VISIBLE); + mNavigationBarView.setOrientedHandleSamplingRegion(null); } } @@ -988,6 +1031,7 @@ public class NavigationBarFragment extends LifecycleFragment implements Callback return false; } mMetricsLogger.action(MetricsEvent.ACTION_ASSIST_LONG_PRESS); + mUiEventLogger.log(NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS); Bundle args = new Bundle(); args.putInt( AssistManager.INVOCATION_TYPE_KEY, AssistManager.INVOCATION_HOME_BUTTON_LONG_PRESS); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java index 6b37ac317cdd..4821d8c46ed4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java @@ -35,6 +35,7 @@ import android.animation.PropertyValuesHolder; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.DrawableRes; +import android.annotation.Nullable; import android.app.StatusBarManager; import android.content.Context; import android.content.res.Configuration; @@ -158,6 +159,14 @@ public class NavigationBarView extends FrameLayout implements */ private ScreenPinningNotify mScreenPinningNotify; private Rect mSamplingBounds = new Rect(); + /** + * When quickswitching between apps of different orientations, we draw a secondary home handle + * in the position of the first app's orientation. This rect represents the region of that + * home handle so we can apply the correct light/dark luma on that. + * @see {@link NavigationBarFragment#mOrientationHandle} + */ + @Nullable + private Rect mOrientedHandleSamplingRegion; private class NavTransitionListener implements TransitionListener { private boolean mBackTransitioning; @@ -327,6 +336,10 @@ public class NavigationBarView extends FrameLayout implements @Override public Rect getSampledRegion(View sampledView) { + if (mOrientedHandleSamplingRegion != null) { + return mOrientedHandleSamplingRegion; + } + updateSamplingRect(); return mSamplingBounds; } @@ -897,6 +910,11 @@ public class NavigationBarView extends FrameLayout implements } } + void setOrientedHandleSamplingRegion(Rect orientedHandleSamplingRegion) { + mOrientedHandleSamplingRegion = orientedHandleSamplingRegion; + mRegionSamplingHelper.updateSamplingRect(); + } + @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); @@ -1190,6 +1208,8 @@ public class NavigationBarView extends FrameLayout implements mIsVertical ? "true" : "false", getLightTransitionsController().getCurrentDarkIntensity())); + pw.println(" mOrientedHandleSamplingRegion: " + mOrientedHandleSamplingRegion); + dumpButton(pw, "back", getBackButton()); dumpButton(pw, "home", getHomeButton()); dumpButton(pw, "rcnt", getRecentsButton()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java index 8889510cde28..d884bdd47930 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java @@ -104,9 +104,9 @@ import com.android.systemui.statusbar.notification.row.ActivatableNotificationVi import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.ExpandableView; import com.android.systemui.statusbar.notification.stack.AnimationProperties; -import com.android.systemui.statusbar.notification.stack.MediaHeaderView; import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.notification.stack.StackStateAnimator; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.phone.dagger.StatusBarComponent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -2474,6 +2474,8 @@ public class NotificationPanelViewController extends PanelViewController { } else { mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_HINT, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); + mLockscreenGestureLogger + .log(LockscreenUiEvent.LOCKSCREEN_LOCK_SHOW_HINT); startUnlockHintAnimation(); } } @@ -3257,7 +3259,7 @@ public class NotificationPanelViewController extends PanelViewController { int velocityDp = Math.abs((int) (vel / displayDensity)); if (start) { mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_DIALER, lengthDp, velocityDp); - + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_DIALER); mFalsingManager.onLeftAffordanceOn(); if (mFalsingManager.shouldEnforceBouncer()) { mStatusBar.executeRunnableDismissingKeyguard( @@ -3272,6 +3274,7 @@ public class NotificationPanelViewController extends PanelViewController { mLastCameraLaunchSource)) { mLockscreenGestureLogger.write( MetricsEvent.ACTION_LS_CAMERA, lengthDp, velocityDp); + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_CAMERA); } mFalsingManager.onCameraOn(); if (mFalsingManager.shouldEnforceBouncer()) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java index 57d36fcafa15..a902e1b0c960 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelViewController.java @@ -47,6 +47,7 @@ import com.android.systemui.statusbar.FlingAnimationUtils; import com.android.systemui.statusbar.StatusBarState; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.VibratorHelper; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.policy.KeyguardStateController; import java.io.FileDescriptor; @@ -319,6 +320,8 @@ public abstract class PanelViewController { mLockscreenGestureLogger.writeAtFractionalPosition(MetricsEvent.ACTION_PANEL_VIEW_EXPAND, (int) (event.getX() / width * 100), (int) (event.getY() / height * 100), rot); + mLockscreenGestureLogger + .log(LockscreenUiEvent.LOCKSCREEN_UNLOCKED_NOTIFICATION_PANEL_EXPAND); } protected void maybeVibrateOnOpening() { @@ -378,6 +381,7 @@ public abstract class PanelViewController { int heightDp = (int) Math.abs((y - mInitialTouchY) / displayDensity); int velocityDp = (int) Math.abs(vel / displayDensity); mLockscreenGestureLogger.write(MetricsEvent.ACTION_LS_UNLOCK, heightDp, velocityDp); + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_UNLOCK); } fling(vel, expand, isFalseTouch(x, y)); onTrackingStopped(expand); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java index 84da35b63d0a..45f0c49a4fd4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java @@ -72,6 +72,7 @@ import com.android.systemui.statusbar.notification.row.NotificationGutsManager; import com.android.systemui.statusbar.notification.row.NotificationGutsManager.OnSettingsClickListener; import com.android.systemui.statusbar.notification.row.NotificationInfo.CheckSaveListener; import com.android.systemui.statusbar.notification.stack.NotificationListContainer; +import com.android.systemui.statusbar.phone.LockscreenGestureLogger.LockscreenUiEvent; import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.KeyguardStateController; @@ -374,6 +375,7 @@ public class StatusBarNotificationPresenter implements NotificationPresenter, mLockscreenGestureLogger.write( MetricsEvent.ACTION_LS_NOTE, 0 /* lengthDp - N/A */, 0 /* velocityDp - N/A */); + mLockscreenGestureLogger.log(LockscreenUiEvent.LOCKSCREEN_NOTIFICATION_FALSE_TOUCH); mNotificationPanel.showTransientIndication(R.string.notification_tap_again); ActivatableNotificationView previousView = mNotificationPanel.getActivatedChild(); if (previousView != null) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java index a15ca9532a88..0cdf1d32d6a0 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/VerticalNavigationHandle.java @@ -18,12 +18,14 @@ package com.android.systemui.statusbar.phone; import android.content.Context; import android.graphics.Canvas; +import android.graphics.RectF; import com.android.systemui.R; /** Temporarily shown view when using QuickSwitch to switch between apps of different rotations */ public class VerticalNavigationHandle extends NavigationHandle { private final int mWidth; + private final RectF mTmpBoundsRectF = new RectF(); public VerticalNavigationHandle(Context context) { super(context); @@ -32,16 +34,21 @@ public class VerticalNavigationHandle extends NavigationHandle { @Override protected void onDraw(Canvas canvas) { + canvas.drawRoundRect(computeHomeHandleBounds(), mRadius, mRadius, mPaint); + } + + RectF computeHomeHandleBounds() { int left; int top; int bottom; int right; - + int topStart = getLocationOnScreen()[1]; int radiusOffset = mRadius * 2; right = getWidth() - mBottom; - top = getHeight() / 2 - (mWidth / 2); /* (height of screen / 2) - (height of bar / 2) */ + top = getHeight() / 2 - (mWidth / 2) - (topStart / 2); left = getWidth() - mBottom - radiusOffset; - bottom = getHeight() / 2 + (mWidth / 2); - canvas.drawRoundRect(left, top, right, bottom, mRadius, mRadius, mPaint); + bottom = top + mWidth; + mTmpBoundsRectF.set(left, top, right, bottom); + return mTmpBoundsRectF; } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java index 58f5d2a5b43f..0ca8ef009173 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java @@ -87,7 +87,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private boolean mHasOvalBg = false; @VisibleForTesting - public enum NavBarActionsEvent implements UiEventLogger.UiEventEnum { + public enum NavBarButtonEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "The home button was pressed in the navigation bar.") NAVBAR_HOME_BUTTON_TAP(533), @@ -111,7 +111,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private final int mId; - NavBarActionsEvent(int id) { + NavBarButtonEvent(int id) { mId = id; } @@ -368,7 +368,7 @@ public class KeyButtonView extends ImageView implements ButtonInterface { private void logSomePresses(int action, int flags) { boolean longPressSet = (flags & KeyEvent.FLAG_LONG_PRESS) != 0; - NavBarActionsEvent uiEvent = NavBarActionsEvent.NONE; + NavBarButtonEvent uiEvent = NavBarButtonEvent.NONE; if (action == MotionEvent.ACTION_UP && mLongClicked) { return; // don't log the up after a long press } @@ -382,21 +382,21 @@ public class KeyButtonView extends ImageView implements ButtonInterface { switch(mCode) { case KeyEvent.KEYCODE_BACK: uiEvent = longPressSet - ? NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS - : NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP; + ? NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS + : NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP; break; case KeyEvent.KEYCODE_HOME: uiEvent = longPressSet - ? NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS - : NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP; + ? NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS + : NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP; break; case KeyEvent.KEYCODE_APP_SWITCH: uiEvent = longPressSet - ? NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS - : NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP; + ? NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS + : NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP; break; } - if (uiEvent != NavBarActionsEvent.NONE) { + if (uiEvent != NavBarButtonEvent.NONE) { mUiEventLogger.log(uiEvent); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java index df3748a8606b..512d0f3910f8 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcher.java @@ -16,11 +16,15 @@ package com.android.systemui.statusbar.policy; +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_DISABLED_ALPHA; +import static com.android.systemui.statusbar.policy.UserSwitcherController.USER_SWITCH_ENABLED_ALPHA; + import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.content.Context; import android.database.DataSetObserver; +import android.graphics.drawable.BitmapDrawable; import android.graphics.drawable.Drawable; import android.graphics.drawable.LayerDrawable; import android.util.AttributeSet; @@ -46,8 +50,6 @@ public class KeyguardUserSwitcher { private static final String TAG = "KeyguardUserSwitcher"; private static final boolean ALWAYS_ON = false; - private static final float USER_SWITCH_ENABLED_ALPHA = 1.0f; - private static final float USER_SWITCH_DISABLED_ALPHA = 0.38f; private final Container mUserSwitcherContainer; private final KeyguardStatusBarView mStatusBarView; @@ -286,27 +288,34 @@ public class KeyguardUserSwitcher { if (item.picture == null) { v.bind(name, getDrawable(mContext, item).mutate(), item.resolveId()); } else { - v.bind(name, item.picture, item.info.id); + Drawable drawable = new BitmapDrawable(v.getResources(), item.picture); + drawable.setColorFilter( + item.isSwitchToEnabled ? null : getDisabledUserAvatarColorFilter()); + v.bind(name, drawable, item.info.id); } - // Disable the icon if switching is disabled - v.setAvatarEnabled(item.isSwitchToEnabled); - convertView.setActivated(item.isCurrent); + v.setActivated(item.isCurrent); + v.setDisabledByAdmin(item.isDisabledByAdmin); + v.setEnabled(item.isSwitchToEnabled); + v.setAlpha(v.isEnabled() ? USER_SWITCH_ENABLED_ALPHA : USER_SWITCH_DISABLED_ALPHA); + if (item.isCurrent) { - mCurrentUserView = convertView; + mCurrentUserView = v; } - convertView.setTag(item); - convertView.setAlpha( - item.isCurrent || item.isSwitchToEnabled ? USER_SWITCH_ENABLED_ALPHA - : USER_SWITCH_DISABLED_ALPHA); - convertView.setEnabled(item.isSwitchToEnabled); - return convertView; + v.setTag(item); + return v; } private static Drawable getDrawable(Context context, UserSwitcherController.UserRecord item) { Drawable drawable = getIconDrawable(context, item); - int iconColorRes = item.isCurrent ? R.color.kg_user_switcher_selected_avatar_icon_color - : R.color.kg_user_switcher_avatar_icon_color; + int iconColorRes; + if (item.isCurrent) { + iconColorRes = R.color.kg_user_switcher_selected_avatar_icon_color; + } else if (!item.isSwitchToEnabled) { + iconColorRes = R.color.GM2_grey_600; + } else { + iconColorRes = R.color.kg_user_switcher_avatar_icon_color; + } drawable.setTint(context.getResources().getColor(iconColorRes, context.getTheme())); if (item.isCurrent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java index db00770f0638..270f248e1a34 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -31,6 +31,9 @@ import android.content.IntentFilter; import android.content.pm.UserInfo; import android.database.ContentObserver; import android.graphics.Bitmap; +import android.graphics.ColorFilter; +import android.graphics.ColorMatrix; +import android.graphics.ColorMatrixColorFilter; import android.graphics.drawable.Drawable; import android.os.AsyncTask; import android.os.Handler; @@ -81,6 +84,9 @@ import javax.inject.Singleton; @Singleton public class UserSwitcherController implements Dumpable { + public static final float USER_SWITCH_ENABLED_ALPHA = 1.0f; + public static final float USER_SWITCH_DISABLED_ALPHA = 0.38f; + private static final String TAG = "UserSwitcherController"; private static final boolean DEBUG = false; private static final String SIMPLE_USER_SWITCHER_GLOBAL_SETTING = @@ -674,6 +680,12 @@ public class UserSwitcherController implements Dumpable { } } + protected static ColorFilter getDisabledUserAvatarColorFilter() { + ColorMatrix matrix = new ColorMatrix(); + matrix.setSaturation(0f); // 0 - grayscale + return new ColorMatrixColorFilter(matrix); + } + protected static Drawable getIconDrawable(Context context, UserRecord item) { int iconRes; if (item.isAddUser) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java index 914868301d72..8b85a0961463 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/micdisclosure/AudioRecordingDisclosureBar.java @@ -29,6 +29,8 @@ import android.content.Context; import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.graphics.PixelFormat; +import android.provider.Settings; +import android.text.TextUtils; import android.util.ArraySet; import android.util.Log; import android.view.Gravity; @@ -63,6 +65,9 @@ public class AudioRecordingDisclosureBar implements // CtsSystemUiHostTestCases:TvMicrophoneCaptureIndicatorTest private static final String LAYOUT_PARAMS_TITLE = "MicrophoneCaptureIndicator"; + private static final String EXEMPT_PACKAGES_LIST = "sysui_mic_disclosure_exempt"; + private static final String FORCED_PACKAGES_LIST = "sysui_mic_disclosure_forced"; + @Retention(RetentionPolicy.SOURCE) @IntDef(prefix = {"STATE_"}, value = { STATE_NOT_SHOWN, @@ -134,6 +139,8 @@ public class AudioRecordingDisclosureBar implements mExemptPackages = new ArraySet<>( Arrays.asList(mContext.getResources().getStringArray( R.array.audio_recording_disclosure_exempt_apps))); + mExemptPackages.addAll(Arrays.asList(getGlobalStringArray(EXEMPT_PACKAGES_LIST))); + mExemptPackages.removeAll(Arrays.asList(getGlobalStringArray(FORCED_PACKAGES_LIST))); mAudioActivityObservers = new AudioActivityObserver[]{ new RecordAudioAppOpObserver(mContext, this), @@ -141,6 +148,11 @@ public class AudioRecordingDisclosureBar implements }; } + private String[] getGlobalStringArray(String setting) { + String result = Settings.Global.getString(mContext.getContentResolver(), setting); + return TextUtils.isEmpty(result) ? new String[0] : result.split(","); + } + @UiThread @Override public void onAudioActivityStateChange(boolean active, String packageName) { diff --git a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt index e905e6772074..5a2b064c5389 100644 --- a/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt +++ b/packages/SystemUI/src/com/android/systemui/util/magnetictarget/MagnetizedObject.kt @@ -32,6 +32,7 @@ import androidx.dynamicanimation.animation.DynamicAnimation import androidx.dynamicanimation.animation.FloatPropertyCompat import androidx.dynamicanimation.animation.SpringForce import com.android.systemui.util.animation.PhysicsAnimator +import kotlin.math.abs import kotlin.math.hypot /** @@ -231,11 +232,11 @@ abstract class MagnetizedObject<T : Any>( var flingUnstuckFromTargetMinVelocity = 1000f /** - * Sets the maximum velocity above which the object will not stick to the target. Even if the + * Sets the maximum X velocity above which the object will not stick to the target. Even if the * object is dragged through the magnetic field, it will not stick to the target until the - * velocity is below this value. + * horizontal velocity is below this value. */ - var stickToTargetMaxVelocity = 2000f + var stickToTargetMaxXVelocity = 2000f /** * Enable or disable haptic vibration effects when the object interacts with the magnetic field. @@ -245,9 +246,6 @@ abstract class MagnetizedObject<T : Any>( */ var hapticsEnabled = true - /** Whether the HAPTIC_FEEDBACK_ENABLED setting is true. */ - private var systemHapticsEnabled = false - /** Default spring configuration to use for animating the object into a target. */ var springConfig = PhysicsAnimator.SpringConfig( SpringForce.STIFFNESS_MEDIUM, SpringForce.DAMPING_RATIO_NO_BOUNCY) @@ -259,24 +257,7 @@ abstract class MagnetizedObject<T : Any>( var flungIntoTargetSpringConfig = springConfig init { - val hapticSettingObserver = - object : ContentObserver(Handler.getMain()) { - override fun onChange(selfChange: Boolean) { - systemHapticsEnabled = - Settings.System.getIntForUser( - context.contentResolver, - Settings.System.HAPTIC_FEEDBACK_ENABLED, - 0, - UserHandle.USER_CURRENT) != 0 - } - } - - context.contentResolver.registerContentObserver( - Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), - true /* notifyForDescendants */, hapticSettingObserver) - - // Trigger the observer once to initialize systemHapticsEnabled. - hapticSettingObserver.onChange(false /* selfChange */) + initHapticSettingObserver(context) } /** @@ -383,7 +364,7 @@ abstract class MagnetizedObject<T : Any>( // If the object is moving too quickly within the magnetic field, do not stick it. This // only applies to objects newly stuck to a target. If the object is moved into a new // target, it wasn't moving at all (since it was stuck to the previous one). - if (objectNewlyStuckToTarget && hypot(velX, velY) > stickToTargetMaxVelocity) { + if (objectNewlyStuckToTarget && abs(velX) > stickToTargetMaxXVelocity) { return false } @@ -623,6 +604,43 @@ abstract class MagnetizedObject<T : Any>( companion object { /** + * Whether the HAPTIC_FEEDBACK_ENABLED setting is true. + * + * We put it in the companion object because we need to register a settings observer and + * [MagnetizedObject] doesn't have an obvious lifecycle so we don't have a good time to + * remove that observer. Since this settings is shared among all instances we just let all + * instances read from this value. + */ + private var systemHapticsEnabled = false + private var hapticSettingObserverInitialized = false + + private fun initHapticSettingObserver(context: Context) { + if (hapticSettingObserverInitialized) { + return + } + + val hapticSettingObserver = + object : ContentObserver(Handler.getMain()) { + override fun onChange(selfChange: Boolean) { + systemHapticsEnabled = + Settings.System.getIntForUser( + context.contentResolver, + Settings.System.HAPTIC_FEEDBACK_ENABLED, + 0, + UserHandle.USER_CURRENT) != 0 + } + } + + context.contentResolver.registerContentObserver( + Settings.System.getUriFor(Settings.System.HAPTIC_FEEDBACK_ENABLED), + true /* notifyForDescendants */, hapticSettingObserver) + + // Trigger the observer once to initialize systemHapticsEnabled. + hapticSettingObserver.onChange(false /* selfChange */) + hapticSettingObserverInitialized = true + } + + /** * Magnetizes the given view. Magnetized views are attracted to one or more magnetic * targets. Magnetic targets attract objects that are dragged near them, and hold them there * unless they're moved away or released. Releasing objects inside a magnetic target diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java index 74d0610ee0d6..29d7a524dd8b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthContainerViewTest.java @@ -45,6 +45,7 @@ import android.testing.TestableLooper.RunWithLooper; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; +import android.view.WindowInsets; import android.view.WindowManager; import android.widget.FrameLayout; import android.widget.ImageView; @@ -210,6 +211,14 @@ public class AuthContainerViewTest extends SysuiTestCase { assertTrue((layoutParams.flags & WindowManager.LayoutParams.FLAG_SECURE) != 0); } + @Test + public void testLayoutParams_excludesImeInsets() { + final IBinder windowToken = mock(IBinder.class); + final WindowManager.LayoutParams layoutParams = + AuthContainerView.getLayoutParams(windowToken); + assertTrue((layoutParams.getFitInsetsTypes() & WindowInsets.Type.ime()) == 0); + } + private void initializeContainer(int authenticators) { AuthContainerView.Config config = new AuthContainerView.Config(); config.mContext = mContext; diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java index c89f6c2597d0..472b121f7b95 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -44,7 +44,6 @@ import android.app.IActivityManager; import android.app.INotificationManager; import android.app.Notification; import android.app.PendingIntent; -import android.content.res.Resources; import android.hardware.display.AmbientDisplayConfiguration; import android.hardware.face.FaceManager; import android.os.Handler; @@ -59,7 +58,7 @@ import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; -import com.android.systemui.SystemUIFactory; +import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -70,20 +69,16 @@ import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.NotificationRemoveInterceptor; import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryListener; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; -import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; import com.android.systemui.statusbar.phone.DozeParameters; import com.android.systemui.statusbar.phone.KeyguardBypassController; -import com.android.systemui.statusbar.phone.LockscreenLockIconController; import com.android.systemui.statusbar.phone.NotificationGroupManager; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; @@ -93,7 +88,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; -import com.android.systemui.util.InjectionInflationController; import com.google.common.collect.ImmutableList; @@ -173,23 +167,18 @@ public class BubbleControllerTest extends SysuiTestCase { @Mock ColorExtractor.GradientColors mGradientColors; @Mock - private Resources mResources; - @Mock private ShadeController mShadeController; @Mock - private NotificationRowComponent mNotificationRowComponent; - @Mock private NotifPipeline mNotifPipeline; @Mock private FeatureFlags mFeatureFlagsOldPipeline; @Mock private DumpManager mDumpManager; @Mock - private LockscreenLockIconController mLockIconController; - @Mock private NotificationShadeWindowView mNotificationShadeWindowView; + @Mock + private IStatusBarService mStatusBarService; - private SuperStatusBarViewFactory mSuperStatusBarViewFactory; private BubbleData mBubbleData; private TestableLooper mTestableLooper; @@ -203,23 +192,6 @@ public class BubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); - mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), - new NotificationRowComponent.Builder() { - @Override - public NotificationRowComponent.Builder activatableNotificationView( - ActivatableNotificationView view) { - return this; - } - - @Override - public NotificationRowComponent build() { - return mNotificationRowComponent; - } - }, - mLockIconController); - - // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, mConfigurationController, mKeyguardBypassController, mColorExtractor, @@ -282,6 +254,7 @@ public class BubbleControllerTest extends SysuiTestCase { mDataRepository, mSysUiState, mock(INotificationManager.class), + mStatusBarService, mWindowManager); mBubbleController.setExpandListener(mBubbleExpandListener); @@ -327,7 +300,7 @@ public class BubbleControllerTest extends SysuiTestCase { } @Test - public void testPromoteBubble_autoExpand() { + public void testPromoteBubble_autoExpand() throws Exception { mBubbleController.updateBubble(mRow2.getEntry()); mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.removeBubble( @@ -337,13 +310,19 @@ public class BubbleControllerTest extends SysuiTestCase { assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b)); verify(mNotificationEntryManager, never()).performRemoveNotification( eq(mRow.getEntry().getSbn()), anyInt()); - assertFalse(mRow.getEntry().isBubble()); + assertThat(mRow.getEntry().isBubble()).isFalse(); Bubble b2 = mBubbleData.getBubbleInStackWithKey(mRow2.getEntry().getKey()); assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b2); mBubbleController.promoteBubbleFromOverflow(b); - assertThat(mBubbleData.getSelectedBubble()).isEqualTo(b); + + assertThat(b.isBubble()).isTrue(); + assertThat(b.shouldAutoExpand()).isTrue(); + int flags = Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE + | Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION; + verify(mStatusBarService, times(1)).onNotificationBubbleChanged( + eq(b.getKey()), eq(true), eq(flags)); } @Test diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java index 8224c88e6c75..17022da3ecde 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java @@ -278,7 +278,7 @@ public class BubbleDataTest extends SysuiTestCase { assertBubbleRemoved(mBubbleA1, BubbleController.DISMISS_AGED); assertOverflowChangedTo(ImmutableList.of(mBubbleA1)); - Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1); + Bubble bubbleA1 = mBubbleData.getOrCreateBubble(mEntryA1, null /* persistedBubble */); bubbleA1.markUpdatedAt(7000L); mBubbleData.notificationEntryUpdated(bubbleA1, false /* suppressFlyout*/, true /* showInShade */); @@ -890,7 +890,7 @@ public class BubbleDataTest extends SysuiTestCase { private void sendUpdatedEntryAtTime(NotificationEntry entry, long postTime) { setPostTime(entry, postTime); // BubbleController calls this: - Bubble b = mBubbleData.getOrCreateBubble(entry); + Bubble b = mBubbleData.getOrCreateBubble(entry, null /* persistedBubble */); // And then this mBubbleData.notificationEntryUpdated(b, false /* suppressFlyout*/, true /* showInShade */); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java index ead95ca1665e..47cd9bca2861 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -55,7 +55,7 @@ import android.view.WindowManager; import androidx.test.filters.SmallTest; import com.android.internal.colorextraction.ColorExtractor; -import com.android.systemui.SystemUIFactory; +import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.SysuiTestCase; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.dump.DumpManager; @@ -64,14 +64,12 @@ import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.FeatureFlags; import com.android.systemui.statusbar.NotificationLockscreenUserManager; import com.android.systemui.statusbar.RankingBuilder; -import com.android.systemui.statusbar.SuperStatusBarViewFactory; import com.android.systemui.statusbar.SysuiStatusBarStateController; import com.android.systemui.statusbar.notification.NotificationEntryManager; import com.android.systemui.statusbar.notification.NotificationFilter; import com.android.systemui.statusbar.notification.collection.NotifPipeline; import com.android.systemui.statusbar.notification.collection.NotificationEntry; import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener; -import com.android.systemui.statusbar.notification.row.ActivatableNotificationView; import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow; import com.android.systemui.statusbar.notification.row.NotificationTestHelper; import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent; @@ -87,7 +85,6 @@ import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.HeadsUpManager; import com.android.systemui.statusbar.policy.ZenModeController; import com.android.systemui.util.FloatingContentCoordinator; -import com.android.systemui.util.InjectionInflationController; import org.junit.Before; import org.junit.Test; @@ -174,8 +171,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { private DumpManager mDumpManager; @Mock private LockscreenLockIconController mLockIconController; + @Mock + private IStatusBarService mStatusBarService; - private SuperStatusBarViewFactory mSuperStatusBarViewFactory; private BubbleData mBubbleData; private TestableLooper mTestableLooper; @@ -189,22 +187,6 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mContext.addMockSystemService(FaceManager.class, mFaceManager); when(mColorExtractor.getNeutralColors()).thenReturn(mGradientColors); - mSuperStatusBarViewFactory = new SuperStatusBarViewFactory(mContext, - new InjectionInflationController(SystemUIFactory.getInstance().getRootComponent()), - new NotificationRowComponent.Builder() { - @Override - public NotificationRowComponent.Builder activatableNotificationView( - ActivatableNotificationView view) { - return this; - } - - @Override - public NotificationRowComponent build() { - return mNotificationRowComponent; - } - }, - mLockIconController); - // Bubbles get added to status bar window view mNotificationShadeWindowController = new NotificationShadeWindowController(mContext, mWindowManager, mActivityManager, mDozeParameters, mStatusBarStateController, @@ -257,6 +239,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mDataRepository, mSysUiState, mock(INotificationManager.class), + mStatusBarService, mWindowManager); mBubbleController.addNotifCallback(mNotifCallback); mBubbleController.setExpandListener(mBubbleExpandListener); diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java index bdb79449ea2a..ab49134ee8c0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/TestableBubbleController.java @@ -20,6 +20,7 @@ import android.app.INotificationManager; import android.content.Context; import android.view.WindowManager; +import com.android.internal.statusbar.IStatusBarService; import com.android.systemui.dump.DumpManager; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -59,13 +60,14 @@ public class TestableBubbleController extends BubbleController { BubbleDataRepository dataRepository, SysUiState sysUiState, INotificationManager notificationManager, + IStatusBarService statusBarService, WindowManager windowManager) { super(context, notificationShadeWindowController, statusBarStateController, shadeController, data, Runnable::run, configurationController, interruptionStateProvider, zenModeController, lockscreenUserManager, groupManager, entryManager, notifPipeline, featureFlags, dumpManager, floatingContentCoordinator, - dataRepository, sysUiState, notificationManager, + dataRepository, sysUiState, notificationManager, statusBarService, windowManager); setInflateSynchronously(true); } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java index 536cae4380c4..b7a2633d0d36 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipAnimationControllerTest.java @@ -82,7 +82,7 @@ public class PipAnimationControllerTest extends SysuiTestCase { @Test public void getAnimator_withBounds_returnBoundsAnimator() { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController - .getAnimator(mLeash, new Rect(), new Rect(), null); + .getAnimator(mLeash, new Rect(), new Rect()); assertEquals("Expect ANIM_TYPE_BOUNDS animation", animator.getAnimationType(), PipAnimationController.ANIM_TYPE_BOUNDS); @@ -94,12 +94,12 @@ public class PipAnimationControllerTest extends SysuiTestCase { final Rect endValue1 = new Rect(100, 100, 200, 200); final Rect endValue2 = new Rect(200, 200, 300, 300); final PipAnimationController.PipTransitionAnimator oldAnimator = mPipAnimationController - .getAnimator(mLeash, startValue, endValue1, null); + .getAnimator(mLeash, startValue, endValue1); oldAnimator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new); oldAnimator.start(); final PipAnimationController.PipTransitionAnimator newAnimator = mPipAnimationController - .getAnimator(mLeash, startValue, endValue2, null); + .getAnimator(mLeash, startValue, endValue2); assertEquals("getAnimator with same type returns same animator", oldAnimator, newAnimator); @@ -129,7 +129,7 @@ public class PipAnimationControllerTest extends SysuiTestCase { final Rect endValue1 = new Rect(100, 100, 200, 200); final Rect endValue2 = new Rect(200, 200, 300, 300); final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController - .getAnimator(mLeash, startValue, endValue1, null); + .getAnimator(mLeash, startValue, endValue1); animator.updateEndValue(endValue2); @@ -141,7 +141,7 @@ public class PipAnimationControllerTest extends SysuiTestCase { final Rect startValue = new Rect(0, 0, 100, 100); final Rect endValue = new Rect(100, 100, 200, 200); final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController - .getAnimator(mLeash, startValue, endValue, null); + .getAnimator(mLeash, startValue, endValue); animator.setSurfaceControlTransactionFactory(DummySurfaceControlTx::new); animator.setPipAnimationCallback(mPipAnimationCallback); diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java index 8a8d2272d563..e5024595d97e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/ScreenRecordTileTest.java @@ -29,6 +29,7 @@ import android.testing.TestableLooper; import androidx.test.filters.SmallTest; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -53,6 +54,8 @@ public class ScreenRecordTileTest extends SysuiTestCase { private ActivityStarter mActivityStarter; @Mock private QSTileHost mHost; + @Mock + private UiEventLogger mUiEventLogger; private TestableLooper mTestableLooper; private ScreenRecordTile mTile; @@ -68,7 +71,7 @@ public class ScreenRecordTileTest extends SysuiTestCase { when(mHost.getContext()).thenReturn(mContext); - mTile = new ScreenRecordTile(mHost, mController, mActivityStarter); + mTile = new ScreenRecordTile(mHost, mController, mActivityStarter, mUiEventLogger); } // Test that the tile is inactive and labeled correctly when the controller is neither starting diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java new file mode 100644 index 000000000000..283a47ca3622 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/screenrecord/RecordingServiceTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.screenrecord; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Intent; +import android.testing.AndroidTestingRunner; + +import androidx.test.filters.SmallTest; + +import com.android.internal.logging.UiEventLogger; +import com.android.systemui.SysuiTestCase; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; + +import java.util.concurrent.Executor; + +@RunWith(AndroidTestingRunner.class) +@SmallTest +public class RecordingServiceTest extends SysuiTestCase { + + @Mock + private UiEventLogger mUiEventLogger; + @Mock + private RecordingController mController; + @Mock + private NotificationManager mNotificationManager; + @Mock + private ScreenMediaRecorder mScreenMediaRecorder; + @Mock + private Notification mNotification; + @Mock + private Executor mExecutor; + + private RecordingService mRecordingService; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + mRecordingService = Mockito.spy(new RecordingService(mController, mExecutor, mUiEventLogger, + mNotificationManager)); + + // Return actual context info + doReturn(mContext).when(mRecordingService).getApplicationContext(); + doReturn(mContext.getUserId()).when(mRecordingService).getUserId(); + doReturn(mContext.getPackageName()).when(mRecordingService).getPackageName(); + doReturn(mContext.getContentResolver()).when(mRecordingService).getContentResolver(); + + // Mock notifications + doNothing().when(mRecordingService).createRecordingNotification(); + doReturn(mNotification).when(mRecordingService).createProcessingNotification(); + doReturn(mNotification).when(mRecordingService).createSaveNotification(any()); + + doNothing().when(mRecordingService).startForeground(anyInt(), any()); + doReturn(mScreenMediaRecorder).when(mRecordingService).getRecorder(); + } + + @Test + public void testLogStartRecording() { + Intent startIntent = RecordingService.getStartIntent(mContext, 0, 0, false); + mRecordingService.onStartCommand(startIntent, 0, 0); + + verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_START); + } + + @Test + public void testLogStopFromQsTile() { + Intent stopIntent = RecordingService.getStopIntent(mContext); + mRecordingService.onStartCommand(stopIntent, 0, 0); + + // Verify that we log the correct event + verify(mUiEventLogger, times(1)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE); + verify(mUiEventLogger, times(0)) + .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION); + } + + @Test + public void testLogStopFromNotificationIntent() { + Intent stopIntent = RecordingService.getNotificationIntent(mContext); + mRecordingService.onStartCommand(stopIntent, 0, 0); + + // Verify that we log the correct event + verify(mUiEventLogger, times(1)) + .log(Events.ScreenRecordEvent.SCREEN_RECORD_END_NOTIFICATION); + verify(mUiEventLogger, times(0)).log(Events.ScreenRecordEvent.SCREEN_RECORD_END_QS_TILE); + } +} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java index 78e9b336f79a..2b12c22cae39 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/HighPriorityProviderTest.java @@ -38,6 +38,7 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.statusbar.RankingBuilder; import com.android.systemui.statusbar.notification.collection.provider.HighPriorityProvider; import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import org.junit.Before; import org.junit.Test; @@ -45,16 +46,22 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; +import java.util.Arrays; + @SmallTest @RunWith(AndroidTestingRunner.class) public class HighPriorityProviderTest extends SysuiTestCase { @Mock private PeopleNotificationIdentifier mPeopleNotificationIdentifier; + @Mock private NotificationGroupManager mGroupManager; private HighPriorityProvider mHighPriorityProvider; @Before public void setup() { MockitoAnnotations.initMocks(this); - mHighPriorityProvider = new HighPriorityProvider(mPeopleNotificationIdentifier); + mHighPriorityProvider = new HighPriorityProvider( + mPeopleNotificationIdentifier, + mGroupManager); } @Test @@ -166,6 +173,22 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test + public void testIsHighPriority_checkChildrenToCalculatePriority() { + // GIVEN: a summary with low priority has a highPriorityChild and a lowPriorityChild + final NotificationEntry summary = createNotifEntry(false); + final NotificationEntry lowPriorityChild = createNotifEntry(false); + final NotificationEntry highPriorityChild = createNotifEntry(true); + when(mGroupManager.isGroupSummary(summary.getSbn())).thenReturn(true); + when(mGroupManager.getChildren(summary.getSbn())).thenReturn( + new ArrayList<>(Arrays.asList(lowPriorityChild, highPriorityChild))); + + // THEN the summary is high priority since it has a high priority child + assertTrue(mHighPriorityProvider.isHighPriority(summary)); + } + + // Tests below here are only relevant to the NEW notification pipeline which uses GroupEntry + + @Test public void testIsHighPriority_summaryUpdated() { // GIVEN a GroupEntry with a lowPrioritySummary and no children final GroupEntry parentEntry = new GroupEntry("test_group_key"); @@ -186,7 +209,7 @@ public class HighPriorityProviderTest extends SysuiTestCase { } @Test - public void testIsHighPriority_checkChildrenToCalculatePriority() { + public void testIsHighPriority_checkChildrenToCalculatePriorityOf() { // GIVEN: // GroupEntry = parentEntry, summary = lowPrioritySummary // NotificationEntry = lowPriorityChild diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt index 1c47131e2e86..82a7774b4d82 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotificationRankingManagerTest.kt @@ -77,7 +77,8 @@ class NotificationRankingManagerTest : SysuiTestCase() { mock(NotificationEntryManagerLogger::class.java), sectionsManager, personNotificationIdentifier, - HighPriorityProvider(personNotificationIdentifier) + HighPriorityProvider(personNotificationIdentifier, + mock(NotificationGroupManager::class.java)) ) } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java index f327967ebd73..43aa8fef76a9 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/PartialConversationInfoTest.java @@ -25,6 +25,7 @@ import static android.view.View.VISIBLE; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.anyObject; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyBoolean; import static org.mockito.Mockito.anyInt; @@ -162,6 +163,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { @Test public void testBindNotification_SetsName() { + when(mMockPackageManager.getApplicationLabel(any())).thenReturn("Package"); mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, @@ -174,42 +176,13 @@ public class PartialConversationInfoTest extends SysuiTestCase { true, false); final TextView textView = mInfo.findViewById(R.id.name); - assertTrue(textView.getText().toString().contains("title")); + assertTrue(textView.getText().toString().equals("Package")); } - @Test - public void testBindNotification_groupSetsPackageIcon() { - mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, true); - final Drawable iconDrawable = mock(Drawable.class); - when(mMockPackageManager.getApplicationIcon(any(ApplicationInfo.class))) - .thenReturn(iconDrawable); - mInfo.bindNotification( - mMockPackageManager, - mMockINotificationManager, - mChannelEditorDialogController, - TEST_PACKAGE_NAME, - mNotificationChannel, - mNotificationChannelSet, - mEntry, - null, - true, - false); - final ImageView iconView = mInfo.findViewById(R.id.conversation_icon); - assertEquals(iconDrawable, iconView.getDrawable()); - } @Test - public void testBindNotification_notGroupSetsMessageIcon() { - Notification n = new Notification.Builder(mContext, TEST_CHANNEL_NAME) - .setStyle(new Notification.MessagingStyle( - new Person.Builder().setName("me").build()) - .addMessage(new Notification.MessagingStyle.Message("hello", 0, - new Person.Builder().setName("friend").setIcon(mIcon).build()))) - .build(); - mSbn = new StatusBarNotification(TEST_PACKAGE_NAME, TEST_PACKAGE_NAME, 0, null, TEST_UID, 0, - n, UserHandle.CURRENT, null, 0); - mEntry.setSbn(mSbn); - mEntry.getSbn().getNotification().extras.putBoolean(EXTRA_IS_GROUP_CONVERSATION, false); + public void testBindNotification_setsIcon() { + when(mMockPackageManager.getApplicationIcon((ApplicationInfo) any())).thenReturn(mDrawable); mInfo.bindNotification( mMockPackageManager, mMockINotificationManager, @@ -221,7 +194,7 @@ public class PartialConversationInfoTest extends SysuiTestCase { null, true, false); - final ImageView iconView = mInfo.findViewById(R.id.conversation_icon); + final ImageView iconView = mInfo.findViewById(R.id.icon); assertEquals(mDrawable.hashCode() + "", mDrawable, iconView.getDrawable()); } @@ -270,64 +243,6 @@ public class PartialConversationInfoTest extends SysuiTestCase { } @Test - public void testBindNotification_GroupNameHiddenIfNoGroup() throws Exception { - mInfo.bindNotification( - mMockPackageManager, - mMockINotificationManager, - mChannelEditorDialogController, - TEST_PACKAGE_NAME, - mNotificationChannel, - mNotificationChannelSet, - mEntry, - null, - true, - false); - final TextView groupNameView = mInfo.findViewById(R.id.group_name); - assertEquals(GONE, groupNameView.getVisibility()); - } - - @Test - public void testBindNotification_SetsGroupNameIfNonNull() throws Exception { - mNotificationChannel.setGroup("test_group_id"); - final NotificationChannelGroup notificationChannelGroup = - new NotificationChannelGroup("test_group_id", "Test Group Name"); - when(mMockINotificationManager.getNotificationChannelGroupForPackage( - eq("test_group_id"), eq(TEST_PACKAGE_NAME), eq(TEST_UID))) - .thenReturn(notificationChannelGroup); - mInfo.bindNotification( - mMockPackageManager, - mMockINotificationManager, - mChannelEditorDialogController, - TEST_PACKAGE_NAME, - mNotificationChannel, - mNotificationChannelSet, - mEntry, - null, - true, - false); - final TextView groupNameView = mInfo.findViewById(R.id.group_name); - assertEquals(View.VISIBLE, groupNameView.getVisibility()); - assertEquals("Test Group Name", groupNameView.getText()); - } - - @Test - public void testBindNotification_SetsTextChannelName() { - mInfo.bindNotification( - mMockPackageManager, - mMockINotificationManager, - mChannelEditorDialogController, - TEST_PACKAGE_NAME, - mNotificationChannel, - mNotificationChannelSet, - mEntry, - null, - true, - false); - final TextView textView = mInfo.findViewById(R.id.parent_channel_name); - assertEquals(TEST_CHANNEL_NAME, textView.getText()); - } - - @Test public void testBindNotification_SetsOnClickListenerForSettings() { final CountDownLatch latch = new CountDownLatch(1); mInfo.bindNotification( diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java index a77f8c649f30..00cbddc87726 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NavigationBarFragmentTest.java @@ -21,6 +21,8 @@ import static android.inputmethodservice.InputMethodService.IME_VISIBLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DisplayAdjustments.DEFAULT_DISPLAY_ADJUSTMENTS; +import static com.android.systemui.statusbar.phone.NavigationBarFragment.NavBarActionEvent.NAVBAR_ASSIST_LONGPRESS; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; @@ -28,6 +30,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -59,6 +62,7 @@ import android.view.accessibility.AccessibilityManager.AccessibilityServicesStat import androidx.test.filters.SmallTest; import com.android.internal.logging.MetricsLogger; +import com.android.internal.logging.UiEventLogger; import com.android.systemui.Dependency; import com.android.systemui.SysuiBaseFragmentTest; import com.android.systemui.SysuiTestableContext; @@ -105,6 +109,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { private Recents mRecents; @Mock private SystemActions mSystemActions; + @Mock + private UiEventLogger mUiEventLogger; private AccessibilityManagerWrapper mAccessibilityWrapper = new AccessibilityManagerWrapper(mContext) { @@ -187,6 +193,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { mFragments.dispatchResume(); processAllMessages(); navigationBarFragment.onHomeLongClick(navigationBarFragment.getView()); + + verify(mUiEventLogger, times(1)).log(NAVBAR_ASSIST_LONGPRESS); } @Test @@ -242,6 +250,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { protected Fragment instantiate(Context context, String className, Bundle arguments) { DeviceProvisionedController deviceProvisionedController = mock(DeviceProvisionedController.class); + when(deviceProvisionedController.isDeviceProvisioned()).thenReturn(true); assertNotNull(mAccessibilityWrapper); return new NavigationBarFragment( context.getDisplayId() == DEFAULT_DISPLAY ? mAccessibilityWrapper @@ -261,7 +270,8 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { mock(ShadeController.class), mock(NotificationRemoteInputManager.class), mock(SystemActions.class), - mHandler); + mHandler, + mUiEventLogger); } private class HostCallbacksForExternalDisplay extends @@ -319,6 +329,7 @@ public class NavigationBarFragmentTest extends SysuiBaseFragmentTest { mock(LightBarTransitionsController.class)); when(view.getRotationButtonController()).thenReturn( mock(RotationButtonController.class)); + when(view.isRecentsButtonVisible()).thenReturn(true); return view; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java index 5e9d592ab773..d52d6860bf42 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyButtonViewTest.java @@ -23,12 +23,12 @@ import static android.view.KeyEvent.KEYCODE_APP_SWITCH; import static android.view.KeyEvent.KEYCODE_BACK; import static android.view.KeyEvent.KEYCODE_HOME; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_BACK_BUTTON_TAP; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_HOME_BUTTON_TAP; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS; -import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarActionsEvent.NAVBAR_OVERVIEW_BUTTON_TAP; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_LONGPRESS; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_BACK_BUTTON_TAP; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_LONGPRESS; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_HOME_BUTTON_TAP; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_LONGPRESS; +import static com.android.systemui.statusbar.policy.KeyButtonView.NavBarButtonEvent.NAVBAR_OVERVIEW_BUTTON_TAP; import static junit.framework.Assert.assertEquals; @@ -140,11 +140,11 @@ public class KeyButtonViewTest extends SysuiTestCase { } private void checkmetrics(int code, int action, int flag, - KeyButtonView.NavBarActionsEvent expected) { + KeyButtonView.NavBarButtonEvent expected) { mKeyButtonView.setCode(code); mKeyButtonView.sendEvent(action, flag); if (expected == null) { - verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarActionsEvent.class)); + verify(mUiEventLogger, never()).log(any(KeyButtonView.NavBarButtonEvent.class)); } else { verify(mUiEventLogger, times(1)).log(expected); } diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index d07a70c1af9b..32e2b04e8e4f 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -25,7 +25,7 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-V3-java", + "netd_aidl_interface-java", "netlink-client", "networkstack-aidl-interfaces-java", "android.hardware.tetheroffload.config-V1.0-java", diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 3fd9ee9a330b..1671dda4bd57 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -33,7 +33,6 @@ import android.net.LinkAddress; import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; -import android.net.TetherOffloadRuleParcel; import android.net.TetheredClient; import android.net.TetheringManager; import android.net.TetheringRequestParcel; @@ -65,6 +64,8 @@ import androidx.annotation.Nullable; import com.android.internal.util.MessageUtils; import com.android.internal.util.State; import com.android.internal.util.StateMachine; +import com.android.networkstack.tethering.BpfCoordinator; +import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; import java.io.IOException; @@ -76,7 +77,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; import java.util.Random; @@ -225,6 +225,8 @@ public class IpServer extends StateMachine { private final SharedLog mLog; private final INetd mNetd; + @NonNull + private final BpfCoordinator mBpfCoordinator; private final Callback mCallback; private final InterfaceController mInterfaceCtrl; private final PrivateAddressCoordinator mPrivateAddressCoordinator; @@ -269,43 +271,6 @@ public class IpServer extends StateMachine { } } - static class Ipv6ForwardingRule { - public final int upstreamIfindex; - public final int downstreamIfindex; - public final Inet6Address address; - public final MacAddress srcMac; - public final MacAddress dstMac; - - Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, Inet6Address address, - MacAddress srcMac, MacAddress dstMac) { - this.upstreamIfindex = upstreamIfindex; - this.downstreamIfindex = downstreamIfIndex; - this.address = address; - this.srcMac = srcMac; - this.dstMac = dstMac; - } - - public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { - return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, - dstMac); - } - - // Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() - // would be error-prone due to generated stable AIDL classes not having a copy constructor. - public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { - final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); - parcel.inputInterfaceIndex = upstreamIfindex; - parcel.outputInterfaceIndex = downstreamIfindex; - parcel.destination = address.getAddress(); - parcel.prefixLength = 128; - parcel.srcL2Address = srcMac.toByteArray(); - parcel.dstL2Address = dstMac.toByteArray(); - return parcel; - } - } - private final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> mIpv6ForwardingRules = - new LinkedHashMap<>(); - private final IpNeighborMonitor mIpNeighborMonitor; private LinkAddress mIpv4Address; @@ -314,11 +279,13 @@ public class IpServer extends StateMachine { // object. It helps to reduce the arguments of the constructor. public IpServer( String ifaceName, Looper looper, int interfaceType, SharedLog log, - INetd netd, Callback callback, boolean usingLegacyDhcp, boolean usingBpfOffload, + INetd netd, @NonNull BpfCoordinator coordinator, Callback callback, + boolean usingLegacyDhcp, boolean usingBpfOffload, PrivateAddressCoordinator addressCoordinator, Dependencies deps) { super(ifaceName, looper); mLog = log.forSubComponent(ifaceName); mNetd = netd; + mBpfCoordinator = coordinator; mCallback = callback; mInterfaceCtrl = new InterfaceController(ifaceName, mNetd, mLog); mIfaceName = ifaceName; @@ -749,6 +716,14 @@ public class IpServer extends StateMachine { } upstreamIfindex = mDeps.getIfindex(upstreamIface); + + // Add upstream index to name mapping for the tether stats usage in the coordinator. + // Although this mapping could be added by both class Tethering and IpServer, adding + // mapping from IpServer guarantees that the mapping is added before the adding + // forwarding rules. That is because there are different state machines in both + // classes. It is hard to guarantee the link property update order between multiple + // state machines. + mBpfCoordinator.addUpstreamNameToLookupTable(upstreamIfindex, upstreamIface); } // If v6only is null, we pass in null to setRaParams(), which handles @@ -864,43 +839,29 @@ public class IpServer extends StateMachine { // TODO: Perhaps remove this protection check. if (!mUsingBpfOffload) return; - try { - mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); - mIpv6ForwardingRules.put(rule.address, rule); - } catch (RemoteException | ServiceSpecificException e) { - mLog.e("Could not add IPv6 downstream rule: ", e); - } + mBpfCoordinator.tetherOffloadRuleAdd(this, rule); } - private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule, boolean removeFromMap) { - // Theoretically, we don't need this check because IP neighbor monitor doesn't start if BPF - // offload is disabled. Add this check just in case. + private void removeIpv6ForwardingRule(Ipv6ForwardingRule rule) { // TODO: Perhaps remove this protection check. + // See the related comment in #addIpv6ForwardingRule. if (!mUsingBpfOffload) return; - try { - mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); - if (removeFromMap) { - mIpv6ForwardingRules.remove(rule.address); - } - } catch (RemoteException | ServiceSpecificException e) { - mLog.e("Could not remove IPv6 downstream rule: ", e); - } + mBpfCoordinator.tetherOffloadRuleRemove(this, rule); } private void clearIpv6ForwardingRules() { - for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { - removeIpv6ForwardingRule(rule, false /*removeFromMap*/); - } - mIpv6ForwardingRules.clear(); + if (!mUsingBpfOffload) return; + + mBpfCoordinator.tetherOffloadRuleClear(this); } - // Convenience method to replace a rule with the same rule on a new upstream interface. - // Allows replacing the rules in one iteration pass without ConcurrentModificationExceptions. - // Relies on the fact that rules are in a map indexed by IP address. - private void updateIpv6ForwardingRule(Ipv6ForwardingRule rule, int newIfindex) { - addIpv6ForwardingRule(rule.onNewUpstream(newIfindex)); - removeIpv6ForwardingRule(rule, false /*removeFromMap*/); + private void updateIpv6ForwardingRule(int newIfindex) { + // TODO: Perhaps remove this protection check. + // See the related comment in #addIpv6ForwardingRule. + if (!mUsingBpfOffload) return; + + mBpfCoordinator.tetherOffloadRuleUpdate(this, newIfindex); } // Handles all updates to IPv6 forwarding rules. These can currently change only if the upstream @@ -916,9 +877,7 @@ public class IpServer extends StateMachine { // If the upstream interface has changed, remove all rules and re-add them with the new // upstream interface. if (prevUpstreamIfindex != upstreamIfindex) { - for (Ipv6ForwardingRule rule : mIpv6ForwardingRules.values()) { - updateIpv6ForwardingRule(rule, upstreamIfindex); - } + updateIpv6ForwardingRule(upstreamIfindex); } // If we're here to process a NeighborEvent, do so now. @@ -938,7 +897,7 @@ public class IpServer extends StateMachine { if (e.isValid()) { addIpv6ForwardingRule(rule); } else { - removeIpv6ForwardingRule(rule, true /*removeFromMap*/); + removeIpv6ForwardingRule(rule); } } diff --git a/packages/Tethering/src/android/net/util/TetheringUtils.java b/packages/Tethering/src/android/net/util/TetheringUtils.java index dd67dddae1cd..b17b4ba77cfb 100644 --- a/packages/Tethering/src/android/net/util/TetheringUtils.java +++ b/packages/Tethering/src/android/net/util/TetheringUtils.java @@ -15,19 +15,94 @@ */ package android.net.util; +import android.net.TetherStatsParcel; import android.net.TetheringRequestParcel; +import androidx.annotation.NonNull; + import java.io.FileDescriptor; import java.net.SocketException; import java.util.Objects; /** - * Native methods for tethering utilization. + * The classes and the methods for tethering utilization. * * {@hide} */ public class TetheringUtils { /** + * The object which records offload Tx/Rx forwarded bytes/packets. + * TODO: Replace the inner class ForwardedStats of class OffloadHardwareInterface with + * this class as well. + */ + public static class ForwardedStats { + public final long rxBytes; + public final long rxPackets; + public final long txBytes; + public final long txPackets; + + public ForwardedStats() { + rxBytes = 0; + rxPackets = 0; + txBytes = 0; + txPackets = 0; + } + + public ForwardedStats(long rxBytes, long txBytes) { + this.rxBytes = rxBytes; + this.rxPackets = 0; + this.txBytes = txBytes; + this.txPackets = 0; + } + + public ForwardedStats(long rxBytes, long rxPackets, long txBytes, long txPackets) { + this.rxBytes = rxBytes; + this.rxPackets = rxPackets; + this.txBytes = txBytes; + this.txPackets = txPackets; + } + + public ForwardedStats(@NonNull TetherStatsParcel tetherStats) { + rxBytes = tetherStats.rxBytes; + rxPackets = tetherStats.rxPackets; + txBytes = tetherStats.txBytes; + txPackets = tetherStats.txPackets; + } + + public ForwardedStats(@NonNull ForwardedStats other) { + rxBytes = other.rxBytes; + rxPackets = other.rxPackets; + txBytes = other.txBytes; + txPackets = other.txPackets; + } + + /** Add Tx/Rx bytes/packets and return the result as a new object. */ + @NonNull + public ForwardedStats add(@NonNull ForwardedStats other) { + return new ForwardedStats(rxBytes + other.rxBytes, rxPackets + other.rxPackets, + txBytes + other.txBytes, txPackets + other.txPackets); + } + + /** Subtract Tx/Rx bytes/packets and return the result as a new object. */ + @NonNull + public ForwardedStats subtract(@NonNull ForwardedStats other) { + // TODO: Perhaps throw an exception if any negative difference value just in case. + final long rxBytesDiff = Math.max(rxBytes - other.rxBytes, 0); + final long rxPacketsDiff = Math.max(rxPackets - other.rxPackets, 0); + final long txBytesDiff = Math.max(txBytes - other.txBytes, 0); + final long txPacketsDiff = Math.max(txPackets - other.txPackets, 0); + return new ForwardedStats(rxBytesDiff, rxPacketsDiff, txBytesDiff, txPacketsDiff); + } + + /** Returns the string representation of this object. */ + @NonNull + public String toString() { + return String.format("ForwardedStats(rxb: %d, rxp: %d, txb: %d, txp: %d)", rxBytes, + rxPackets, txBytes, txPackets); + } + } + + /** * Configures a socket for receiving ICMPv6 router solicitations and sending advertisements. * @param fd the socket's {@link FileDescriptor}. * @param ifIndex the interface index. diff --git a/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java new file mode 100644 index 000000000000..fc27b6add052 --- /dev/null +++ b/packages/Tethering/src/com/android/networkstack/tethering/BpfCoordinator.java @@ -0,0 +1,637 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.networkstack.tethering; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStats.UID_TETHERING; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; + +import android.app.usage.NetworkStatsManager; +import android.net.INetd; +import android.net.MacAddress; +import android.net.NetworkStats; +import android.net.NetworkStats.Entry; +import android.net.TetherOffloadRuleParcel; +import android.net.TetherStatsParcel; +import android.net.ip.IpServer; +import android.net.netstats.provider.NetworkStatsProvider; +import android.net.util.SharedLog; +import android.net.util.TetheringUtils.ForwardedStats; +import android.os.Handler; +import android.os.RemoteException; +import android.os.ServiceSpecificException; +import android.text.TextUtils; +import android.util.Log; +import android.util.SparseArray; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.internal.annotations.VisibleForTesting; + +import java.net.Inet6Address; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.Objects; + +/** + * This coordinator is responsible for providing BPF offload relevant functionality. + * - Get tethering stats. + * - Set data limit. + * - Set global alert. + * - Add/remove forwarding rules. + * + * @hide + */ +public class BpfCoordinator { + private static final String TAG = BpfCoordinator.class.getSimpleName(); + @VisibleForTesting + static final int DEFAULT_PERFORM_POLL_INTERVAL_MS = 5000; // TODO: Make it customizable. + + @VisibleForTesting + enum StatsType { + STATS_PER_IFACE, + STATS_PER_UID, + } + + @NonNull + private final Handler mHandler; + @NonNull + private final INetd mNetd; + @NonNull + private final SharedLog mLog; + @NonNull + private final Dependencies mDeps; + @Nullable + private final BpfTetherStatsProvider mStatsProvider; + + // Tracks whether BPF tethering is started or not. This is set by tethering before it + // starts the first IpServer and is cleared by tethering shortly before the last IpServer + // is stopped. Note that rule updates (especially deletions, but sometimes additions as + // well) may arrive when this is false. If they do, they must be communicated to netd. + // Changes in data limits may also arrive when this is false, and if they do, they must + // also be communicated to netd. + private boolean mPollingStarted = false; + + // Tracking remaining alert quota. Unlike limit quota is subject to interface, the alert + // quota is interface independent and global for tether offload. + private long mRemainingAlertQuota = QUOTA_UNLIMITED; + + // Maps upstream interface index to offloaded traffic statistics. + // Always contains the latest total bytes/packets, since each upstream was started, received + // from the BPF maps for each interface. + private final SparseArray<ForwardedStats> mStats = new SparseArray<>(); + + // Maps upstream interface names to interface quotas. + // Always contains the latest value received from the framework for each interface, regardless + // of whether offload is currently running (or is even supported) on that interface. Only + // includes interfaces that have a quota set. Note that this map is used for storing the quota + // which is set from the service. Because the service uses the interface name to present the + // interface, this map uses the interface name to be the mapping index. + private final HashMap<String, Long> mInterfaceQuotas = new HashMap<>(); + + // Maps upstream interface index to interface names. + // Store all interface name since boot. Used for lookup what interface name it is from the + // tether stats got from netd because netd reports interface index to present an interface. + // TODO: Remove the unused interface name. + private final SparseArray<String> mInterfaceNames = new SparseArray<>(); + + // Map of downstream rule maps. Each of these maps represents the IPv6 forwarding rules for a + // given downstream. Each map: + // - Is owned by the IpServer that is responsible for that downstream. + // - Must only be modified by that IpServer. + // - Is created when the IpServer adds its first rule, and deleted when the IpServer deletes + // its last rule (or clears its rules). + // TODO: Perhaps seal the map and rule operations which communicates with netd into a class. + // TODO: Does this need to be a LinkedHashMap or can it just be a HashMap? Also, could it be + // a ConcurrentHashMap, in order to avoid the copies in tetherOffloadRuleClear + // and tetherOffloadRuleUpdate? + // TODO: Perhaps use one-dimensional map and access specific downstream rules via downstream + // index. For doing that, IpServer must guarantee that it always has a valid IPv6 downstream + // interface index while calling function to clear all rules. IpServer may be calling clear + // rules function without a valid IPv6 downstream interface index even if it may have one + // before. IpServer would need to call getInterfaceParams() in the constructor instead of when + // startIpv6() is called, and make mInterfaceParams final. + private final HashMap<IpServer, LinkedHashMap<Inet6Address, Ipv6ForwardingRule>> + mIpv6ForwardingRules = new LinkedHashMap<>(); + + // Runnable that used by scheduling next polling of stats. + private final Runnable mScheduledPollingTask = () -> { + updateForwardedStatsFromNetd(); + maybeSchedulePollingStats(); + }; + + @VisibleForTesting + public static class Dependencies { + int getPerformPollInterval() { + // TODO: Consider make this configurable. + return DEFAULT_PERFORM_POLL_INTERVAL_MS; + } + } + + @VisibleForTesting + public BpfCoordinator(@NonNull Handler handler, @NonNull INetd netd, + @NonNull NetworkStatsManager nsm, @NonNull SharedLog log, @NonNull Dependencies deps) { + mHandler = handler; + mNetd = netd; + mLog = log.forSubComponent(TAG); + BpfTetherStatsProvider provider = new BpfTetherStatsProvider(); + try { + nsm.registerNetworkStatsProvider(getClass().getSimpleName(), provider); + } catch (RuntimeException e) { + // TODO: Perhaps not allow to use BPF offload because the reregistration failure + // implied that no data limit could be applies on a metered upstream if any. + Log.wtf(TAG, "Cannot register offload stats provider: " + e); + provider = null; + } + mStatsProvider = provider; + mDeps = deps; + } + + /** + * Start BPF tethering offload stats polling when the first upstream is started. + * Note that this can be only called on handler thread. + * TODO: Perhaps check BPF support before starting. + * TODO: Start the stats polling only if there is any client on the downstream. + */ + public void startPolling() { + if (mPollingStarted) return; + + mPollingStarted = true; + maybeSchedulePollingStats(); + + mLog.i("Polling started"); + } + + /** + * Stop BPF tethering offload stats polling. + * The data limit cleanup and the tether stats maps cleanup are not implemented here. + * These cleanups rely on all IpServers calling #tetherOffloadRuleRemove. After the + * last rule is removed from the upstream, #tetherOffloadRuleRemove does the cleanup + * functionality. + * Note that this can be only called on handler thread. + */ + public void stopPolling() { + if (!mPollingStarted) return; + + // Stop scheduled polling tasks and poll the latest stats from BPF maps. + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } + updateForwardedStatsFromNetd(); + mPollingStarted = false; + + mLog.i("Polling stopped"); + } + + /** + * Add forwarding rule. After adding the first rule on a given upstream, must add the data + * limit on the given upstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleAdd( + @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + try { + // TODO: Perhaps avoid to add a duplicate rule. + mNetd.tetherOffloadRuleAdd(rule.toTetherOffloadRuleParcel()); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Could not add IPv6 forwarding rule: ", e); + return; + } + + if (!mIpv6ForwardingRules.containsKey(ipServer)) { + mIpv6ForwardingRules.put(ipServer, new LinkedHashMap<Inet6Address, + Ipv6ForwardingRule>()); + } + LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer); + + // Setup the data limit on the given upstream if the first rule is added. + final int upstreamIfindex = rule.upstreamIfindex; + if (!isAnyRuleOnUpstream(upstreamIfindex)) { + // If failed to set a data limit, probably should not use this upstream, because + // the upstream may not want to blow through the data limit that was told to apply. + // TODO: Perhaps stop the coordinator. + boolean success = updateDataLimit(upstreamIfindex); + if (!success) { + final String iface = mInterfaceNames.get(upstreamIfindex); + mLog.e("Setting data limit for " + iface + " failed."); + } + } + + // Must update the adding rule after calling #isAnyRuleOnUpstream because it needs to + // check if it is about adding a first rule for a given upstream. + rules.put(rule.address, rule); + } + + /** + * Remove forwarding rule. After removing the last rule on a given upstream, must clear + * data limit, update the last tether stats and remove the tether stats in the BPF maps. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleRemove( + @NonNull final IpServer ipServer, @NonNull final Ipv6ForwardingRule rule) { + try { + // TODO: Perhaps avoid to remove a non-existent rule. + mNetd.tetherOffloadRuleRemove(rule.toTetherOffloadRuleParcel()); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Could not remove IPv6 forwarding rule: ", e); + return; + } + + LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get(ipServer); + if (rules == null) return; + + // Must remove rules before calling #isAnyRuleOnUpstream because it needs to check if + // the last rule is removed for a given upstream. If no rule is removed, return early. + // Avoid unnecessary work on a non-existent rule which may have never been added or + // removed already. + if (rules.remove(rule.address) == null) return; + + // Remove the downstream entry if it has no more rule. + if (rules.isEmpty()) { + mIpv6ForwardingRules.remove(ipServer); + } + + // Do cleanup functionality if there is no more rule on the given upstream. + final int upstreamIfindex = rule.upstreamIfindex; + if (!isAnyRuleOnUpstream(upstreamIfindex)) { + try { + final TetherStatsParcel stats = + mNetd.tetherOffloadGetAndClearStats(upstreamIfindex); + // Update the last stats delta and delete the local cache for a given upstream. + updateQuotaAndStatsFromSnapshot(new TetherStatsParcel[] {stats}); + mStats.remove(upstreamIfindex); + } catch (RemoteException | ServiceSpecificException e) { + Log.wtf(TAG, "Exception when cleanup tether stats for upstream index " + + upstreamIfindex + ": ", e); + } + } + } + + /** + * Clear all forwarding rules for a given downstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleClear(@NonNull final IpServer ipServer) { + final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get( + ipServer); + if (rules == null) return; + + // Need to build a rule list because the rule map may be changed in the iteration. + for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) { + tetherOffloadRuleRemove(ipServer, rule); + } + } + + /** + * Update existing forwarding rules to new upstream for a given downstream. + * Note that this can be only called on handler thread. + */ + public void tetherOffloadRuleUpdate(@NonNull final IpServer ipServer, int newUpstreamIfindex) { + final LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules = mIpv6ForwardingRules.get( + ipServer); + if (rules == null) return; + + // Need to build a rule list because the rule map may be changed in the iteration. + for (final Ipv6ForwardingRule rule : new ArrayList<Ipv6ForwardingRule>(rules.values())) { + // Remove the old rule before adding the new one because the map uses the same key for + // both rules. Reversing the processing order causes that the new rule is removed as + // unexpected. + // TODO: Add new rule first to reduce the latency which has no rule. + tetherOffloadRuleRemove(ipServer, rule); + tetherOffloadRuleAdd(ipServer, rule.onNewUpstream(newUpstreamIfindex)); + } + } + + /** + * Add upstream name to lookup table. The lookup table is used for tether stats interface name + * lookup because the netd only reports interface index in BPF tether stats but the service + * expects the interface name in NetworkStats object. + * Note that this can be only called on handler thread. + */ + public void addUpstreamNameToLookupTable(int upstreamIfindex, @NonNull String upstreamIface) { + if (upstreamIfindex == 0 || TextUtils.isEmpty(upstreamIface)) return; + + // The same interface index to name mapping may be added by different IpServer objects or + // re-added by reconnection on the same upstream interface. Ignore the duplicate one. + final String iface = mInterfaceNames.get(upstreamIfindex); + if (iface == null) { + mInterfaceNames.put(upstreamIfindex, upstreamIface); + } else if (!TextUtils.equals(iface, upstreamIface)) { + Log.wtf(TAG, "The upstream interface name " + upstreamIface + + " is different from the existing interface name " + + iface + " for index " + upstreamIfindex); + } + } + + /** IPv6 forwarding rule class. */ + public static class Ipv6ForwardingRule { + public final int upstreamIfindex; + public final int downstreamIfindex; + + @NonNull + public final Inet6Address address; + @NonNull + public final MacAddress srcMac; + @NonNull + public final MacAddress dstMac; + + public Ipv6ForwardingRule(int upstreamIfindex, int downstreamIfIndex, + @NonNull Inet6Address address, @NonNull MacAddress srcMac, + @NonNull MacAddress dstMac) { + this.upstreamIfindex = upstreamIfindex; + this.downstreamIfindex = downstreamIfIndex; + this.address = address; + this.srcMac = srcMac; + this.dstMac = dstMac; + } + + /** Return a new rule object which updates with new upstream index. */ + @NonNull + public Ipv6ForwardingRule onNewUpstream(int newUpstreamIfindex) { + return new Ipv6ForwardingRule(newUpstreamIfindex, downstreamIfindex, address, srcMac, + dstMac); + } + + /** + * Don't manipulate TetherOffloadRuleParcel directly because implementing onNewUpstream() + * would be error-prone due to generated stable AIDL classes not having a copy constructor. + */ + @NonNull + public TetherOffloadRuleParcel toTetherOffloadRuleParcel() { + final TetherOffloadRuleParcel parcel = new TetherOffloadRuleParcel(); + parcel.inputInterfaceIndex = upstreamIfindex; + parcel.outputInterfaceIndex = downstreamIfindex; + parcel.destination = address.getAddress(); + parcel.prefixLength = 128; + parcel.srcL2Address = srcMac.toByteArray(); + parcel.dstL2Address = dstMac.toByteArray(); + return parcel; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof Ipv6ForwardingRule)) return false; + Ipv6ForwardingRule that = (Ipv6ForwardingRule) o; + return this.upstreamIfindex == that.upstreamIfindex + && this.downstreamIfindex == that.downstreamIfindex + && Objects.equals(this.address, that.address) + && Objects.equals(this.srcMac, that.srcMac) + && Objects.equals(this.dstMac, that.dstMac); + } + + @Override + public int hashCode() { + // TODO: if this is ever used in production code, don't pass ifindices + // to Objects.hash() to avoid autoboxing overhead. + return Objects.hash(upstreamIfindex, downstreamIfindex, address, srcMac, dstMac); + } + } + + /** + * A BPF tethering stats provider to provide network statistics to the system. + * Note that this class' data may only be accessed on the handler thread. + */ + @VisibleForTesting + class BpfTetherStatsProvider extends NetworkStatsProvider { + // The offloaded traffic statistics per interface that has not been reported since the + // last call to pushTetherStats. Only the interfaces that were ever tethering upstreams + // and has pending tether stats delta are included in this NetworkStats object. + private NetworkStats mIfaceStats = new NetworkStats(0L, 0); + + // The same stats as above, but counts network stats per uid. + private NetworkStats mUidStats = new NetworkStats(0L, 0); + + @Override + public void onRequestStatsUpdate(int token) { + mHandler.post(() -> pushTetherStats()); + } + + @Override + public void onSetAlert(long quotaBytes) { + mHandler.post(() -> updateAlertQuota(quotaBytes)); + } + + @Override + public void onSetLimit(@NonNull String iface, long quotaBytes) { + if (quotaBytes < QUOTA_UNLIMITED) { + throw new IllegalArgumentException("invalid quota value " + quotaBytes); + } + + mHandler.post(() -> { + final Long curIfaceQuota = mInterfaceQuotas.get(iface); + + if (null == curIfaceQuota && QUOTA_UNLIMITED == quotaBytes) return; + + if (quotaBytes == QUOTA_UNLIMITED) { + mInterfaceQuotas.remove(iface); + } else { + mInterfaceQuotas.put(iface, quotaBytes); + } + maybeUpdateDataLimit(iface); + }); + } + + @VisibleForTesting + void pushTetherStats() { + try { + // The token is not used for now. See b/153606961. + notifyStatsUpdated(0 /* token */, mIfaceStats, mUidStats); + + // Clear the accumulated tether stats delta after reported. Note that create a new + // empty object because NetworkStats#clear is @hide. + mIfaceStats = new NetworkStats(0L, 0); + mUidStats = new NetworkStats(0L, 0); + } catch (RuntimeException e) { + mLog.e("Cannot report network stats: ", e); + } + } + + private void accumulateDiff(@NonNull NetworkStats ifaceDiff, + @NonNull NetworkStats uidDiff) { + mIfaceStats = mIfaceStats.add(ifaceDiff); + mUidStats = mUidStats.add(uidDiff); + } + } + + private int getInterfaceIndexFromRules(@NonNull String ifName) { + for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules + .values()) { + for (Ipv6ForwardingRule rule : rules.values()) { + final int upstreamIfindex = rule.upstreamIfindex; + if (TextUtils.equals(ifName, mInterfaceNames.get(upstreamIfindex))) { + return upstreamIfindex; + } + } + } + return 0; + } + + private long getQuotaBytes(@NonNull String iface) { + final Long limit = mInterfaceQuotas.get(iface); + final long quotaBytes = (limit != null) ? limit : QUOTA_UNLIMITED; + + return quotaBytes; + } + + private boolean sendDataLimitToNetd(int ifIndex, long quotaBytes) { + if (ifIndex == 0) { + Log.wtf(TAG, "Invalid interface index."); + return false; + } + + try { + mNetd.tetherOffloadSetInterfaceQuota(ifIndex, quotaBytes); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Exception when updating quota " + quotaBytes + ": ", e); + return false; + } + + return true; + } + + // Handle the data limit update from the service which is the stats provider registered for. + private void maybeUpdateDataLimit(@NonNull String iface) { + // Set data limit only on a given upstream which has at least one rule. If we can't get + // an interface index for a given interface name, it means either there is no rule for + // a given upstream or the interface name is not an upstream which is monitored by the + // coordinator. + final int ifIndex = getInterfaceIndexFromRules(iface); + if (ifIndex == 0) return; + + final long quotaBytes = getQuotaBytes(iface); + sendDataLimitToNetd(ifIndex, quotaBytes); + } + + // Handle the data limit update while adding forwarding rules. + private boolean updateDataLimit(int ifIndex) { + final String iface = mInterfaceNames.get(ifIndex); + if (iface == null) { + mLog.e("Fail to get the interface name for index " + ifIndex); + return false; + } + final long quotaBytes = getQuotaBytes(iface); + return sendDataLimitToNetd(ifIndex, quotaBytes); + } + + private boolean isAnyRuleOnUpstream(int upstreamIfindex) { + for (LinkedHashMap<Inet6Address, Ipv6ForwardingRule> rules : mIpv6ForwardingRules + .values()) { + for (Ipv6ForwardingRule rule : rules.values()) { + if (upstreamIfindex == rule.upstreamIfindex) return true; + } + } + return false; + } + + @NonNull + private NetworkStats buildNetworkStats(@NonNull StatsType type, int ifIndex, + @NonNull final ForwardedStats diff) { + NetworkStats stats = new NetworkStats(0L, 0); + final String iface = mInterfaceNames.get(ifIndex); + if (iface == null) { + // TODO: Use Log.wtf once the coordinator owns full control of tether stats from netd. + // For now, netd may add the empty stats for the upstream which is not monitored by + // the coordinator. Silently ignore it. + return stats; + } + final int uid = (type == StatsType.STATS_PER_UID) ? UID_TETHERING : UID_ALL; + // Note that the argument 'metered', 'roaming' and 'defaultNetwork' are not recorded for + // network stats snapshot. See NetworkStatsRecorder#recordSnapshotLocked. + return stats.addEntry(new Entry(iface, uid, SET_DEFAULT, TAG_NONE, METERED_NO, + ROAMING_NO, DEFAULT_NETWORK_NO, diff.rxBytes, diff.rxPackets, + diff.txBytes, diff.txPackets, 0L /* operations */)); + } + + private void updateAlertQuota(long newQuota) { + if (newQuota < QUOTA_UNLIMITED) { + throw new IllegalArgumentException("invalid quota value " + newQuota); + } + if (mRemainingAlertQuota == newQuota) return; + + mRemainingAlertQuota = newQuota; + if (mRemainingAlertQuota == 0) { + mLog.i("onAlertReached"); + if (mStatsProvider != null) mStatsProvider.notifyAlertReached(); + } + } + + private void updateQuotaAndStatsFromSnapshot( + @NonNull final TetherStatsParcel[] tetherStatsList) { + long usedAlertQuota = 0; + for (TetherStatsParcel tetherStats : tetherStatsList) { + final Integer ifIndex = tetherStats.ifIndex; + final ForwardedStats curr = new ForwardedStats(tetherStats); + final ForwardedStats base = mStats.get(ifIndex); + final ForwardedStats diff = (base != null) ? curr.subtract(base) : curr; + usedAlertQuota += diff.rxBytes + diff.txBytes; + + // Update the local cache for counting tether stats delta. + mStats.put(ifIndex, curr); + + // Update the accumulated tether stats delta to the stats provider for the service + // querying. + if (mStatsProvider != null) { + try { + mStatsProvider.accumulateDiff( + buildNetworkStats(StatsType.STATS_PER_IFACE, ifIndex, diff), + buildNetworkStats(StatsType.STATS_PER_UID, ifIndex, diff)); + } catch (ArrayIndexOutOfBoundsException e) { + Log.wtf(TAG, "Fail to update the accumulated stats delta for interface index " + + ifIndex + " : ", e); + } + } + } + + if (mRemainingAlertQuota > 0 && usedAlertQuota > 0) { + // Trim to zero if overshoot. + final long newQuota = Math.max(mRemainingAlertQuota - usedAlertQuota, 0); + updateAlertQuota(newQuota); + } + + // TODO: Count the used limit quota for notifying data limit reached. + } + + private void updateForwardedStatsFromNetd() { + final TetherStatsParcel[] tetherStatsList; + try { + // The reported tether stats are total data usage for all currently-active upstream + // interfaces since tethering start. + tetherStatsList = mNetd.tetherOffloadGetStats(); + } catch (RemoteException | ServiceSpecificException e) { + mLog.e("Problem fetching tethering stats: ", e); + return; + } + updateQuotaAndStatsFromSnapshot(tetherStatsList); + } + + private void maybeSchedulePollingStats() { + if (!mPollingStarted) return; + + if (mHandler.hasCallbacks(mScheduledPollingTask)) { + mHandler.removeCallbacks(mScheduledPollingTask); + } + + mHandler.postDelayed(mScheduledPollingTask, mDeps.getPerformPollInterval()); + } +} diff --git a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java index 69eec8df9864..df6745855067 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/Tethering.java @@ -232,6 +232,7 @@ public class Tethering { private final TetheringThreadExecutor mExecutor; private final TetheringNotificationUpdater mNotificationUpdater; private final UserManager mUserManager; + private final BpfCoordinator mBpfCoordinator; private final PrivateAddressCoordinator mPrivateAddressCoordinator; private int mActiveDataSubId = INVALID_SUBSCRIPTION_ID; // All the usage of mTetheringEventCallback should run in the same thread. @@ -284,6 +285,8 @@ public class Tethering { mUpstreamNetworkMonitor = mDeps.getUpstreamNetworkMonitor(mContext, mTetherMasterSM, mLog, TetherMasterSM.EVENT_UPSTREAM_CALLBACK); mForwardedDownstreams = new LinkedHashSet<>(); + mBpfCoordinator = mDeps.getBpfCoordinator( + mHandler, mNetd, mLog, new BpfCoordinator.Dependencies()); IntentFilter filter = new IntentFilter(); filter.addAction(ACTION_CARRIER_CONFIG_CHANGED); @@ -1704,6 +1707,9 @@ public class Tethering { chooseUpstreamType(true); mTryCell = false; } + + // TODO: Check the upstream interface if it is managed by BPF offload. + mBpfCoordinator.startPolling(); } @Override @@ -1716,6 +1722,7 @@ public class Tethering { mTetherUpstream = null; reportUpstreamChanged(null); } + mBpfCoordinator.stopPolling(); } private boolean updateUpstreamWanted() { @@ -2341,7 +2348,7 @@ public class Tethering { mLog.log("adding TetheringInterfaceStateMachine for: " + iface); final TetherState tetherState = new TetherState( - new IpServer(iface, mLooper, interfaceType, mLog, mNetd, + new IpServer(iface, mLooper, interfaceType, mLog, mNetd, mBpfCoordinator, makeControlCallback(), mConfig.enableLegacyDhcpServer, mConfig.enableBpfOffload, mPrivateAddressCoordinator, mDeps.getIpServerDependencies())); diff --git a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java index ce546c701a61..d637c8646b4a 100644 --- a/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java +++ b/packages/Tethering/src/com/android/networkstack/tethering/TetheringDependencies.java @@ -41,6 +41,17 @@ import java.util.ArrayList; */ public abstract class TetheringDependencies { /** + * Get a reference to the BpfCoordinator to be used by tethering. + */ + public @NonNull BpfCoordinator getBpfCoordinator( + @NonNull Handler handler, @NonNull INetd netd, @NonNull SharedLog log, + @NonNull BpfCoordinator.Dependencies deps) { + final NetworkStatsManager statsManager = + (NetworkStatsManager) getContext().getSystemService(Context.NETWORK_STATS_SERVICE); + return new BpfCoordinator(handler, netd, statsManager, log, deps); + } + + /** * Get a reference to the offload hardware interface to be used by tethering. */ public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) { diff --git a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java index 0cda29a32f59..c3bc915a232d 100644 --- a/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java +++ b/packages/Tethering/tests/unit/src/android/net/ip/IpServerTest.java @@ -54,12 +54,14 @@ import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.never; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.spy; import static org.mockito.Mockito.timeout; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import static org.mockito.Mockito.when; +import android.app.usage.NetworkStatsManager; import android.net.INetd; import android.net.InetAddresses; import android.net.InterfaceConfigurationParcel; @@ -69,6 +71,7 @@ import android.net.LinkProperties; import android.net.MacAddress; import android.net.RouteInfo; import android.net.TetherOffloadRuleParcel; +import android.net.TetherStatsParcel; import android.net.dhcp.DhcpServingParamsParcel; import android.net.dhcp.IDhcpEventCallbacks; import android.net.dhcp.IDhcpServer; @@ -80,13 +83,17 @@ import android.net.util.InterfaceParams; import android.net.util.InterfaceSet; import android.net.util.PrefixUtils; import android.net.util.SharedLog; +import android.os.Handler; import android.os.RemoteException; import android.os.test.TestLooper; import android.text.TextUtils; +import androidx.annotation.NonNull; import androidx.test.filters.SmallTest; import androidx.test.runner.AndroidJUnit4; +import com.android.networkstack.tethering.BpfCoordinator; +import com.android.networkstack.tethering.BpfCoordinator.Ipv6ForwardingRule; import com.android.networkstack.tethering.PrivateAddressCoordinator; import org.junit.Before; @@ -100,6 +107,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.net.Inet4Address; +import java.net.Inet6Address; import java.net.InetAddress; import java.util.Arrays; import java.util.List; @@ -133,6 +141,7 @@ public class IpServerTest { @Mock private IpNeighborMonitor mIpNeighborMonitor; @Mock private IpServer.Dependencies mDependencies; @Mock private PrivateAddressCoordinator mAddressCoordinator; + @Mock private NetworkStatsManager mStatsManager; @Captor private ArgumentCaptor<DhcpServingParamsParcel> mDhcpParamsCaptor; @@ -142,6 +151,7 @@ public class IpServerTest { private IpServer mIpServer; private InterfaceConfigurationParcel mInterfaceConfiguration; private NeighborEventConsumer mNeighborEventConsumer; + private BpfCoordinator mBpfCoordinator; private void initStateMachine(int interfaceType) throws Exception { initStateMachine(interfaceType, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD); @@ -179,7 +189,7 @@ public class IpServerTest { neighborCaptor.capture()); mIpServer = new IpServer( - IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, + IFACE_NAME, mLooper.getLooper(), interfaceType, mSharedLog, mNetd, mBpfCoordinator, mCallback, usingLegacyDhcp, usingBpfOffload, mAddressCoordinator, mDependencies); mIpServer.start(); mNeighborEventConsumer = neighborCaptor.getValue(); @@ -215,6 +225,10 @@ public class IpServerTest { MockitoAnnotations.initMocks(this); when(mSharedLog.forSubComponent(anyString())).thenReturn(mSharedLog); when(mAddressCoordinator.requestDownstreamAddress(any())).thenReturn(mTestAddress); + + BpfCoordinator bc = new BpfCoordinator(new Handler(mLooper.getLooper()), mNetd, + mStatsManager, mSharedLog, new BpfCoordinator.Dependencies()); + mBpfCoordinator = spy(bc); } @Test @@ -222,8 +236,8 @@ public class IpServerTest { when(mDependencies.getIpNeighborMonitor(any(), any(), any())) .thenReturn(mIpNeighborMonitor); mIpServer = new IpServer(IFACE_NAME, mLooper.getLooper(), TETHERING_BLUETOOTH, mSharedLog, - mNetd, mCallback, false /* usingLegacyDhcp */, DEFAULT_USING_BPF_OFFLOAD, - mAddressCoordinator, mDependencies); + mNetd, mBpfCoordinator, mCallback, false /* usingLegacyDhcp */, + DEFAULT_USING_BPF_OFFLOAD, mAddressCoordinator, mDependencies); mIpServer.start(); mLooper.dispatchAll(); verify(mCallback).updateInterfaceState( @@ -619,6 +633,10 @@ public class IpServerTest { * (actual: "android.net.TetherOffloadRuleParcel@8c827b0" or some such), but at least it does * work. * + * TODO: consider making the error message more readable by adding a method that catching the + * AssertionFailedError and throwing a new assertion with more details. See + * NetworkMonitorTest#verifyNetworkTested. + * * See ConnectivityServiceTest#assertRoutesAdded for an alternative approach which solves the * TooManyActualInvocations problem described above by forcing the caller of the custom assert * method to specify all expected invocations in one call. This is useful when the stable @@ -658,6 +676,27 @@ public class IpServerTest { return argThat(new TetherOffloadRuleParcelMatcher(upstreamIfindex, dst, dstMac)); } + private static Ipv6ForwardingRule makeForwardingRule( + int upstreamIfindex, @NonNull InetAddress dst, @NonNull MacAddress dstMac) { + return new Ipv6ForwardingRule(upstreamIfindex, TEST_IFACE_PARAMS.index, + (Inet6Address) dst, TEST_IFACE_PARAMS.macAddr, dstMac); + } + + private TetherStatsParcel buildEmptyTetherStatsParcel(int ifIndex) { + TetherStatsParcel parcel = new TetherStatsParcel(); + parcel.ifIndex = ifIndex; + return parcel; + } + + private void resetNetdAndBpfCoordinator() throws Exception { + reset(mNetd, mBpfCoordinator); + when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]); + when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX)) + .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX)); + when(mNetd.tetherOffloadGetAndClearStats(UPSTREAM_IFINDEX2)) + .thenReturn(buildEmptyTetherStatsParcel(UPSTREAM_IFINDEX2)); + } + @Test public void addRemoveipv6ForwardingRules() throws Exception { initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, @@ -675,75 +714,100 @@ public class IpServerTest { final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macB = MacAddress.fromString("11:22:33:00:00:0b"); - reset(mNetd); + resetNetdAndBpfCoordinator(); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); + + // TODO: Perhaps verify the interaction of tetherOffloadSetInterfaceQuota and + // tetherOffloadGetAndClearStats in netd while the rules are changed. // Events on other interfaces are ignored. recvNewNeigh(notMyIfindex, neighA, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // Events on this interface are received and sent to netd. recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); - reset(mNetd); + resetNetdAndBpfCoordinator(); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // Link-local and multicast neighbors are ignored. recvNewNeigh(myIfindex, neighLL, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); recvNewNeigh(myIfindex, neighMC, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // A neighbor that is no longer valid causes the rule to be removed. // NUD_FAILED events do not have a MAC address. recvNewNeigh(myIfindex, neighA, NUD_FAILED, null); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macNull)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macNull)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // A neighbor that is deleted causes the rule to be removed. recvDelNeigh(myIfindex, neighB, NUD_STALE, macB); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macNull)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macNull)); - reset(mNetd); + resetNetdAndBpfCoordinator(); - // Upstream changes result in deleting and re-adding the rules. + // Upstream changes result in updating the rules. recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); - reset(mNetd); + resetNetdAndBpfCoordinator(); InOrder inOrder = inOrder(mNetd); LinkProperties lp = new LinkProperties(); lp.setInterfaceName(UPSTREAM_IFACE2); dispatchTetherConnectionChanged(UPSTREAM_IFACE2, lp, -1); - inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); + verify(mBpfCoordinator).tetherOffloadRuleUpdate(mIpServer, UPSTREAM_IFINDEX2); inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); - inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighA, macA)); inOrder.verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + inOrder.verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX2, neighB, macB)); + resetNetdAndBpfCoordinator(); // When the upstream is lost, rules are removed. dispatchTetherConnectionChanged(null, null, 0); + // Clear function is called two times by: + // - processMessage CMD_TETHER_CONNECTION_CHANGED for the upstream is lost. + // - processMessage CMD_IPV6_TETHER_UPDATE for the IPv6 upstream is lost. + // See dispatchTetherConnectionChanged. + verify(mBpfCoordinator, times(2)).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX2, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); // If the upstream is IPv4-only, no rules are added. dispatchTetherConnectionChanged(UPSTREAM_IFACE); - reset(mNetd); + resetNetdAndBpfCoordinator(); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); - verifyNoMoreInteractions(mNetd); + // Clear function is called by #updateIpv6ForwardingRules for the IPv6 upstream is lost. + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); + verifyNoMoreInteractions(mBpfCoordinator, mNetd); // Rules can be added again once upstream IPv6 connectivity is available. lp.setInterfaceName(UPSTREAM_IFACE); dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); + verify(mBpfCoordinator, never()).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd, never()).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); // If upstream IPv6 connectivity is lost, rules are removed. - reset(mNetd); + resetNetdAndBpfCoordinator(); dispatchTetherConnectionChanged(UPSTREAM_IFACE, null, 0); + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); // When the interface goes down, rules are removed. @@ -751,15 +815,20 @@ public class IpServerTest { dispatchTetherConnectionChanged(UPSTREAM_IFACE, lp, -1); recvNewNeigh(myIfindex, neighA, NUD_REACHABLE, macA); recvNewNeigh(myIfindex, neighB, NUD_REACHABLE, macB); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighA, macA)); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neighB, macB)); verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); mIpServer.stop(); mLooper.dispatchAll(); + verify(mBpfCoordinator).tetherOffloadRuleClear(mIpServer); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighA, macA)); verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neighB, macB)); - reset(mNetd); + resetNetdAndBpfCoordinator(); } @Test @@ -769,35 +838,46 @@ public class IpServerTest { final MacAddress macA = MacAddress.fromString("00:00:00:00:00:0a"); final MacAddress macNull = MacAddress.fromString("00:00:00:00:00:00"); - reset(mNetd); - // Expect that rules can be only added/removed when the BPF offload config is enabled. - // Note that the usingBpfOffload false case is not a realistic test case. Because IP + // Note that the BPF offload disabled case is not a realistic test case. Because IP // neighbor monitor doesn't start if BPF offload is disabled, there should have no // neighbor event listening. This is used for testing the protection check just in case. - // TODO: Perhaps remove this test once we don't need this check anymore. - for (boolean usingBpfOffload : new boolean[]{true, false}) { - initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, - usingBpfOffload); - - // A neighbor is added. - recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); - if (usingBpfOffload) { - verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); - } else { - verify(mNetd, never()).tetherOffloadRuleAdd(any()); - } - reset(mNetd); - - // A neighbor is deleted. - recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); - if (usingBpfOffload) { - verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); - } else { - verify(mNetd, never()).tetherOffloadRuleRemove(any()); - } - reset(mNetd); - } + // TODO: Perhaps remove the BPF offload disabled case test once this check isn't needed + // anymore. + + // [1] Enable BPF offload. + // A neighbor that is added or deleted causes the rule to be added or removed. + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + true /* usingBpfOffload */); + resetNetdAndBpfCoordinator(); + + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + verify(mBpfCoordinator).tetherOffloadRuleAdd( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macA)); + verify(mNetd).tetherOffloadRuleAdd(matches(UPSTREAM_IFINDEX, neigh, macA)); + resetNetdAndBpfCoordinator(); + + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + verify(mBpfCoordinator).tetherOffloadRuleRemove( + mIpServer, makeForwardingRule(UPSTREAM_IFINDEX, neigh, macNull)); + verify(mNetd).tetherOffloadRuleRemove(matches(UPSTREAM_IFINDEX, neigh, macNull)); + resetNetdAndBpfCoordinator(); + + // [2] Disable BPF offload. + // A neighbor that is added or deleted doesn’t cause the rule to be added or removed. + initTetheredStateMachine(TETHERING_WIFI, UPSTREAM_IFACE, false /* usingLegacyDhcp */, + false /* usingBpfOffload */); + resetNetdAndBpfCoordinator(); + + recvNewNeigh(myIfindex, neigh, NUD_REACHABLE, macA); + verify(mBpfCoordinator, never()).tetherOffloadRuleAdd(any(), any()); + verify(mNetd, never()).tetherOffloadRuleAdd(any()); + resetNetdAndBpfCoordinator(); + + recvDelNeigh(myIfindex, neigh, NUD_STALE, macA); + verify(mBpfCoordinator, never()).tetherOffloadRuleRemove(any(), any()); + verify(mNetd, never()).tetherOffloadRuleRemove(any()); + resetNetdAndBpfCoordinator(); } @Test diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java new file mode 100644 index 000000000000..e2d7aab4e33f --- /dev/null +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/BpfCoordinatorTest.java @@ -0,0 +1,246 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.networkstack.tethering; + +import static android.net.NetworkStats.DEFAULT_NETWORK_NO; +import static android.net.NetworkStats.METERED_NO; +import static android.net.NetworkStats.ROAMING_NO; +import static android.net.NetworkStats.SET_DEFAULT; +import static android.net.NetworkStats.TAG_NONE; +import static android.net.NetworkStats.UID_ALL; +import static android.net.NetworkStats.UID_TETHERING; +import static android.net.netstats.provider.NetworkStatsProvider.QUOTA_UNLIMITED; + +import static com.android.networkstack.tethering.BpfCoordinator + .DEFAULT_PERFORM_POLL_INTERVAL_MS; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_IFACE; +import static com.android.networkstack.tethering.BpfCoordinator.StatsType.STATS_PER_UID; + +import static junit.framework.Assert.assertNotNull; + +import static org.mockito.Matchers.anyString; +import static org.mockito.Mockito.clearInvocations; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import android.annotation.NonNull; +import android.app.usage.NetworkStatsManager; +import android.net.INetd; +import android.net.NetworkStats; +import android.net.TetherStatsParcel; +import android.net.util.SharedLog; +import android.os.Handler; +import android.os.test.TestLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.runner.AndroidJUnit4; + +import com.android.testutils.TestableNetworkStatsProviderCbBinder; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.ArrayList; + +@RunWith(AndroidJUnit4.class) +@SmallTest +public class BpfCoordinatorTest { + @Mock private NetworkStatsManager mStatsManager; + @Mock private INetd mNetd; + // Late init since methods must be called by the thread that created this object. + private TestableNetworkStatsProviderCbBinder mTetherStatsProviderCb; + private BpfCoordinator.BpfTetherStatsProvider mTetherStatsProvider; + private final ArgumentCaptor<ArrayList> mStringArrayCaptor = + ArgumentCaptor.forClass(ArrayList.class); + private final TestLooper mTestLooper = new TestLooper(); + private BpfCoordinator.Dependencies mDeps = + new BpfCoordinator.Dependencies() { + @Override + int getPerformPollInterval() { + return DEFAULT_PERFORM_POLL_INTERVAL_MS; + } + }; + + @Before public void setUp() { + MockitoAnnotations.initMocks(this); + } + + private void waitForIdle() { + mTestLooper.dispatchAll(); + } + + private void setupFunctioningNetdInterface() throws Exception { + when(mNetd.tetherOffloadGetStats()).thenReturn(new TetherStatsParcel[0]); + } + + @NonNull + private BpfCoordinator makeBpfCoordinator() throws Exception { + BpfCoordinator coordinator = new BpfCoordinator( + new Handler(mTestLooper.getLooper()), mNetd, mStatsManager, new SharedLog("test"), + mDeps); + final ArgumentCaptor<BpfCoordinator.BpfTetherStatsProvider> + tetherStatsProviderCaptor = + ArgumentCaptor.forClass(BpfCoordinator.BpfTetherStatsProvider.class); + verify(mStatsManager).registerNetworkStatsProvider(anyString(), + tetherStatsProviderCaptor.capture()); + mTetherStatsProvider = tetherStatsProviderCaptor.getValue(); + assertNotNull(mTetherStatsProvider); + mTetherStatsProviderCb = new TestableNetworkStatsProviderCbBinder(); + mTetherStatsProvider.setProviderCallbackBinder(mTetherStatsProviderCb); + return coordinator; + } + + @NonNull + private static NetworkStats.Entry buildTestEntry(@NonNull StatsType how, + @NonNull String iface, long rxBytes, long rxPackets, long txBytes, long txPackets) { + return new NetworkStats.Entry(iface, how == STATS_PER_IFACE ? UID_ALL : UID_TETHERING, + SET_DEFAULT, TAG_NONE, METERED_NO, ROAMING_NO, DEFAULT_NETWORK_NO, rxBytes, + rxPackets, txBytes, txPackets, 0L); + } + + @NonNull + private static TetherStatsParcel buildTestTetherStatsParcel(@NonNull Integer ifIndex, + long rxBytes, long rxPackets, long txBytes, long txPackets) { + final TetherStatsParcel parcel = new TetherStatsParcel(); + parcel.ifIndex = ifIndex; + parcel.rxBytes = rxBytes; + parcel.rxPackets = rxPackets; + parcel.txBytes = txBytes; + parcel.txPackets = txPackets; + return parcel; + } + + private void setTetherOffloadStatsList(TetherStatsParcel[] tetherStatsList) throws Exception { + when(mNetd.tetherOffloadGetStats()).thenReturn(tetherStatsList); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + } + + @Test + public void testGetForwardedStats() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + coordinator.startPolling(); + + final String wlanIface = "wlan0"; + final Integer wlanIfIndex = 100; + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 101; + + // Add interface name to lookup table. In realistic case, the upstream interface name will + // be added by IpServer when IpServer has received with a new IPv6 upstream update event. + coordinator.addUpstreamNameToLookupTable(wlanIfIndex, wlanIface); + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // [1] Both interface stats are changed. + // Setup the tether stats of wlan and mobile interface. Note that move forward the time of + // the looper to make sure the new tether stats has been updated by polling update thread. + setTetherOffloadStatsList(new TetherStatsParcel[] { + buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200), + buildTestTetherStatsParcel(mobileIfIndex, 3000, 300, 4000, 400)}); + + final NetworkStats expectedIfaceStats = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 1000, 100, 2000, 200)) + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 3000, 300, 4000, 400)); + + final NetworkStats expectedUidStats = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 1000, 100, 2000, 200)) + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 3000, 300, 4000, 400)); + + // Force pushing stats update to verify the stats reported. + // TODO: Perhaps make #expectNotifyStatsUpdated to use test TetherStatsParcel object for + // verifying the notification. + mTetherStatsProvider.pushTetherStats(); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStats, expectedUidStats); + + // [2] Only one interface stats is changed. + // The tether stats of mobile interface is accumulated and The tether stats of wlan + // interface is the same. + setTetherOffloadStatsList(new TetherStatsParcel[] { + buildTestTetherStatsParcel(wlanIfIndex, 1000, 100, 2000, 200), + buildTestTetherStatsParcel(mobileIfIndex, 3010, 320, 4030, 440)}); + + final NetworkStats expectedIfaceStatsDiff = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_IFACE, wlanIface, 0, 0, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_IFACE, mobileIface, 10, 20, 30, 40)); + + final NetworkStats expectedUidStatsDiff = new NetworkStats(0L, 2) + .addEntry(buildTestEntry(STATS_PER_UID, wlanIface, 0, 0, 0, 0)) + .addEntry(buildTestEntry(STATS_PER_UID, mobileIface, 10, 20, 30, 40)); + + // Force pushing stats update to verify that only diff of stats is reported. + mTetherStatsProvider.pushTetherStats(); + mTetherStatsProviderCb.expectNotifyStatsUpdated(expectedIfaceStatsDiff, + expectedUidStatsDiff); + + // [3] Stop coordinator. + // Shutdown the coordinator and clear the invocation history, especially the + // tetherOffloadGetStats() calls. + coordinator.stopPolling(); + clearInvocations(mNetd); + + // Verify the polling update thread stopped. + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + verify(mNetd, never()).tetherOffloadGetStats(); + } + + @Test + public void testOnSetAlert() throws Exception { + setupFunctioningNetdInterface(); + + final BpfCoordinator coordinator = makeBpfCoordinator(); + coordinator.startPolling(); + + final String mobileIface = "rmnet_data0"; + final Integer mobileIfIndex = 100; + coordinator.addUpstreamNameToLookupTable(mobileIfIndex, mobileIface); + + // Verify that set quota to 0 will immediately triggers a callback. + mTetherStatsProvider.onSetAlert(0); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that notifyAlertReached never fired if quota is not yet reached. + when(mNetd.tetherOffloadGetStats()).thenReturn( + new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 0, 0, 0, 0)}); + mTetherStatsProvider.onSetAlert(100); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + + // Verify that notifyAlertReached fired when quota is reached. + when(mNetd.tetherOffloadGetStats()).thenReturn( + new TetherStatsParcel[] {buildTestTetherStatsParcel(mobileIfIndex, 50, 0, 50, 0)}); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.expectNotifyAlertReached(); + + // Verify that set quota with UNLIMITED won't trigger any callback. + mTetherStatsProvider.onSetAlert(QUOTA_UNLIMITED); + mTestLooper.moveTimeForward(DEFAULT_PERFORM_POLL_INTERVAL_MS); + waitForIdle(); + mTetherStatsProviderCb.assertNoCallback(); + } +} diff --git a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java index bb65b18edb8a..8146a58dddcb 100644 --- a/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/networkstack/tethering/TetheringTest.java @@ -203,6 +203,7 @@ public class TetheringTest { @Mock private ConnectivityManager mCm; @Mock private EthernetManager mEm; @Mock private TetheringNotificationUpdater mNotificationUpdater; + @Mock private BpfCoordinator mBpfCoordinator; private final MockIpServerDependencies mIpServerDependencies = spy(new MockIpServerDependencies()); @@ -337,6 +338,12 @@ public class TetheringTest { } @Override + public BpfCoordinator getBpfCoordinator(Handler handler, INetd netd, + SharedLog log, BpfCoordinator.Dependencies deps) { + return mBpfCoordinator; + } + + @Override public OffloadHardwareInterface getOffloadHardwareInterface(Handler h, SharedLog log) { return mOffloadHardwareInterface; } diff --git a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml index 4e265fd9c5d5..0f375610865d 100644 --- a/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml +++ b/packages/overlays/IconPackCircularLauncherOverlay/res/drawable/ic_select.xml @@ -18,15 +18,6 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="#FF000000" - android:pathData="M11.25,1h1.5v3h-1.5z"/> - <path - android:fillColor="#FF000000" - android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/> - <path - android:fillColor="#FF000000" - android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/> - <path - android:fillColor="#FF000000" - android:pathData="M15.5,12.5l-1.25,0V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9L8.03,15.5c-0.39,-0.1 -1.23,-0.36 -2.56,0.97c-0.29,0.29 -0.29,0.75 -0.01,1.05l3.79,3.98c0,0 0,0 0,0.01c1.37,1.41 3.28,1.51 4.04,1.49l2.2,0c2.12,0.06 5.25,-1.01 5.25,-5.25C20.75,13.19 17.23,12.46 15.5,12.5zM15.5,21.5l-2.25,0c-0.44,0.01 -1.93,-0.02 -2.92,-1.03l-3.27,-3.43c0.17,-0.1 0.38,-0.13 0.58,-0.08l2.91,0.78c0.47,0.12 0.94,-0.23 0.94,-0.72V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.41 0.33,0.75 0.75,0.75l2.05,0c1.26,-0.03 3.7,0.37 3.7,3.75C19.25,21.14 16.78,21.53 15.5,21.5z"/> + android:fillColor="@android:color/white" + android:pathData="M18.04,13.71c-0.71,-0.77 -1.71,-1.21 -2.76,-1.21h-1.15V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-1.44,-0.38c-1.1,-0.29 -2.28,0.02 -3.09,0.83l-0.52,0.52L10.56,23h7.92l0.54,-6.44C19.1,15.52 18.75,14.48 18.04,13.71zM17.1,21.5h-5.9l-4.16,-4.37c0.32,-0.11 0.68,-0.13 1.01,-0.04l3.33,0.89V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h2.65c0.64,0 1.22,0.26 1.66,0.73c0.43,0.47 0.64,1.08 0.59,1.71L17.1,21.5zM2.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C2.25,8.51 2.51,8.25 2.81,8.25zM5.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C5.25,8.51 5.51,8.25 5.81,8.25zM17.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C17.25,8.51 17.5,8.25 17.81,8.25zM20.81,8.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V8.81C20.25,8.51 20.5,8.25 20.81,8.25zM2.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C2.25,5.5 2.51,5.25 2.81,5.25zM20.81,5.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V5.81C20.25,5.5 20.5,5.25 20.81,5.25zM2.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H2.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C2.25,2.51 2.51,2.25 2.81,2.25zM5.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H5.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C5.25,2.51 5.51,2.25 5.81,2.25zM8.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56H8.81c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C8.25,2.51 8.51,2.25 8.81,2.25zM11.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C11.25,2.51 11.51,2.25 11.81,2.25zM14.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C14.25,2.51 14.51,2.25 14.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM17.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C17.25,2.51 17.5,2.25 17.81,2.25zM20.81,2.25h0.38c0.31,0 0.56,0.26 0.56,0.56v0.38c0,0.31 -0.26,0.56 -0.56,0.56h-0.38c-0.31,0 -0.56,-0.26 -0.56,-0.56V2.81C20.25,2.51 20.5,2.25 20.81,2.25z"/> </vector> diff --git a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml index df4525d48777..51d4a1183fb9 100644 --- a/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml +++ b/packages/overlays/IconPackFilledLauncherOverlay/res/drawable/ic_select.xml @@ -18,15 +18,6 @@ android:viewportWidth="24" android:viewportHeight="24"> <path - android:fillColor="#FF000000" - android:pathData="M17.59,5.83l0.71,-0.71c0.39,-0.39 0.39,-1.02 0,-1.41l0,0c-0.39,-0.39 -1.02,-0.39 -1.41,0l-0.71,0.71c-0.39,0.39 -0.39,1.02 0,1.41C16.56,6.21 17.2,6.21 17.59,5.83z"/> - <path - android:fillColor="#FF000000" - android:pathData="M12,4c0.55,0 1,-0.45 1,-1V2c0,-0.55 -0.45,-1 -1,-1s-1,0.45 -1,1v1C11,3.55 11.45,4 12,4z"/> - <path - android:fillColor="#FF000000" - android:pathData="M6.42,5.83c0.39,0.39 1.02,0.39 1.41,0c0.39,-0.39 0.39,-1.02 0,-1.41L7.12,3.71c-0.39,-0.39 -1.02,-0.39 -1.41,0l0,0c-0.39,0.39 -0.39,1.02 0,1.41L6.42,5.83z"/> - <path - android:fillColor="#FF000000" - android:pathData="M17.95,14.43l-3.23,-1.61c-0.42,-0.21 -0.88,-0.32 -1.34,-0.32H13v-5C13,6.67 12.33,6 11.5,6C10.67,6 10,6.67 10,7.5v9.12c0,0.32 -0.29,0.55 -0.6,0.49l-2.84,-0.6c-0.37,-0.08 -0.76,0.04 -1.03,0.31c-0.43,0.44 -0.43,1.14 0.01,1.58l3.71,3.71C9.81,22.68 10.58,23 11.37,23h4.82c1.49,0 2.76,-1.1 2.97,-2.58l0.41,-2.89C19.76,16.26 19.1,15.01 17.95,14.43z"/> + android:fillColor="@android:color/white" + android:pathData="M19.09,14.75L15,12.71c-0.28,-0.14 -0.58,-0.21 -0.89,-0.21H13.5v-5C13.5,6.67 12.83,6 12,6s-1.5,0.67 -1.5,1.5v9.74L7,16.5c-0.33,-0.07 -0.68,0.03 -0.92,0.28l-0.13,0.13c-0.39,0.39 -0.38,1.02 0,1.41l4.09,4.09c0.38,0.38 0.89,0.59 1.42,0.59h6.1c1,0 1.84,-0.73 1.98,-1.72l0.63,-4.46C20.3,15.97 19.86,15.14 19.09,14.75zM2.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C2.25,9.58 2.42,9.75 2.62,9.75zM5.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C5.25,9.58 5.41,9.75 5.62,9.75zM17.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C17.25,9.58 17.42,9.75 17.62,9.75zM20.62,9.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75C20.25,9.58 20.42,9.75 20.62,9.75zM2.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,6.58 2.42,6.75 2.62,6.75zM20.62,6.75h0.75c0.21,0 0.38,-0.16 0.38,-0.38V5.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,6.58 20.42,6.75 20.62,6.75zM2.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C2.25,3.58 2.42,3.75 2.62,3.75zM5.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C5.25,3.58 5.41,3.75 5.62,3.75zM8.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C8.25,3.58 8.41,3.75 8.62,3.75zM14.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C14.25,3.58 14.41,3.75 14.62,3.75zM17.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C17.25,3.58 17.42,3.75 17.62,3.75zM20.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.17,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C20.25,3.58 20.42,3.75 20.62,3.75zM11.62,3.75h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62c0,-0.21 -0.16,-0.38 -0.38,-0.38h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75C11.25,3.58 11.41,3.75 11.62,3.75z"/> </vector> diff --git a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml index b699a4444d76..7bd92ef8687a 100644 --- a/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml +++ b/packages/overlays/IconPackRoundedLauncherOverlay/res/drawable/ic_select.xml @@ -17,16 +17,7 @@ android:height="24dp" android:viewportWidth="24" android:viewportHeight="24"> - <path - android:fillColor="#FF000000" - android:pathData="M16.19,12.5h-1.94V8.12C14.25,6.95 13.3,6 12.12,6S10,6.95 10,8.12v7.9l-3.22,-0.86l-1.82,1.82L10.68,23h8.6l1.57,-7.96L16.19,12.5zM18.04,21.5h-6.72l-4.27,-4.49l0.18,-0.18l4.28,1.14V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62V14h3.06l3.35,1.83L18.04,21.5z"/> - <path - android:fillColor="#FF000000" - android:pathData="M11.25,1h1.5v3h-1.5z"/> - <path - android:fillColor="#FF000000" - android:pathData="M15.5983,5.3402l2.1213,-2.1213l1.0606,1.0606l-2.1213,2.1213z"/> - <path - android:fillColor="#FF000000" - android:pathData="M5.2187,4.2803l1.0606,-1.0606l2.1213,2.1213l-1.0606,1.0606z"/> + <path + android:fillColor="@android:color/white" + android:pathData="M18.46,14.17l-4.33,-1.46V8.12C14.13,6.95 13.18,6 12,6S9.88,6.95 9.88,8.12v7.9l-2.3,-0.61c-0.57,-0.15 -1.18,0.01 -1.6,0.43c-0.64,0.64 -0.66,1.66 -0.03,2.32l3.79,3.99c0.52,0.54 1.24,0.85 1.99,0.85h5.16c1.31,0 2.44,-0.93 2.7,-2.22l0.69,-3.48C20.54,15.95 19.76,14.6 18.46,14.17zM18.81,17.01l-0.69,3.48c-0.11,0.58 -0.63,1.01 -1.23,1.01h-5.16c-0.34,0 -0.67,-0.14 -0.91,-0.39l-3.8,-3.99c-0.06,-0.06 -0.06,-0.16 0,-0.23c0.03,-0.03 0.07,-0.05 0.11,-0.05c0.01,0 0.03,0 0.04,0.01l3.24,0.86c0.22,0.06 0.46,0.01 0.65,-0.13c0.18,-0.14 0.29,-0.36 0.29,-0.59V8.12c0,-0.34 0.28,-0.62 0.62,-0.62s0.62,0.28 0.62,0.62v5.12c0,0.32 0.21,0.61 0.51,0.71l4.84,1.63C18.57,15.79 18.93,16.4 18.81,17.01zM3.38,8.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C3.75,8.41 3.59,8.25 3.38,8.25zM6.38,8.25H5.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C6.75,8.41 6.59,8.25 6.38,8.25zM18.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C18.75,8.41 18.59,8.25 18.38,8.25zM21.38,8.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V8.62C21.75,8.41 21.59,8.25 21.38,8.25zM3.38,5.25H2.62c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C3.75,5.41 3.59,5.25 3.38,5.25zM21.38,5.25h-0.75c-0.21,0 -0.38,0.16 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V5.62C21.75,5.41 21.59,5.25 21.38,5.25zM3.38,2.25H2.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C3.75,2.42 3.59,2.25 3.38,2.25zM6.38,2.25H5.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C6.75,2.42 6.59,2.25 6.38,2.25zM9.38,2.25H8.62c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C9.75,2.42 9.59,2.25 9.38,2.25zM12.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C12.75,2.42 12.59,2.25 12.38,2.25zM15.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C15.75,2.42 15.59,2.25 15.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM18.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C18.75,2.42 18.59,2.25 18.38,2.25zM21.38,2.25h-0.75c-0.21,0 -0.38,0.17 -0.38,0.38v0.75c0,0.21 0.16,0.38 0.38,0.38h0.75c0.21,0 0.38,-0.17 0.38,-0.38V2.62C21.75,2.42 21.59,2.25 21.38,2.25z" /> </vector> diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 642526d13aff..a9a0ab69f633 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2715,7 +2715,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState final ViewState currentView = mViewStates.get(mCurrentViewId); currentView.maybeCallOnFillReady(flags); } - } else if (viewState.id.equals(this.mCurrentViewId) + } + + if (viewState.id.equals(this.mCurrentViewId) && (viewState.getState() & ViewState.STATE_INLINE_SHOWN) != 0) { if ((viewState.getState() & ViewState.STATE_INLINE_DISABLED) != 0) { mInlineSessionController.disableFilterMatching(viewState.id); diff --git a/services/core/Android.bp b/services/core/Android.bp index 9e8a8727dc36..65e98ac8e684 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -100,7 +100,7 @@ java_library_static { "android.net.ipsec.ike.stubs.module_lib", "app-compat-annotations", "framework-tethering.stubs.module_lib", - "service-permission-stubs", + "service-permission.stubs.system_server", ], required: [ diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index c5c3cafa8813..a7bf98280af8 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4918,52 +4918,6 @@ public final class ActiveServices { if (isDeviceOwner) { return true; } - - r.mInfoDenyWhileInUsePermissionInFgs = - "Background FGS start while-in-use permission restriction [callingPackage: " - + callingPackage - + "; callingUid: " + callingUid - + "; intent: " + intent - + "]"; return false; } - - // TODO: remove this toast after feature development is done - void showWhileInUseDebugToastLocked(int uid, int op, int mode) { - final UidRecord uidRec = mAm.mProcessList.getUidRecordLocked(uid); - if (uidRec == null) { - return; - } - - for (int i = uidRec.procRecords.size() - 1; i >= 0; i--) { - ProcessRecord pr = uidRec.procRecords.valueAt(i); - if (pr.uid != uid) { - continue; - } - for (int j = pr.numberOfRunningServices() - 1; j >= 0; j--) { - ServiceRecord r = pr.getRunningServiceAt(j); - if (!r.isForeground) { - continue; - } - if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE) { - if (!r.mAllowWhileInUsePermissionInFgs - && r.mInfoDenyWhileInUsePermissionInFgs != null) { - final String msg = r.mInfoDenyWhileInUsePermissionInFgs - + " affected while-in-use permission:" - + AppOpsManager.opToPublicName(op); - Slog.wtf(TAG, msg); - } - } else if (mode == DEBUG_FGS_ENFORCE_TYPE) { - final String msg = - "FGS Missing foregroundServiceType in manifest file [callingPackage: " - + r.mRecentCallingPackage - + "; intent:" + r.intent.getIntent() - + "] affected while-in-use permission:" - + AppOpsManager.opToPublicName(op) - + "; targetSdkVersion:" + r.appInfo.targetSdkVersion; - Slog.wtf(TAG, msg); - } - } - } - } } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index caaa8371af53..026f147e955c 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -28,6 +28,7 @@ import static android.app.ActivityManager.INSTR_FLAG_DISABLE_TEST_API_CHECKS; import static android.app.ActivityManager.INSTR_FLAG_MOUNT_EXTERNAL_STORAGE_FULL; import static android.app.ActivityManager.PROCESS_STATE_LAST_ACTIVITY; import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT; +import static android.app.ActivityManager.PROCESS_STATE_TOP; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.AppOpsManager.OP_NONE; @@ -299,7 +300,6 @@ import android.util.PrintWriterPrinter; import android.util.Slog; import android.util.SparseArray; import android.util.SparseIntArray; -import android.util.SparseLongArray; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; @@ -421,7 +421,6 @@ public class ActivityManagerService extends IActivityManager.Stub * Priority we boost main thread and RT of top app to. */ public static final int TOP_APP_PRIORITY_BOOST = -10; - private static final String SYSTEM_PROPERTY_DEVICE_PROVISIONED = "persist.sys.device_provisioned"; @@ -823,45 +822,7 @@ public class ActivityManagerService extends IActivityManager.Stub } } - /** - * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj. - * The latency of the thread switch could cause client app failure when the app is checking - * {@link #isUidActive} before updateOomAdj is done. - * - * Use PendingStartActivityUids to save uid after WindowManager start activity and before - * updateOomAdj is done. - * - * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock! - */ - final PendingStartActivityUids mPendingStartActivityUidsLocked = new PendingStartActivityUids(); - final class PendingStartActivityUids { - // Key is uid, value is SystemClock.elapsedRealtime() when the key is added. - private final SparseLongArray mPendingUids = new SparseLongArray(); - - void add(int uid) { - if (mPendingUids.indexOfKey(uid) < 0) { - mPendingUids.put(uid, SystemClock.elapsedRealtime()); - } - } - - void delete(int uid) { - if (mPendingUids.indexOfKey(uid) >= 0) { - long delay = SystemClock.elapsedRealtime() - mPendingUids.get(uid); - if (delay >= 1000) { - Slog.wtf(TAG, - "PendingStartActivityUids startActivity to updateOomAdj delay:" - + delay + "ms," - + " uid:" + uid - + " packageName:" + Settings.getPackageNameForUid(mContext, uid)); - } - mPendingUids.delete(uid); - } - } - - boolean isPendingTopUid(int uid) { - return mPendingUids.indexOfKey(uid) >= 0; - } - } + private final PendingStartActivityUids mPendingStartActivityUids; /** * Puts the process record in the map. @@ -2585,6 +2546,7 @@ public class ActivityManagerService extends IActivityManager.Stub mFactoryTest = FACTORY_TEST_OFF; mUgmInternal = LocalServices.getService(UriGrantsManagerInternal.class); mInternal = new LocalService(); + mPendingStartActivityUids = new PendingStartActivityUids(mContext); } // Note: This method is invoked on the main thread but may need to attach various @@ -2742,6 +2704,7 @@ public class ActivityManagerService extends IActivityManager.Stub } mInternal = new LocalService(); + mPendingStartActivityUids = new PendingStartActivityUids(mContext); } public void setSystemServiceManager(SystemServiceManager mgr) { @@ -6093,9 +6056,18 @@ public class ActivityManagerService extends IActivityManager.Stub synchronized (mPidsSelfLocked) { for (int i = 0; i < pids.length; i++) { ProcessRecord pr = mPidsSelfLocked.get(pids[i]); - states[i] = (pr == null) ? PROCESS_STATE_NONEXISTENT : pr.getCurProcState(); - if (scores != null) { - scores[i] = (pr == null) ? ProcessList.INVALID_ADJ : pr.curAdj; + if (pr != null) { + final boolean isPendingTop = + mPendingStartActivityUids.isPendingTopPid(pr.uid, pids[i]); + states[i] = isPendingTop ? PROCESS_STATE_TOP : pr.getCurProcState(); + if (scores != null) { + scores[i] = isPendingTop ? ProcessList.FOREGROUND_APP_ADJ : pr.curAdj; + } + } else { + states[i] = PROCESS_STATE_NONEXISTENT; + if (scores != null) { + scores[i] = ProcessList.INVALID_ADJ; + } } } } @@ -8839,15 +8811,7 @@ public class ActivityManagerService extends IActivityManager.Stub return true; } } - - if (mInternal.isPendingTopUid(uid)) { - Slog.wtf(TAG, "PendingStartActivityUids isUidActive false but" - + " isPendingTopUid true, uid:" + uid - + " callingPackage:" + callingPackage); - return true; - } else { - return false; - } + return mInternal.isPendingTopUid(uid); } boolean isUidActiveLocked(int uid) { @@ -19707,15 +19671,6 @@ public class ActivityManagerService extends IActivityManager.Stub return false; } - // TODO: remove this toast after feature development is done - @Override - public void showWhileInUseDebugToast(int uid, int op, int mode) { - synchronized (ActivityManagerService.this) { - ActivityManagerService.this.mServices.showWhileInUseDebugToastLocked( - uid, op, mode); - } - } - @Override public void setDeviceOwnerUid(int uid) { synchronized (ActivityManagerService.this) { @@ -19731,22 +19686,18 @@ public class ActivityManagerService extends IActivityManager.Stub } @Override - public void updatePendingTopUid(int uid, boolean pending) { - synchronized (mPendingStartActivityUidsLocked) { - if (pending) { - mPendingStartActivityUidsLocked.add(uid); - } else { - mPendingStartActivityUidsLocked.delete(uid); - } - } + public void addPendingTopUid(int uid, int pid) { + mPendingStartActivityUids.add(uid, pid); + } + @Override + public void deletePendingTopUid(int uid) { + mPendingStartActivityUids.delete(uid); } @Override public boolean isPendingTopUid(int uid) { - synchronized (mPendingStartActivityUidsLocked) { - return mPendingStartActivityUidsLocked.isPendingTopUid(uid); - } + return mPendingStartActivityUids.isPendingTopUid(uid); } } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index 14c5b2cb12b2..da5f48962130 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -951,7 +951,7 @@ public final class OomAdjuster { mService.mServices.foregroundServiceProcStateChangedLocked(uidRec); } } - mService.mInternal.updatePendingTopUid(uidRec.uid, false); + mService.mInternal.deletePendingTopUid(uidRec.uid); } if (mLocalPowerManager != null) { mLocalPowerManager.finishUidChanges(); @@ -1508,16 +1508,7 @@ public final class OomAdjuster { capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0; - } else { - //The FGS has the location capability, but due to FGS BG start restriction it - //lost the capability, use temp location capability to mark this case. - //TODO: remove this block when development is done. - capabilityFromFGS |= - (fgsType & FOREGROUND_SERVICE_TYPE_LOCATION) != 0 - ? ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION - : 0; - } - if (s.mAllowWhileInUsePermissionInFgs) { + boolean enabled = false; try { enabled = mPlatformCompat.isChangeEnabled( @@ -1527,23 +1518,13 @@ public final class OomAdjuster { if (enabled) { capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA - : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA; + != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0; capabilityFromFGS |= (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; + != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0; } else { - // Remove fgsType check and assign PROCESS_CAPABILITY_FOREGROUND_CAMERA - // and MICROPHONE when finish debugging. - capabilityFromFGS |= - (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA - : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q; - capabilityFromFGS |= - (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE) - != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE - : ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q; + capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA + | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; } } } diff --git a/services/core/java/com/android/server/am/PendingStartActivityUids.java b/services/core/java/com/android/server/am/PendingStartActivityUids.java new file mode 100644 index 000000000000..6bf9d4e5c3f0 --- /dev/null +++ b/services/core/java/com/android/server/am/PendingStartActivityUids.java @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.am; + +import android.content.Context; +import android.os.SystemClock; +import android.util.Pair; +import android.util.Slog; +import android.util.SparseArray; + +/** + * While starting activity, WindowManager posts a runnable to DisplayThread to updateOomAdj. + * The latency of the thread switch could cause client app failure when the app is checking + * {@link ActivityManagerService#isUidActive} before updateOomAdj is done. + * + * Use PendingStartActivityUids to save uid after WindowManager start activity and before + * updateOomAdj is done. + * + * <p>NOTE: This object is protected by its own lock, NOT the global activity manager lock! + */ +final class PendingStartActivityUids { + static final String TAG = ActivityManagerService.TAG; + + // Key is uid, value is Pair of pid and SystemClock.elapsedRealtime() when the + // uid is added. + private final SparseArray<Pair<Integer, Long>> mPendingUids = new SparseArray(); + private Context mContext; + + PendingStartActivityUids(Context context) { + mContext = context; + } + + synchronized void add(int uid, int pid) { + if (mPendingUids.get(uid) == null) { + mPendingUids.put(uid, new Pair<>(pid, SystemClock.elapsedRealtime())); + } + } + + synchronized void delete(int uid) { + final Pair<Integer, Long> pendingPid = mPendingUids.get(uid); + if (pendingPid != null) { + final long delay = SystemClock.elapsedRealtime() - pendingPid.second; + if (delay >= 1000 /*ms*/) { + Slog.i(TAG, + "PendingStartActivityUids startActivity to updateOomAdj delay:" + + delay + "ms," + " uid:" + uid); + } + mPendingUids.delete(uid); + } + } + + synchronized boolean isPendingTopPid(int uid, int pid) { + final Pair<Integer, Long> pendingPid = mPendingUids.get(uid); + if (pendingPid != null) { + return pendingPid.first == pid; + } else { + return false; + } + } + + synchronized boolean isPendingTopUid(int uid) { + return mPendingUids.get(uid) != null; + } +}
\ No newline at end of file diff --git a/services/core/java/com/android/server/am/ServiceRecord.java b/services/core/java/com/android/server/am/ServiceRecord.java index 4670d58ca63b..9c96e6e02566 100644 --- a/services/core/java/com/android/server/am/ServiceRecord.java +++ b/services/core/java/com/android/server/am/ServiceRecord.java @@ -138,10 +138,7 @@ final class ServiceRecord extends Binder implements ComponentName.WithComponentN // allow while-in-use permissions in foreground service or not. // while-in-use permissions in FGS started from background might be restricted. boolean mAllowWhileInUsePermissionInFgs; - // information string what/why service is denied while-in-use permissions when - // foreground service is started from background. - // TODO: remove this field after feature development is done - String mInfoDenyWhileInUsePermissionInFgs; + // the most recent package that start/bind this service. String mRecentCallingPackage; diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index 9f2714673cd6..73c98da6aa56 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -16,11 +16,6 @@ package com.android.server.appop; -import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA; -import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q; -import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION; -import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; -import static android.app.ActivityManager.DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_CAMERA; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_LOCATION; import static android.app.ActivityManager.PROCESS_CAPABILITY_FOREGROUND_MICROPHONE; @@ -520,9 +515,6 @@ public class AppOpsService extends IAppOpsService.Stub { public SparseBooleanArray foregroundOps; public boolean hasForegroundWatchers; - public long lastTimeShowDebugToast; - public long lastTimePendingTopUid; - public UidState(int uid) { this.uid = uid; } @@ -545,7 +537,6 @@ public class AppOpsService extends IAppOpsService.Stub { return MODE_ALLOWED; } else if (mActivityManagerInternal != null && mActivityManagerInternal.isPendingTopUid(uid)) { - maybeLogPendingTopUid(op, mode); return MODE_ALLOWED; } else if (state <= UID_STATE_TOP) { // process is in TOP. @@ -559,44 +550,19 @@ public class AppOpsService extends IAppOpsService.Stub { case AppOpsManager.OP_MONITOR_HIGH_POWER_LOCATION: if ((capability & PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) { return MODE_ALLOWED; - } else if ((capability - & DEBUG_PROCESS_CAPABILITY_FOREGROUND_LOCATION) != 0) { - // The FGS has the location capability, but due to FGS BG start - // restriction it lost the capability, use temp location capability - // to mark this case. - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE); - return MODE_IGNORED; } else { return MODE_IGNORED; } case OP_CAMERA: if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { return MODE_ALLOWED; - } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) - != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_ALLOWED; - } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) - != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_IGNORED; } else { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE); return MODE_IGNORED; } case OP_RECORD_AUDIO: if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { return MODE_ALLOWED; - } else if ((capability - & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_ALLOWED; - } else if ((capability - & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_IGNORED; } else { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE); return MODE_IGNORED; } default: @@ -611,38 +577,19 @@ public class AppOpsService extends IAppOpsService.Stub { case OP_CAMERA: if (mActivityManagerInternal != null && mActivityManagerInternal.isPendingTopUid(uid)) { - maybeLogPendingTopUid(op, mode); return MODE_ALLOWED; } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { return MODE_ALLOWED; - } else if ((capability - & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA_Q) != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_ALLOWED; - } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_CAMERA) != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_IGNORED; } else { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE); return MODE_IGNORED; } case OP_RECORD_AUDIO: if (mActivityManagerInternal != null && mActivityManagerInternal.isPendingTopUid(uid)) { - maybeLogPendingTopUid(op, mode); return MODE_ALLOWED; } else if ((capability & PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) != 0) { return MODE_ALLOWED; - } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE_Q) - != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_ALLOWED; - } else if ((capability & DEBUG_PROCESS_CAPABILITY_FOREGROUND_MICROPHONE) - != 0) { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ENFORCE_TYPE); - return MODE_IGNORED; } else { - maybeShowWhileInUseDebugToast(op, DEBUG_FGS_ALLOW_WHILE_IN_USE); return MODE_IGNORED; } default: @@ -696,40 +643,6 @@ public class AppOpsService extends IAppOpsService.Stub { } foregroundOps = which; } - - // TODO: remove this toast after feature development is done - // For DEBUG_FGS_ALLOW_WHILE_IN_USE, if the procstate is foreground service and while-in-use - // permission is denied, show a toast message and generate a WTF log so we know - // how many apps are impacted by the new background started foreground service while-in-use - // permission restriction. - // For DEBUG_FGS_ENFORCE_TYPE, The process has a foreground service that does not have - // camera/microphone foregroundServiceType in manifest file, and the process is asking - // AppOps for camera/microphone ops, show a toast message and generate a WTF log. - void maybeShowWhileInUseDebugToast(int op, int mode) { - if (mode == DEBUG_FGS_ALLOW_WHILE_IN_USE && state != UID_STATE_FOREGROUND_SERVICE) { - return; - } - final long now = System.currentTimeMillis(); - if (lastTimeShowDebugToast == 0 || now - lastTimeShowDebugToast > 600000) { - lastTimeShowDebugToast = now; - mHandler.sendMessage(PooledLambda.obtainMessage( - ActivityManagerInternal::showWhileInUseDebugToast, - mActivityManagerInternal, uid, op, mode)); - } - } - - - void maybeLogPendingTopUid(int op, int mode) { - final long now = System.currentTimeMillis(); - if (lastTimePendingTopUid == 0 || now - lastTimePendingTopUid > 300000) { - lastTimePendingTopUid = now; - Slog.wtf(TAG, "PendingStartActivityUids evalMode, isPendingTopUid true, uid:" - + uid - + " packageName:" + Settings.getPackageNameForUid(mContext, uid) - + " op:" + op - + " mode:" + mode); - } - } } final static class Ops extends SparseArray<Op> { @@ -6052,7 +5965,7 @@ public class AppOpsService extends IAppOpsService.Stub { List<String> runtimeAppOpsList = getRuntimeAppOpsList(); AppOpsManager.HistoricalOpsRequest histOpsRequest = new AppOpsManager.HistoricalOpsRequest.Builder( - Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), + Math.max(Instant.now().minus(7, ChronoUnit.DAYS).toEpochMilli(), 0), Long.MAX_VALUE).setOpNames(runtimeAppOpsList).setFlags( OP_FLAG_SELF | OP_FLAG_TRUSTED_PROXIED).build(); appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index 5c6b481a60bd..45f95fd3f663 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -38,6 +38,7 @@ import android.os.Message; import android.os.PowerManager; import android.os.RemoteException; import android.os.SystemClock; +import android.text.TextUtils; import android.util.Log; import android.util.PrintWriterPrinter; @@ -329,11 +330,13 @@ import java.util.concurrent.atomic.AtomicBoolean; final BtDeviceConnectionInfo info = new BtDeviceConnectionInfo(device, state, profile, suppressNoisyIntent, a2dpVolume); + final String name = TextUtils.emptyIfNull(device.getName()); new MediaMetrics.Item(MediaMetrics.Name.AUDIO_DEVICE + MediaMetrics.SEPARATOR + "postBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent") .set(MediaMetrics.Property.STATE, state == BluetoothProfile.STATE_CONNECTED ? MediaMetrics.Value.CONNECTED : MediaMetrics.Value.DISCONNECTED) .set(MediaMetrics.Property.INDEX, a2dpVolume) + .set(MediaMetrics.Property.NAME, name) .record(); // operations of removing and posting messages related to A2DP device state change must be diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index 27d9ba08e4a2..6d45abaf0234 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -1893,7 +1893,7 @@ public class AudioService extends IAudioService.Stub Binder.getCallingUid(), true, keyEventMode); break; case KeyEvent.KEYCODE_VOLUME_MUTE: - if (event.getRepeatCount() == 0) { + if (event.getAction() == KeyEvent.ACTION_DOWN && event.getRepeatCount() == 0) { adjustSuggestedStreamVolume(AudioManager.ADJUST_TOGGLE_MUTE, AudioManager.USE_DEFAULT_STREAM_TYPE, flags, callingPackage, caller, Binder.getCallingUid(), true, VOL_ADJUST_NORMAL); @@ -2155,7 +2155,8 @@ public class AudioService extends IAudioService.Stub } int oldIndex = mStreamStates[streamType].getIndex(device); - if (adjustVolume && (direction != AudioManager.ADJUST_SAME)) { + if (adjustVolume + && (direction != AudioManager.ADJUST_SAME) && (keyEventMode != VOL_ADJUST_END)) { mAudioHandler.removeMessages(MSG_UNMUTE_STREAM); if (isMuteAdjust) { @@ -2238,6 +2239,11 @@ public class AudioService extends IAudioService.Stub if (streamTypeAlias == AudioSystem.STREAM_MUSIC) { setSystemAudioVolume(oldIndex, newIndex, getStreamMaxVolume(streamType), flags); } + } + + final int newIndex = mStreamStates[streamType].getIndex(device); + + if (adjustVolume) { synchronized (mHdmiClientLock) { if (mHdmiManager != null) { // mHdmiCecSink true => mHdmiPlaybackClient != null @@ -2290,8 +2296,7 @@ public class AudioService extends IAudioService.Stub } } } - int index = mStreamStates[streamType].getIndex(device); - sendVolumeUpdate(streamType, oldIndex, index, flags, device); + sendVolumeUpdate(streamType, oldIndex, newIndex, flags, device); } // Called after a delay when volume down is pressed while muted diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index 787f7f398fcb..6f12155c5ec6 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -28,6 +28,7 @@ import android.util.Pair; import android.util.Slog; import android.util.Spline; +import com.android.internal.BrightnessSynchronizer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.Preconditions; import com.android.server.display.utils.Plog; @@ -348,9 +349,9 @@ public abstract class BrightnessMappingStrategy { // Normalize entire brightness range to 0 - 1. protected static float normalizeAbsoluteBrightness(int brightness) { - brightness = MathUtils.constrain(brightness, - PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON); - return (float) brightness / PowerManager.BRIGHTNESS_ON; + return BrightnessSynchronizer.brightnessIntToFloat(brightness, + PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, + PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); } private Pair<float[], float[]> insertControlPoint( diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java index d38ee678c7aa..7950fcf7234c 100644 --- a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java +++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java @@ -104,8 +104,6 @@ public class ManagedProfilePasswordCache { // Generate auth-bound key to user 0 (since we the caller is user 0) .setUserAuthenticationRequired(true) .setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS) - // Only accessible after user 0's keyguard is unlocked - .setUnlockedDeviceRequired(true) .build()); key = generator.generateKey(); } catch (GeneralSecurityException e) { @@ -171,10 +169,14 @@ public class ManagedProfilePasswordCache { public void removePassword(int userId) { synchronized (mEncryptedPasswords) { String keyName = getEncryptionKeyName(userId); + String legacyKeyName = getLegacyEncryptionKeyName(userId); try { if (mKeyStore.containsAlias(keyName)) { mKeyStore.deleteEntry(keyName); } + if (mKeyStore.containsAlias(legacyKeyName)) { + mKeyStore.deleteEntry(legacyKeyName); + } } catch (KeyStoreException e) { Slog.d(TAG, "Cannot delete key", e); } @@ -186,6 +188,14 @@ public class ManagedProfilePasswordCache { } private static String getEncryptionKeyName(int userId) { + return "com.android.server.locksettings.unified_profile_cache_v2_" + userId; + } + + /** + * Returns the legacy keystore key name when setUnlockedDeviceRequired() was set explicitly. + * Only existed during Android 11 internal testing period. + */ + private static String getLegacyEncryptionKeyName(int userId) { return "com.android.server.locksettings.unified_profile_cache_" + userId; } } diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java index 0e997155e7af..c12f89c25a9e 100644 --- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java +++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java @@ -1583,7 +1583,7 @@ class MediaRouter2ServiceImpl { private void onSessionInfoChangedOnHandler(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { List<IMediaRouter2Manager> managers = getManagers(); - notifySessionInfoChangedToManagers(managers, sessionInfo); + notifySessionUpdatedToManagers(managers, sessionInfo); // For system provider, notify all routers. if (provider == mSystemProvider) { @@ -1608,7 +1608,7 @@ class MediaRouter2ServiceImpl { private void onSessionReleasedOnHandler(@NonNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo) { List<IMediaRouter2Manager> managers = getManagers(); - notifySessionInfoChangedToManagers(managers, sessionInfo); + notifySessionReleasedToManagers(managers, sessionInfo); RouterRecord routerRecord = mSessionToRouterMap.get(sessionInfo.getId()); if (routerRecord == null) { @@ -1913,15 +1913,28 @@ class MediaRouter2ServiceImpl { } } - private void notifySessionInfoChangedToManagers( + private void notifySessionUpdatedToManagers( @NonNull List<IMediaRouter2Manager> managers, @NonNull RoutingSessionInfo sessionInfo) { for (IMediaRouter2Manager manager : managers) { try { manager.notifySessionUpdated(sessionInfo); } catch (RemoteException ex) { - Slog.w(TAG, "notifySessionInfosChangedToManagers: " - + "failed to notify. Manager probably died.", ex); + Slog.w(TAG, "notifySessionUpdatedToManagers: " + + "Failed to notify. Manager probably died.", ex); + } + } + } + + private void notifySessionReleasedToManagers( + @NonNull List<IMediaRouter2Manager> managers, + @NonNull RoutingSessionInfo sessionInfo) { + for (IMediaRouter2Manager manager : managers) { + try { + manager.notifySessionReleased(sessionInfo); + } catch (RemoteException ex) { + Slog.w(TAG, "notifySessionReleasedToManagers: " + + "Failed to notify. Manager probably died.", ex); } } } diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 5585e9816783..a9139adff4f9 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -92,6 +92,7 @@ import static android.service.notification.NotificationListenerService.TRIM_FULL import static android.service.notification.NotificationListenerService.TRIM_LIGHT; import static android.view.WindowManager.LayoutParams.TYPE_TOAST; +import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES; import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES; @@ -1906,7 +1907,8 @@ public class NotificationManagerService extends SystemService { mMetricsLogger = new MetricsLogger(); mRankingHandler = rankingHandler; mConditionProviders = conditionProviders; - mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders); + mZenModeHelper = new ZenModeHelper(getContext(), mHandler.getLooper(), mConditionProviders, + new SysUiStatsEvent.BuilderFactory()); mZenModeHelper.addCallback(new ZenModeHelper.Callback() { @Override public void onConfigChanged() { @@ -2189,6 +2191,12 @@ public class NotificationManagerService extends SystemService { ConcurrentUtils.DIRECT_EXECUTOR, mPullAtomCallback ); + mStatsManager.setPullAtomCallback( + DND_MODE_RULE, + null, // use default PullAtomMetadata values + BackgroundThread.getExecutor(), + mPullAtomCallback + ); } private class StatsPullAtomCallbackImpl implements StatsManager.StatsPullAtomCallback { @@ -2198,6 +2206,7 @@ public class NotificationManagerService extends SystemService { case PACKAGE_NOTIFICATION_PREFERENCES: case PACKAGE_NOTIFICATION_CHANNEL_PREFERENCES: case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: + case DND_MODE_RULE: return pullNotificationStates(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); @@ -2216,6 +2225,9 @@ public class NotificationManagerService extends SystemService { case PACKAGE_NOTIFICATION_CHANNEL_GROUP_PREFERENCES: mPreferencesHelper.pullPackageChannelGroupPreferencesStats(data); break; + case DND_MODE_RULE: + mZenModeHelper.pullRules(data); + break; } return StatsManager.PULL_SUCCESS; } @@ -4015,7 +4027,7 @@ public class NotificationManagerService extends SystemService { private void cancelNotificationFromListenerLocked(ManagedServiceInfo info, int callingUid, int callingPid, String pkg, String tag, int id, int userId) { cancelNotification(callingUid, callingPid, pkg, tag, id, 0, - FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE | FLAG_BUBBLE, + FLAG_ONGOING_EVENT | FLAG_FOREGROUND_SERVICE, true, userId, REASON_LISTENER_CANCEL, info); } @@ -6248,6 +6260,13 @@ public class NotificationManagerService extends SystemService { mUsageStats.registerClickedByUser(r); } + if (mReason == REASON_LISTENER_CANCEL + && (r.getNotification().flags & FLAG_BUBBLE) != 0) { + mNotificationDelegate.onBubbleNotificationSuppressionChanged( + r.getKey(), /* suppressed */ true); + return; + } + if ((r.getNotification().flags & mMustHaveFlags) != mMustHaveFlags) { return; } diff --git a/services/core/java/com/android/server/notification/SysUiStatsEvent.java b/services/core/java/com/android/server/notification/SysUiStatsEvent.java index 9bc2346d4e96..90737bdeae4a 100644 --- a/services/core/java/com/android/server/notification/SysUiStatsEvent.java +++ b/services/core/java/com/android/server/notification/SysUiStatsEvent.java @@ -58,6 +58,11 @@ public class SysUiStatsEvent { mBuilder.writeBoolean(value); return this; } + + public Builder writeByteArray(byte[] value) { + mBuilder.writeByteArray(value); + return this; + } } static class BuilderFactory { diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java index a490b9c99bb4..4931d3f3e95c 100644 --- a/services/core/java/com/android/server/notification/ZenModeHelper.java +++ b/services/core/java/com/android/server/notification/ZenModeHelper.java @@ -20,6 +20,10 @@ import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_DISABLED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_ENABLED; import static android.app.NotificationManager.AUTOMATIC_RULE_STATUS_REMOVED; import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY; +import static android.service.notification.DNDModeProto.ROOT_CONFIG; + +import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID; +import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; import android.app.AppOpsManager; import android.app.AutomaticZenRule; @@ -67,6 +71,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.Slog; import android.util.SparseArray; +import android.util.StatsEvent; import android.util.proto.ProtoOutputStream; import com.android.internal.R; @@ -103,6 +108,7 @@ public class ZenModeHelper { private final SettingsObserver mSettingsObserver; private final AppOpsManager mAppOps; @VisibleForTesting protected final NotificationManager mNotificationManager; + private final SysUiStatsEvent.BuilderFactory mStatsEventBuilderFactory; @VisibleForTesting protected ZenModeConfig mDefaultConfig; private final ArrayList<Callback> mCallbacks = new ArrayList<Callback>(); private final ZenModeFiltering mFiltering; @@ -130,7 +136,8 @@ public class ZenModeHelper { private String[] mPriorityOnlyDndExemptPackages; - public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders) { + public ZenModeHelper(Context context, Looper looper, ConditionProviders conditionProviders, + SysUiStatsEvent.BuilderFactory statsEventBuilderFactory) { mContext = context; mHandler = new H(looper); addCallback(mMetrics); @@ -148,6 +155,7 @@ public class ZenModeHelper { mFiltering = new ZenModeFiltering(mContext); mConditions = new ZenModeConditions(this, conditionProviders); mServiceConfig = conditionProviders.getConfig(); + mStatsEventBuilderFactory = statsEventBuilderFactory; } public Looper getLooper() { @@ -1170,6 +1178,72 @@ public class ZenModeHelper { } } + /** + * Generate pulled atoms about do not disturb configurations. + */ + public void pullRules(List<StatsEvent> events) { + synchronized (mConfig) { + final int numConfigs = mConfigs.size(); + int id = 0; + for (int i = 0; i < numConfigs; i++) { + final int user = mConfigs.keyAt(i); + final ZenModeConfig config = mConfigs.valueAt(i); + SysUiStatsEvent.Builder data = mStatsEventBuilderFactory.newBuilder() + .setAtomId(DND_MODE_RULE) + .writeInt(user) + .writeBoolean(config.manualRule != null) // enabled + .writeBoolean(config.areChannelsBypassingDnd) + .writeInt(ROOT_CONFIG) + .writeString("") // name, empty for root config + .writeInt(Process.SYSTEM_UID) // system owns root config + .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true) + .writeByteArray(config.toZenPolicy().toProto()); + events.add(data.build()); + if (config.manualRule != null && config.manualRule.enabler != null) { + ruleToProto(user, config.manualRule, events); + } + for (ZenRule rule : config.automaticRules.values()) { + ruleToProto(user, rule, events); + } + } + } + } + + private void ruleToProto(int user, ZenRule rule, List<StatsEvent> events) { + // Make the ID safe. + String id = rule.id == null ? "" : rule.id; + if (!ZenModeConfig.DEFAULT_RULE_IDS.contains(id)) { + id = ""; + } + + // Look for packages and enablers, enablers get priority. + String pkg = rule.pkg == null ? "" : rule.pkg; + if (rule.enabler != null) { + pkg = rule.enabler; + id = ZenModeConfig.MANUAL_RULE_ID; + } + + // TODO: fetch the uid from the package manager + int uid = "android".equals(pkg) ? Process.SYSTEM_UID : 0; + + SysUiStatsEvent.Builder data; + data = mStatsEventBuilderFactory.newBuilder() + .setAtomId(DND_MODE_RULE) + .writeInt(user) + .writeBoolean(rule.enabled) + .writeBoolean(false) // channels_bypassing unused for rules + .writeInt(rule.zenMode) + .writeString(id) + .writeInt(uid) + .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true); + byte[] policyProto = new byte[]{}; + if (rule.zenPolicy != null) { + policyProto = rule.zenPolicy.toProto(); + } + data.writeByteArray(policyProto); + events.add(data.build()); + } + @VisibleForTesting protected final class RingerModeDelegate implements AudioManagerInternal.RingerModeDelegate { @Override diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java index 4b6ee71803a7..ba60f179e661 100644 --- a/services/core/java/com/android/server/pm/AppsFilter.java +++ b/services/core/java/com/android/server/pm/AppsFilter.java @@ -19,6 +19,8 @@ package com.android.server.pm; import static android.os.Trace.TRACE_TAG_PACKAGE_MANAGER; import static android.provider.DeviceConfig.NAMESPACE_PACKAGE_MANAGER_SERVICE; +import static com.android.internal.annotations.VisibleForTesting.Visibility.PRIVATE; + import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; @@ -109,12 +111,25 @@ public class AppsFilter { private final boolean mSystemAppsQueryable; private final FeatureConfig mFeatureConfig; - private final OverlayReferenceMapper mOverlayReferenceMapper; + private final StateProvider mStateProvider; + private PackageParser.SigningDetails mSystemSigningDetails; private Set<String> mProtectedBroadcasts = new ArraySet<>(); - AppsFilter(FeatureConfig featureConfig, String[] forceQueryableWhitelist, + /** + * This structure maps uid -> uid and indicates whether access from the first should be + * filtered to the second. It's essentially a cache of the + * {@link #shouldFilterApplicationInternal(int, SettingBase, PackageSetting, int)} call. + * NOTE: It can only be relied upon after the system is ready to avoid unnecessary update on + * initial scan and is null until {@link #onSystemReady()} is called. + */ + private volatile SparseArray<SparseBooleanArray> mShouldFilterCache; + + @VisibleForTesting(visibility = PRIVATE) + AppsFilter(StateProvider stateProvider, + FeatureConfig featureConfig, + String[] forceQueryableWhitelist, boolean systemAppsQueryable, @Nullable OverlayReferenceMapper.Provider overlayProvider) { mFeatureConfig = featureConfig; @@ -122,8 +137,23 @@ public class AppsFilter { mSystemAppsQueryable = systemAppsQueryable; mOverlayReferenceMapper = new OverlayReferenceMapper(true /*deferRebuild*/, overlayProvider); + mStateProvider = stateProvider; + } + + /** + * Provides system state to AppsFilter via {@link CurrentStateCallback} after properly guarding + * the data with the package lock. + */ + @VisibleForTesting(visibility = PRIVATE) + public interface StateProvider { + void runWithState(CurrentStateCallback callback); + + interface CurrentStateCallback { + void currentState(ArrayMap<String, PackageSetting> settings, int[] users); + } } + @VisibleForTesting(visibility = PRIVATE) public interface FeatureConfig { /** Called when the system is ready and components can be queried. */ @@ -140,6 +170,7 @@ public class AppsFilter { /** * Turns on logging for the given appId + * * @param enable true if logging should be enabled, false if disabled. */ void enableLogging(int appId, boolean enable); @@ -147,6 +178,7 @@ public class AppsFilter { /** * Initializes the package enablement state for the given package. This gives opportunity * to do any expensive operations ahead of the actual checks. + * * @param removed true if adding, false if removing */ void updatePackageState(PackageSetting setting, boolean removed); @@ -162,6 +194,7 @@ public class AppsFilter { @Nullable private SparseBooleanArray mLoggingEnabled = null; + private AppsFilter mAppsFilter; private FeatureConfigImpl( PackageManagerInternal pmInternal, PackageManagerService.Injector injector) { @@ -169,6 +202,10 @@ public class AppsFilter { mInjector = injector; } + public void setAppsFilter(AppsFilter filter) { + mAppsFilter = filter; + } + @Override public void onSystemReady() { mFeatureEnabled = DeviceConfig.getBoolean( @@ -235,27 +272,28 @@ public class AppsFilter { @Override public void onCompatChange(String packageName) { - updateEnabledState(mPmInternal.getPackage(packageName)); - } - - private void updateEnabledState(AndroidPackage pkg) { final long token = Binder.clearCallingIdentity(); try { - // TODO(b/135203078): Do not use toAppInfo - final boolean enabled = - mInjector.getCompatibility().isChangeEnabled( - PackageManager.FILTER_APPLICATION_QUERY, - pkg.toAppInfoWithoutState()); - if (enabled) { - mDisabledPackages.remove(pkg.getPackageName()); - } else { - mDisabledPackages.add(pkg.getPackageName()); - } + updateEnabledState(mPmInternal.getPackage(packageName)); + mAppsFilter.updateShouldFilterCacheForPackage(packageName); } finally { Binder.restoreCallingIdentity(token); } } + private void updateEnabledState(AndroidPackage pkg) { + // TODO(b/135203078): Do not use toAppInfo + final boolean enabled = + mInjector.getCompatibility().isChangeEnabled( + PackageManager.FILTER_APPLICATION_QUERY, + pkg.toAppInfoWithoutState()); + if (enabled) { + mDisabledPackages.remove(pkg.getPackageName()); + } else { + mDisabledPackages.add(pkg.getPackageName()); + } + } + @Override public void updatePackageState(PackageSetting setting, boolean removed) { final boolean enableLogging = @@ -275,7 +313,7 @@ public class AppsFilter { final boolean forceSystemAppsQueryable = injector.getContext().getResources() .getBoolean(R.bool.config_forceSystemPackagesQueryable); - final FeatureConfig featureConfig = new FeatureConfigImpl(pms, injector); + final FeatureConfigImpl featureConfig = new FeatureConfigImpl(pms, injector); final String[] forcedQueryablePackageNames; if (forceSystemAppsQueryable) { // all system apps already queryable, no need to read and parse individual exceptions @@ -288,8 +326,16 @@ public class AppsFilter { forcedQueryablePackageNames[i] = forcedQueryablePackageNames[i].intern(); } } - return new AppsFilter(featureConfig, forcedQueryablePackageNames, - forceSystemAppsQueryable, null); + final StateProvider stateProvider = command -> { + synchronized (injector.getLock()) { + command.currentState(injector.getSettings().mPackages, + injector.getUserManagerInternal().getUserIds()); + } + }; + AppsFilter appsFilter = new AppsFilter(stateProvider, featureConfig, + forcedQueryablePackageNames, forceSystemAppsQueryable, null); + featureConfig.setAppsFilter(appsFilter); + return appsFilter; } public FeatureConfig getFeatureConfig() { @@ -412,28 +458,54 @@ public class AppsFilter { * visibility of the caller from the target. * * @param recipientUid the uid gaining visibility of the {@code visibleUid}. - * @param visibleUid the uid becoming visible to the {@recipientUid} + * @param visibleUid the uid becoming visible to the {@recipientUid} */ public void grantImplicitAccess(int recipientUid, int visibleUid) { - if (recipientUid != visibleUid - && mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { - Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); + if (recipientUid != visibleUid) { + if (mImplicitlyQueryable.add(recipientUid, visibleUid) && DEBUG_LOGGING) { + Slog.i(TAG, "implicit access granted: " + recipientUid + " -> " + visibleUid); + } + if (mShouldFilterCache != null) { + // update the cache in a one-off manner since we've got all the information we need. + SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid); + if (visibleUids == null) { + visibleUids = new SparseBooleanArray(); + mShouldFilterCache.put(recipientUid, visibleUids); + } + visibleUids.put(visibleUid, false); + } } } public void onSystemReady() { + mShouldFilterCache = new SparseArray<>(); mFeatureConfig.onSystemReady(); mOverlayReferenceMapper.rebuildIfDeferred(); + updateEntireShouldFilterCache(); } /** * Adds a package that should be considered when filtering visibility between apps. * - * @param newPkgSetting the new setting being added - * @param existingSettings all other settings currently on the device. + * @param newPkgSetting the new setting being added */ - public void addPackage(PackageSetting newPkgSetting, - ArrayMap<String, PackageSetting> existingSettings) { + public void addPackage(PackageSetting newPkgSetting) { + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); + try { + mStateProvider.runWithState((settings, users) -> { + addPackageInternal(newPkgSetting, settings, users); + if (mShouldFilterCache != null) { + updateShouldFilterCacheForPackage( + null, newPkgSetting, settings, users, settings.size()); + } // else, rebuild entire cache when system is ready + }); + } finally { + Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); + } + } + + private void addPackageInternal(PackageSetting newPkgSetting, + ArrayMap<String, PackageSetting> existingSettings, int[] allUsers) { if (Objects.equals("android", newPkgSetting.name)) { // let's set aside the framework signatures mSystemSigningDetails = newPkgSetting.signatures.mSigningDetails; @@ -446,79 +518,151 @@ public class AppsFilter { } } - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "filter.addPackage"); - try { - final AndroidPackage newPkg = newPkgSetting.pkg; - if (newPkg == null) { - // nothing to add - return; - } + final AndroidPackage newPkg = newPkgSetting.pkg; + if (newPkg == null) { + // nothing to add + return; + } - if (!newPkg.getProtectedBroadcasts().isEmpty()) { - mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts()); - recomputeComponentVisibility(existingSettings, newPkg.getPackageName()); - } + if (!newPkg.getProtectedBroadcasts().isEmpty()) { + mProtectedBroadcasts.addAll(newPkg.getProtectedBroadcasts()); + recomputeComponentVisibility(existingSettings, newPkg.getPackageName()); + } - final boolean newIsForceQueryable = - mForceQueryable.contains(newPkgSetting.appId) - /* shared user that is already force queryable */ - || newPkg.isForceQueryable() - || newPkgSetting.forceQueryableOverride - || (newPkgSetting.isSystem() && (mSystemAppsQueryable - || ArrayUtils.contains(mForceQueryableByDevicePackageNames, - newPkg.getPackageName()))); - if (newIsForceQueryable - || (mSystemSigningDetails != null - && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { - mForceQueryable.add(newPkgSetting.appId); - } + final boolean newIsForceQueryable = + mForceQueryable.contains(newPkgSetting.appId) + /* shared user that is already force queryable */ + || newPkg.isForceQueryable() + || newPkgSetting.forceQueryableOverride + || (newPkgSetting.isSystem() && (mSystemAppsQueryable + || ArrayUtils.contains(mForceQueryableByDevicePackageNames, + newPkg.getPackageName()))); + if (newIsForceQueryable + || (mSystemSigningDetails != null + && isSystemSigned(mSystemSigningDetails, newPkgSetting))) { + mForceQueryable.add(newPkgSetting.appId); + } - for (int i = existingSettings.size() - 1; i >= 0; i--) { - final PackageSetting existingSetting = existingSettings.valueAt(i); - if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { - continue; + for (int i = existingSettings.size() - 1; i >= 0; i--) { + final PackageSetting existingSetting = existingSettings.valueAt(i); + if (existingSetting.appId == newPkgSetting.appId || existingSetting.pkg == null) { + continue; + } + final AndroidPackage existingPkg = existingSetting.pkg; + // let's evaluate the ability of already added packages to see this new package + if (!newIsForceQueryable) { + if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); } - final AndroidPackage existingPkg = existingSetting.pkg; - // let's evaluate the ability of already added packages to see this new package - if (!newIsForceQueryable) { - if (canQueryViaComponents(existingPkg, newPkg, mProtectedBroadcasts)) { - mQueriesViaComponent.add(existingSetting.appId, newPkgSetting.appId); - } - if (canQueryViaPackage(existingPkg, newPkg) - || canQueryAsInstaller(existingSetting, newPkg)) { - mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); - } + if (canQueryViaPackage(existingPkg, newPkg) + || canQueryAsInstaller(existingSetting, newPkg)) { + mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } - // now we'll evaluate our new package's ability to see existing packages - if (!mForceQueryable.contains(existingSetting.appId)) { - if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { - mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); - } - if (canQueryViaPackage(newPkg, existingPkg) - || canQueryAsInstaller(newPkgSetting, existingPkg)) { - mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); - } + } + // now we'll evaluate our new package's ability to see existing packages + if (!mForceQueryable.contains(existingSetting.appId)) { + if (canQueryViaComponents(newPkg, existingPkg, mProtectedBroadcasts)) { + mQueriesViaComponent.add(newPkgSetting.appId, existingSetting.appId); } - // if either package instruments the other, mark both as visible to one another - if (pkgInstruments(newPkgSetting, existingSetting) - || pkgInstruments(existingSetting, newPkgSetting)) { + if (canQueryViaPackage(newPkg, existingPkg) + || canQueryAsInstaller(newPkgSetting, existingPkg)) { mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); - mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); } } + // if either package instruments the other, mark both as visible to one another + if (pkgInstruments(newPkgSetting, existingSetting) + || pkgInstruments(existingSetting, newPkgSetting)) { + mQueriesViaPackage.add(newPkgSetting.appId, existingSetting.appId); + mQueriesViaPackage.add(existingSetting.appId, newPkgSetting.appId); + } + } - int existingSize = existingSettings.size(); - ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); - for (int index = 0; index < existingSize; index++) { - PackageSetting pkgSetting = existingSettings.valueAt(index); - if (pkgSetting.pkg != null) { - existingPkgs.put(pkgSetting.name, pkgSetting.pkg); + int existingSize = existingSettings.size(); + ArrayMap<String, AndroidPackage> existingPkgs = new ArrayMap<>(existingSize); + for (int index = 0; index < existingSize; index++) { + PackageSetting pkgSetting = existingSettings.valueAt(index); + if (pkgSetting.pkg != null) { + existingPkgs.put(pkgSetting.name, pkgSetting.pkg); + } + } + mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); + mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); + } + + private void removeAppIdFromVisibilityCache(int appId) { + if (mShouldFilterCache == null) { + return; + } + for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) { + if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) { + mShouldFilterCache.removeAt(i); + continue; + } + SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i); + for (int j = targetSparseArray.size() - 1; j >= 0; j--) { + if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) { + targetSparseArray.removeAt(j); + } + } + } + } + + private void updateEntireShouldFilterCache() { + mStateProvider.runWithState((settings, users) -> { + mShouldFilterCache.clear(); + for (int i = settings.size() - 1; i >= 0; i--) { + updateShouldFilterCacheForPackage( + null /*skipPackage*/, settings.valueAt(i), settings, users, i); + } + }); + } + + public void onUsersChanged() { + if (mShouldFilterCache != null) { + updateEntireShouldFilterCache(); + } + } + + private void updateShouldFilterCacheForPackage(String packageName) { + mStateProvider.runWithState((settings, users) -> { + updateShouldFilterCacheForPackage(null /* skipPackage */, settings.get(packageName), + settings, users, settings.size() /*maxIndex*/); + }); + + } + + private void updateShouldFilterCacheForPackage(@Nullable String skipPackageName, + PackageSetting subjectSetting, ArrayMap<String, PackageSetting> allSettings, + int[] allUsers, int maxIndex) { + for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) { + PackageSetting otherSetting = allSettings.valueAt(i); + if (subjectSetting.appId == otherSetting.appId) { + continue; + } + //noinspection StringEquality + if (subjectSetting.name == skipPackageName || otherSetting.name == skipPackageName) { + continue; + } + for (int su = 0; su < allUsers.length; su++) { + int subjectUser = allUsers[su]; + for (int ou = su; ou < allUsers.length; ou++) { + int otherUser = allUsers[ou]; + int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId); + if (!mShouldFilterCache.contains(subjectUid)) { + mShouldFilterCache.put(subjectUid, new SparseBooleanArray()); + } + int otherUid = UserHandle.getUid(otherUser, otherSetting.appId); + if (!mShouldFilterCache.contains(otherUid)) { + mShouldFilterCache.put(otherUid, new SparseBooleanArray()); + } + mShouldFilterCache.get(subjectUid).put(otherUid, + shouldFilterApplicationInternal( + subjectUid, subjectSetting, otherSetting, otherUser)); + mShouldFilterCache.get(otherUid).put(subjectUid, + shouldFilterApplicationInternal( + otherUid, otherSetting, subjectSetting, subjectUser)); } } - mOverlayReferenceMapper.addPkg(newPkgSetting.pkg, existingPkgs); - mFeatureConfig.updatePackageState(newPkgSetting, false /*removed*/); - } finally { - Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } @@ -569,6 +713,7 @@ public class AppsFilter { } } } + /** * Fetches all app Ids that a given setting is currently visible to, per provided user. This * only includes UIDs >= {@link Process#FIRST_APPLICATION_UID} as all other UIDs can already see @@ -577,11 +722,11 @@ public class AppsFilter { * If the setting is visible to all UIDs, null is returned. If an app is not visible to any * applications, the int array will be empty. * - * @param users the set of users that should be evaluated for this calculation + * @param users the set of users that should be evaluated for this calculation * @param existingSettings the set of all package settings that currently exist on device * @return a SparseArray mapping userIds to a sorted int array of appIds that may view the - * provided setting or null if the app is visible to all and no whitelist should be - * applied. + * provided setting or null if the app is visible to all and no whitelist should be + * applied. */ @Nullable public SparseArray<int[]> getVisibilityWhitelist(PackageSetting setting, int[] users, @@ -626,52 +771,60 @@ public class AppsFilter { /** * Removes a package for consideration when filtering visibility between apps. * - * @param setting the setting of the package being removed. - * @param allUsers array of all current users on device. + * @param setting the setting of the package being removed. */ - public void removePackage(PackageSetting setting, int[] allUsers, - ArrayMap<String, PackageSetting> existingSettings) { - mForceQueryable.remove(setting.appId); - - for (int u = 0; u < allUsers.length; u++) { - final int userId = allUsers[u]; - final int removingUid = UserHandle.getUid(userId, setting.appId); - mImplicitlyQueryable.remove(removingUid); - for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { - mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid); + public void removePackage(PackageSetting setting) { + removeAppIdFromVisibilityCache(setting.appId); + mStateProvider.runWithState((settings, users) -> { + for (int u = 0; u < users.length; u++) { + final int userId = users[u]; + final int removingUid = UserHandle.getUid(userId, setting.appId); + mImplicitlyQueryable.remove(removingUid); + for (int i = mImplicitlyQueryable.size() - 1; i >= 0; i--) { + mImplicitlyQueryable.remove(mImplicitlyQueryable.keyAt(i), removingUid); + } } - } - mQueriesViaComponent.remove(setting.appId); - for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { - mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId); - } - mQueriesViaPackage.remove(setting.appId); - for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { - mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); - } + mQueriesViaComponent.remove(setting.appId); + for (int i = mQueriesViaComponent.size() - 1; i >= 0; i--) { + mQueriesViaComponent.remove(mQueriesViaComponent.keyAt(i), setting.appId); + } + mQueriesViaPackage.remove(setting.appId); + for (int i = mQueriesViaPackage.size() - 1; i >= 0; i--) { + mQueriesViaPackage.remove(mQueriesViaPackage.keyAt(i), setting.appId); + } - // re-add other shared user members to re-establish visibility between them and other - // packages - if (setting.sharedUser != null) { - for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { - if (setting.sharedUser.packages.valueAt(i) == setting) { - continue; + // re-add other shared user members to re-establish visibility between them and other + // packages + if (setting.sharedUser != null) { + for (int i = setting.sharedUser.packages.size() - 1; i >= 0; i--) { + if (setting.sharedUser.packages.valueAt(i) == setting) { + continue; + } + addPackageInternal( + setting.sharedUser.packages.valueAt(i), settings, users); } - addPackage(setting.sharedUser.packages.valueAt(i), existingSettings); } - } - if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { - final String removingPackageName = setting.pkg.getPackageName(); - mProtectedBroadcasts.clear(); - mProtectedBroadcasts.addAll( - collectProtectedBroadcasts(existingSettings, removingPackageName)); - recomputeComponentVisibility(existingSettings, removingPackageName); - } + if (!setting.pkg.getProtectedBroadcasts().isEmpty()) { + final String removingPackageName = setting.pkg.getPackageName(); + mProtectedBroadcasts.clear(); + mProtectedBroadcasts.addAll( + collectProtectedBroadcasts(settings, removingPackageName)); + recomputeComponentVisibility(settings, removingPackageName); + } + + mOverlayReferenceMapper.removePkg(setting.name); + mFeatureConfig.updatePackageState(setting, true /*removed*/); + + if (mShouldFilterCache != null) { + updateShouldFilterCacheForPackage( + setting.name, setting, settings, users, settings.size()); + } + }); + mForceQueryable.remove(setting.appId); + - mOverlayReferenceMapper.removePkg(setting.name); - mFeatureConfig.updatePackageState(setting, true /*removed*/); } /** @@ -688,11 +841,32 @@ public class AppsFilter { PackageSetting targetPkgSetting, int userId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplication"); try { - - if (!shouldFilterApplicationInternal( - callingUid, callingSetting, targetPkgSetting, userId)) { + if (callingUid < Process.FIRST_APPLICATION_UID + || UserHandle.getAppId(callingUid) == targetPkgSetting.appId) { return false; } + if (mShouldFilterCache != null) { // use cache + SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid); + final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId); + if (shouldFilterTargets == null) { + Slog.wtf(TAG, "Encountered calling uid with no cached rules: " + callingUid); + return true; + } + int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid); + if (indexOfTargetUid < 0) { + Slog.w(TAG, "Encountered calling -> target with no cached rules: " + + callingUid + " -> " + targetUid); + return true; + } + if (!shouldFilterTargets.valueAt(indexOfTargetUid)) { + return false; + } + } else { + if (!shouldFilterApplicationInternal( + callingUid, callingSetting, targetPkgSetting, userId)) { + return false; + } + } if (DEBUG_LOGGING || mFeatureConfig.isLoggingEnabled(UserHandle.getAppId(callingUid))) { log(callingSetting, targetPkgSetting, "BLOCKED"); } @@ -703,7 +877,7 @@ public class AppsFilter { } private boolean shouldFilterApplicationInternal(int callingUid, SettingBase callingSetting, - PackageSetting targetPkgSetting, int userId) { + PackageSetting targetPkgSetting, int targetUserId) { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "shouldFilterApplicationInternal"); try { final boolean featureEnabled = mFeatureConfig.isGloballyEnabled(); @@ -713,12 +887,6 @@ public class AppsFilter { } return false; } - if (callingUid < Process.FIRST_APPLICATION_UID) { - if (DEBUG_LOGGING) { - Slog.d(TAG, "filtering skipped; " + callingUid + " is system"); - } - return false; - } if (callingSetting == null) { Slog.wtf(TAG, "No setting found for non system uid " + callingUid); return true; @@ -727,8 +895,14 @@ public class AppsFilter { final ArraySet<PackageSetting> callingSharedPkgSettings; Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "callingSetting instanceof"); if (callingSetting instanceof PackageSetting) { - callingPkgSetting = (PackageSetting) callingSetting; - callingSharedPkgSettings = null; + if (((PackageSetting) callingSetting).sharedUser == null) { + callingPkgSetting = (PackageSetting) callingSetting; + callingSharedPkgSettings = null; + } else { + callingPkgSetting = null; + callingSharedPkgSettings = + ((PackageSetting) callingSetting).sharedUser.packages; + } } else { callingPkgSetting = null; callingSharedPkgSettings = ((SharedUserSetting) callingSetting).packages; @@ -786,13 +960,17 @@ public class AppsFilter { } try { - Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "hasPermission"); - if (callingSetting.getPermissionsState().hasPermission( - Manifest.permission.QUERY_ALL_PACKAGES, UserHandle.getUserId(callingUid))) { - if (DEBUG_LOGGING) { - log(callingSetting, targetPkgSetting, "has query-all permission"); + Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "requestsQueryAllPackages"); + if (callingPkgSetting != null) { + if (requestsQueryAllPackages(callingPkgSetting)) { + return false; + } + } else { + for (int i = callingSharedPkgSettings.size() - 1; i >= 0; i--) { + if (requestsQueryAllPackages(callingSharedPkgSettings.valueAt(i))) { + return false; + } } - return false; } } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); @@ -833,7 +1011,7 @@ public class AppsFilter { try { Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "mImplicitlyQueryable"); - final int targetUid = UserHandle.getUid(userId, targetAppId); + final int targetUid = UserHandle.getUid(targetUserId, targetAppId); if (mImplicitlyQueryable.contains(callingUid, targetUid)) { if (DEBUG_LOGGING) { log(callingSetting, targetPkgSetting, "implicitly queryable for user"); @@ -871,13 +1049,20 @@ public class AppsFilter { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } - return true; } finally { Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER); } } + + private static boolean requestsQueryAllPackages(PackageSetting pkgSetting) { + // we're not guaranteed to have permissions yet analyzed at package add, so we inspect the + // package directly + return pkgSetting.pkg.getRequestedPermissions().contains( + Manifest.permission.QUERY_ALL_PACKAGES); + } + /** Returns {@code true} if the source package instruments the target package. */ private static boolean pkgInstruments(PackageSetting source, PackageSetting target) { try { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 766fae64f647..fd37f041450e 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -10713,6 +10713,20 @@ public class PackageManagerService extends IPackageManager.Stub return resultList; } + private int getVendorPartitionVersion() { + final String version = SystemProperties.get("ro.vndk.version"); + if (!version.isEmpty()) { + try { + return Integer.parseInt(version); + } catch (NumberFormatException ignore) { + if (ArrayUtils.contains(Build.VERSION.ACTIVE_CODENAMES, version)) { + return Build.VERSION_CODES.CUR_DEVELOPMENT; + } + } + } + return Build.VERSION_CODES.P; + } + @GuardedBy({"mInstallLock", "mLock"}) private ScanResult scanPackageTracedLI(ParsedPackage parsedPackage, final @ParseFlags int parseFlags, @ScanFlags int scanFlags, long currentTime, @@ -10894,7 +10908,7 @@ public class PackageManagerService extends IPackageManager.Stub // Scan as privileged apps that share a user with a priv-app. final boolean skipVendorPrivilegeScan = ((scanFlags & SCAN_AS_VENDOR) != 0) - && SystemProperties.getInt("ro.vndk.version", 28) < 28; + && getVendorPartitionVersion() < 28; if (((scanFlags & SCAN_AS_PRIVILEGED) == 0) && !pkg.isPrivileged() && (pkg.getSharedUserId() != null) @@ -12070,6 +12084,20 @@ public class PackageManagerService extends IPackageManager.Stub + pkg.getPackageName() + " is static and cannot be upgraded."); } + } else { + if ((scanFlags & SCAN_AS_VENDOR) != 0) { + if (pkg.getTargetSdkVersion() < getVendorPartitionVersion()) { + Slog.w(TAG, "System overlay " + pkg.getPackageName() + + " targets an SDK below the required SDK level of vendor" + + " overlays (" + getVendorPartitionVersion() + ")." + + " This will become an install error in a future release"); + } + } else if (pkg.getTargetSdkVersion() < Build.VERSION.SDK_INT) { + Slog.w(TAG, "System overlay " + pkg.getPackageName() + + " targets an SDK below the required SDK level of system" + + " overlays (" + Build.VERSION.SDK_INT + ")." + + " This will become an install error in a future release"); + } } } else { // A non-preloaded overlay packages must have targetSdkVersion >= Q, or be @@ -12334,7 +12362,7 @@ public class PackageManagerService extends IPackageManager.Stub ksms.addScannedPackageLPw(pkg); mComponentResolver.addAllComponents(pkg, chatty); - mAppsFilter.addPackage(pkgSetting, mSettings.mPackages); + mAppsFilter.addPackage(pkgSetting); // Don't allow ephemeral applications to define new permissions groups. if ((scanFlags & SCAN_AS_INSTANT_APP) != 0) { @@ -12508,8 +12536,6 @@ public class PackageManagerService extends IPackageManager.Stub void cleanPackageDataStructuresLILPw(AndroidPackage pkg, boolean chatty) { mComponentResolver.removeAllComponents(pkg, chatty); - mAppsFilter.removePackage(getPackageSetting(pkg.getPackageName()), - mInjector.getUserManagerInternal().getUserIds(), mSettings.mPackages); mPermissionManager.removeAllPermissions(pkg, chatty); final int instrumentationSize = ArrayUtils.size(pkg.getInstrumentations()); @@ -14225,7 +14251,7 @@ public class PackageManagerService extends IPackageManager.Stub // Okay! targetPackageSetting.setInstallerPackageName(installerPackageName); mSettings.addInstallerPackageNames(targetPackageSetting.installSource); - mAppsFilter.addPackage(targetPackageSetting, mSettings.mPackages); + mAppsFilter.addPackage(targetPackageSetting); scheduleWriteSettingsLocked(); } } @@ -18678,6 +18704,7 @@ public class PackageManagerService extends IPackageManager.Stub clearIntentFilterVerificationsLPw(deletedPs.name, UserHandle.USER_ALL, true); clearDefaultBrowserIfNeeded(packageName); mSettings.mKeySetManagerService.removeAppKeySetDataLPw(packageName); + mAppsFilter.removePackage(getPackageSetting(packageName)); removedAppId = mSettings.removePackageLPw(packageName); if (outInfo != null) { outInfo.removedAppId = removedAppId; @@ -23435,6 +23462,7 @@ public class PackageManagerService extends IPackageManager.Stub scheduleWritePackageRestrictionsLocked(userId); scheduleWritePackageListLocked(userId); primeDomainVerificationsLPw(userId); + mAppsFilter.onUsersChanged(); } } diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 40fa798309c1..2a6997cba4bb 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -989,6 +989,15 @@ public class UserManagerService extends IUserManager.Stub { ensureCanModifyQuietMode( callingPackage, Binder.getCallingUid(), userId, target != null, dontAskCredential); + + if (onlyIfCredentialNotRequired && callingPackage.equals( + getPackageManagerInternal().getSystemUiServiceComponent().getPackageName())) { + // This is to prevent SysUI from accidentally allowing the profile to turned on + // without password when keyguard is still locked. + throw new SecurityException("SystemUI is not allowed to set " + + "QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED"); + } + final long identity = Binder.clearCallingIdentity(); try { if (enableQuietMode) { @@ -996,7 +1005,17 @@ public class UserManagerService extends IUserManager.Stub { userId, true /* enableQuietMode */, target, callingPackage); return true; } - mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId); + if (mLockPatternUtils.isManagedProfileWithUnifiedChallenge(userId)) { + KeyguardManager km = mContext.getSystemService(KeyguardManager.class); + // Normally only attempt to auto-unlock unified challenge if keyguard is not showing + // (to stop turning profile on automatically via the QS tile), except when we + // are called with QUIET_MODE_DISABLE_ONLY_IF_CREDENTIAL_NOT_REQUIRED, in which + // case always attempt to auto-unlock. + if (!km.isDeviceLocked(mLocalService.getProfileParentId(userId)) + || onlyIfCredentialNotRequired) { + mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId); + } + } final boolean needToShowConfirmCredential = !dontAskCredential && mLockPatternUtils.isSecure(userId) && !StorageManager.isUserKeyUnlocked(userId); @@ -1029,6 +1048,8 @@ public class UserManagerService extends IUserManager.Stub { */ private void ensureCanModifyQuietMode(String callingPackage, int callingUid, @UserIdInt int targetUserId, boolean startIntent, boolean dontAskCredential) { + verifyCallingPackage(callingPackage, callingUid); + if (hasManageUsersPermission()) { return; } @@ -1050,7 +1071,6 @@ public class UserManagerService extends IUserManager.Stub { return; } - verifyCallingPackage(callingPackage, callingUid); final ShortcutServiceInternal shortcutInternal = LocalServices.getService(ShortcutServiceInternal.class); if (shortcutInternal != null) { diff --git a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java index 58732b4c778f..7c89b9850c5d 100644 --- a/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java +++ b/services/core/java/com/android/server/pm/UserSystemPackageInstaller.java @@ -96,6 +96,8 @@ import java.util.Set; class UserSystemPackageInstaller { private static final String TAG = "UserManagerService"; + private static final boolean DEBUG = false; + /** * System Property whether to only install system packages on a user if they're whitelisted for * that user type. These are flags and can be freely combined. @@ -328,12 +330,15 @@ class UserSystemPackageInstaller { // Check whether all whitelisted packages are indeed on the system. final String notPresentFmt = "%s is whitelisted but not present."; final String notSystemFmt = "%s is whitelisted and present but not a system package."; + final String overlayPackageFmt = "%s is whitelisted but it's auto-generated RRO package."; for (String pkgName : allWhitelistedPackages) { final AndroidPackage pkg = pmInt.getPackage(pkgName); if (pkg == null) { warnings.add(String.format(notPresentFmt, pkgName)); } else if (!pkg.isSystem()) { warnings.add(String.format(notSystemFmt, pkgName)); + } else if (isAutoGeneratedRRO(pkg)) { + warnings.add(String.format(overlayPackageFmt, pkgName)); } } return warnings; @@ -407,6 +412,23 @@ class UserSystemPackageInstaller { return isImplicitWhitelistSystemMode(getWhitelistMode()); } + /** + * Whether package name has auto-generated RRO package name suffix. + */ + @VisibleForTesting + static boolean hasAutoGeneratedRROSuffix(String name) { + return name.endsWith(".auto_generated_rro_product__") + || name.endsWith(".auto_generated_rro_vendor__"); + } + + /** + * Whether the package is auto-generated RRO package. + */ + private static boolean isAutoGeneratedRRO(AndroidPackage pkg) { + return pkg.isOverlay() + && (hasAutoGeneratedRROSuffix(pkg.getManifestPackageName())); + } + /** See {@link #isEnforceMode()}. */ private static boolean isEnforceMode(int whitelistMode) { return (whitelistMode & USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE) != 0; @@ -518,7 +540,18 @@ class UserSystemPackageInstaller { static boolean shouldInstallPackage(AndroidPackage sysPkg, @NonNull ArrayMap<String, Long> userTypeWhitelist, @NonNull Set<String> userWhitelist, boolean implicitlyWhitelist) { - final String pkgName = sysPkg.getManifestPackageName(); + final String pkgName; + if (isAutoGeneratedRRO(sysPkg)) { + pkgName = sysPkg.getOverlayTarget(); + if (DEBUG) { + Slog.i(TAG, "shouldInstallPackage(): " + sysPkg.getManifestPackageName() + + " is auto-generated RRO package, will look for overlay system package: " + + pkgName); + } + } else { + pkgName = sysPkg.getManifestPackageName(); + } + return (implicitlyWhitelist && !userTypeWhitelist.containsKey(pkgName)) || userWhitelist.contains(pkgName); } diff --git a/services/core/java/com/android/server/power/PreRebootLogger.java b/services/core/java/com/android/server/power/PreRebootLogger.java index cda00b404c0b..c9e81ed7a796 100644 --- a/services/core/java/com/android/server/power/PreRebootLogger.java +++ b/services/core/java/com/android/server/power/PreRebootLogger.java @@ -16,6 +16,7 @@ package com.android.server.power; +import android.annotation.DurationMillisLong; import android.annotation.NonNull; import android.content.Context; import android.os.Environment; @@ -23,7 +24,7 @@ import android.os.IBinder; import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ServiceManager; -import android.provider.Settings; +import android.provider.Settings.Global; import android.util.Slog; import com.android.internal.annotations.GuardedBy; @@ -34,6 +35,8 @@ import java.io.File; import java.io.FileNotFoundException; import java.io.FileWriter; import java.io.IOException; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; /** * Provides utils to dump/wipe pre-reboot information. @@ -46,10 +49,12 @@ final class PreRebootLogger { private static final String[] SERVICES_TO_DUMP = {Context.ROLLBACK_SERVICE, "package"}; private static final Object sLock = new Object(); + private static final long MAX_DUMP_TIME = TimeUnit.SECONDS.toMillis(20); /** * Process pre-reboot information. Dump pre-reboot information to {@link #PREREBOOT_DIR} if - * enabled {@link Settings.Global#ADB_ENABLED}; wipe dumped information otherwise. + * enabled {@link Settings.Global#ADB_ENABLED} and having active staged session; wipe dumped + * information otherwise. */ static void log(Context context) { log(context, getDumpDir()); @@ -57,28 +62,49 @@ final class PreRebootLogger { @VisibleForTesting static void log(Context context, @NonNull File dumpDir) { - if (Settings.Global.getInt( - context.getContentResolver(), Settings.Global.ADB_ENABLED, 0) == 1) { - Slog.d(TAG, "Dumping pre-reboot information..."); - dump(dumpDir); + if (needDump(context)) { + dump(dumpDir, MAX_DUMP_TIME); } else { - Slog.d(TAG, "Wiping pre-reboot information..."); wipe(dumpDir); } } - private static void dump(@NonNull File dumpDir) { - synchronized (sLock) { - for (String buffer : BUFFERS_TO_DUMP) { - dumpLogsLocked(dumpDir, buffer); - } - for (String service : SERVICES_TO_DUMP) { - dumpServiceLocked(dumpDir, service); + private static boolean needDump(Context context) { + return Global.getInt(context.getContentResolver(), Global.ADB_ENABLED, 0) == 1 + && !context.getPackageManager().getPackageInstaller() + .getActiveStagedSessions().isEmpty(); + } + + @VisibleForTesting + static void dump(@NonNull File dumpDir, @DurationMillisLong long maxWaitTime) { + Slog.d(TAG, "Dumping pre-reboot information..."); + final AtomicBoolean done = new AtomicBoolean(false); + final Thread t = new Thread(() -> { + synchronized (sLock) { + for (String buffer : BUFFERS_TO_DUMP) { + dumpLogsLocked(dumpDir, buffer); + } + for (String service : SERVICES_TO_DUMP) { + dumpServiceLocked(dumpDir, service); + } } + done.set(true); + }); + t.start(); + + try { + t.join(maxWaitTime); + } catch (InterruptedException e) { + Slog.e(TAG, "Failed to dump pre-reboot information due to interrupted", e); + } + + if (!done.get()) { + Slog.w(TAG, "Failed to dump pre-reboot information due to timeout"); } } private static void wipe(@NonNull File dumpDir) { + Slog.d(TAG, "Wiping pre-reboot information..."); synchronized (sLock) { for (File file : dumpDir.listFiles()) { file.delete(); @@ -109,7 +135,7 @@ final class PreRebootLogger { {"logcat", "-d", "-b", buffer, "-f", dumpFile.getAbsolutePath()}; Runtime.getRuntime().exec(cmdline).waitFor(); } catch (IOException | InterruptedException e) { - Slog.d(TAG, "Dump system log buffer before reboot fail", e); + Slog.e(TAG, "Failed to dump system log buffer before reboot", e); } } @@ -127,7 +153,7 @@ final class PreRebootLogger { | ParcelFileDescriptor.MODE_WRITE_ONLY); binder.dump(fd.getFileDescriptor(), ArrayUtils.emptyArray(String.class)); } catch (FileNotFoundException | RemoteException e) { - Slog.d(TAG, String.format("Dump %s service before reboot fail", serviceName), e); + Slog.e(TAG, String.format("Failed to dump %s service before reboot", serviceName), e); } } } diff --git a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java index c0c9b3220ae0..c2bae1a8962b 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -191,7 +191,6 @@ import java.util.Random; import java.util.Set; import java.util.UUID; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.Executor; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; @@ -257,21 +256,17 @@ public class StatsPullAtomService extends SystemService { @GuardedBy("mNotificationStatsLock") private INotificationManager mNotificationManagerService; - private final Object mProcessStatsLock = new Object(); - @GuardedBy("mProcessStatsLock") + @GuardedBy("mProcStatsLock") private IProcessStats mProcessStatsService; - private final Object mCpuTrackerLock = new Object(); - @GuardedBy("mCpuTrackerLock") + @GuardedBy("mProcessCpuTimeLock") private ProcessCpuTracker mProcessCpuTracker; - private final Object mDebugElapsedClockLock = new Object(); @GuardedBy("mDebugElapsedClockLock") private long mDebugElapsedClockPreviousValue = 0; @GuardedBy("mDebugElapsedClockLock") private long mDebugElapsedClockPullCount = 0; - private final Object mDebugFailingElapsedClockLock = new Object(); @GuardedBy("mDebugFailingElapsedClockLock") private long mDebugFailingElapsedClockPreviousValue = 0; @GuardedBy("mDebugFailingElapsedClockLock") @@ -284,26 +279,40 @@ public class StatsPullAtomService extends SystemService { private TelephonyManager mTelephony; private SubscriptionManager mSubscriptionManager; + @GuardedBy("mKernelWakelockLock") private KernelWakelockReader mKernelWakelockReader; + @GuardedBy("mKernelWakelockLock") private KernelWakelockStats mTmpWakelockStats; + @GuardedBy("mDiskIoLock") private StoragedUidIoStatsReader mStoragedUidIoStatsReader; + @GuardedBy("mCpuTimePerFreqLock") private KernelCpuSpeedReader[] mKernelCpuSpeedReaders; // Disables throttler on CPU time readers. + @GuardedBy("mCpuTimePerUidLock") private KernelCpuUidUserSysTimeReader mCpuUidUserSysTimeReader; + @GuardedBy("mCpuTimePerUidFreqLock") private KernelCpuUidFreqTimeReader mCpuUidFreqTimeReader; + @GuardedBy("mCpuActiveTimeLock") private KernelCpuUidActiveTimeReader mCpuUidActiveTimeReader; + @GuardedBy("mClusterTimeLock") private KernelCpuUidClusterTimeReader mCpuUidClusterTimeReader; + @GuardedBy("mProcStatsLock") private File mBaseDir; + @GuardedBy("mHealthHalLock") private BatteryService.HealthServiceWrapper mHealthService; @Nullable + @GuardedBy("mCpuTimePerThreadFreqLock") private KernelCpuThreadReaderDiff mKernelCpuThreadReader; + private final Object mBatteryStatsHelperLock = new Object(); + @GuardedBy("mBatteryStatsHelperLock") private BatteryStatsHelper mBatteryStatsHelper = null; + @GuardedBy("mBatteryStatsHelperLock") private long mBatteryStatsHelperTimestampMs = -MAX_BATTERY_STATS_HELPER_FREQUENCY_MS; private StatsPullAtomCallbackImpl mStatsCallbackImpl; @@ -311,19 +320,75 @@ public class StatsPullAtomService extends SystemService { private final Object mAppOpsSamplingRateLock = new Object(); @GuardedBy("mAppOpsSamplingRateLock") private int mAppOpsSamplingRate = 0; + private final Object mDangerousAppOpsListLock = new Object(); + @GuardedBy("mDangerousAppOpsListLock") private final ArraySet<Integer> mDangerousAppOpsList = new ArraySet<>(); // Baselines that stores list of NetworkStats right after initializing, with associated - // information. This is used to calculate difference when pulling - // {Mobile|Wifi}BytesTransfer* atoms. Note that this is not thread-safe, and must - // only be accessed on the background thread. + // information. This is used to calculate difference when pulling BytesTransfer atoms. @NonNull - private final List<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>(); + @GuardedBy("mDataBytesTransferLock") + private final ArrayList<NetworkStatsExt> mNetworkStatsBaselines = new ArrayList<>(); // Listener for monitoring subscriptions changed event. private StatsSubscriptionsListener mStatsSubscriptionsListener; // List that stores SubInfo of subscriptions that ever appeared since boot. - private final CopyOnWriteArrayList<SubInfo> mHistoricalSubs = new CopyOnWriteArrayList<>(); + @GuardedBy("mDataBytesTransferLock") + private final ArrayList<SubInfo> mHistoricalSubs = new ArrayList<>(); + + // Puller locks + private final Object mDataBytesTransferLock = new Object(); + private final Object mBluetoothBytesTransferLock = new Object(); + private final Object mKernelWakelockLock = new Object(); + private final Object mCpuTimePerFreqLock = new Object(); + private final Object mCpuTimePerUidLock = new Object(); + private final Object mCpuTimePerUidFreqLock = new Object(); + private final Object mCpuActiveTimeLock = new Object(); + private final Object mCpuClusterTimeLock = new Object(); + private final Object mWifiActivityInfoLock = new Object(); + private final Object mModemActivityInfoLock = new Object(); + private final Object mBluetoothActivityInfoLock = new Object(); + private final Object mSystemElapsedRealtimeLock = new Object(); + private final Object mSystemUptimeLock = new Object(); + private final Object mProcessMemoryStateLock = new Object(); + private final Object mProcessMemoryHighWaterMarkLock = new Object(); + private final Object mProcessMemorySnapshotLock = new Object(); + private final Object mSystemIonHeapSizeLock = new Object(); + private final Object mIonHeapSizeLock = new Object(); + private final Object mProcessSystemIonHeapSizeLock = new Object(); + private final Object mTemperatureLock = new Object(); + private final Object mCooldownDeviceLock = new Object(); + private final Object mBinderCallsStatsLock = new Object(); + private final Object mBinderCallsStatsExceptionsLock = new Object(); + private final Object mLooperStatsLock = new Object(); + private final Object mDiskStatsLock = new Object(); + private final Object mDirectoryUsageLock = new Object(); + private final Object mAppSizeLock = new Object(); + private final Object mCategorySizeLock = new Object(); + private final Object mNumBiometricsEnrolledLock = new Object(); + private final Object mProcStatsLock = new Object(); + private final Object mDiskIoLock = new Object(); + private final Object mPowerProfileLock = new Object(); + private final Object mProcessCpuTimeLock = new Object(); + private final Object mCpuTimePerThreadFreqLock = new Object(); + private final Object mDeviceCalculatedPowerUseLock = new Object(); + private final Object mDeviceCalculatedPowerBlameUidLock = new Object(); + private final Object mDeviceCalculatedPowerBlameOtherLock = new Object(); + private final Object mDebugElapsedClockLock = new Object(); + private final Object mDebugFailingElapsedClockLock = new Object(); + private final Object mBuildInformationLock = new Object(); + private final Object mRoleHolderLock = new Object(); + private final Object mTimeZoneDataInfoLock = new Object(); + private final Object mExternalStorageInfoLock = new Object(); + private final Object mAppsOnExternalStorageInfoLock = new Object(); + private final Object mFaceSettingsLock = new Object(); + private final Object mAppOpsLock = new Object(); + private final Object mRuntimeAppOpAccessMessageLock = new Object(); + private final Object mNotificationRemoteViewsLock = new Object(); + private final Object mDangerousPermissionStateLock = new Object(); + private final Object mHealthHalLock = new Object(); + private final Object mAttributedAppOpsLock = new Object(); + private final Object mSettingsStatsLock = new Object(); public StatsPullAtomService(Context context) { super(context); @@ -353,123 +418,229 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: case FrameworkStatsLog.DATA_USAGE_BYTES_TRANSFER: - return pullDataBytesTransfer(atomTag, data); + synchronized (mDataBytesTransferLock) { + return pullDataBytesTransferLocked(atomTag, data); + } case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER: - return pullBluetoothBytesTransfer(atomTag, data); + synchronized (mBluetoothBytesTransferLock) { + return pullBluetoothBytesTransferLocked(atomTag, data); + } case FrameworkStatsLog.KERNEL_WAKELOCK: - return pullKernelWakelock(atomTag, data); + synchronized (mKernelWakelockLock) { + return pullKernelWakelockLocked(atomTag, data); + } case FrameworkStatsLog.CPU_TIME_PER_FREQ: - return pullCpuTimePerFreq(atomTag, data); + synchronized (mCpuTimePerFreqLock) { + return pullCpuTimePerFreqLocked(atomTag, data); + } case FrameworkStatsLog.CPU_TIME_PER_UID: - return pullCpuTimePerUid(atomTag, data); + synchronized (mCpuTimePerUidLock) { + return pullCpuTimePerUidLocked(atomTag, data); + } case FrameworkStatsLog.CPU_TIME_PER_UID_FREQ: - return pullCpuTimeperUidFreq(atomTag, data); + synchronized (mCpuTimePerUidFreqLock) { + return pullCpuTimePerUidFreqLocked(atomTag, data); + } case FrameworkStatsLog.CPU_ACTIVE_TIME: - return pullCpuActiveTime(atomTag, data); + synchronized (mCpuActiveTimeLock) { + return pullCpuActiveTimeLocked(atomTag, data); + } case FrameworkStatsLog.CPU_CLUSTER_TIME: - return pullCpuClusterTime(atomTag, data); + synchronized (mCpuClusterTimeLock) { + return pullCpuClusterTimeLocked(atomTag, data); + } case FrameworkStatsLog.WIFI_ACTIVITY_INFO: - return pullWifiActivityInfo(atomTag, data); + synchronized (mWifiActivityInfoLock) { + return pullWifiActivityInfoLocked(atomTag, data); + } case FrameworkStatsLog.MODEM_ACTIVITY_INFO: - return pullModemActivityInfo(atomTag, data); + synchronized (mModemActivityInfoLock) { + return pullModemActivityInfoLocked(atomTag, data); + } case FrameworkStatsLog.BLUETOOTH_ACTIVITY_INFO: - return pullBluetoothActivityInfo(atomTag, data); + synchronized (mBluetoothActivityInfoLock) { + return pullBluetoothActivityInfoLocked(atomTag, data); + } case FrameworkStatsLog.SYSTEM_ELAPSED_REALTIME: - return pullSystemElapsedRealtime(atomTag, data); + synchronized (mSystemElapsedRealtimeLock) { + return pullSystemElapsedRealtimeLocked(atomTag, data); + } case FrameworkStatsLog.SYSTEM_UPTIME: - return pullSystemUptime(atomTag, data); + synchronized (mSystemUptimeLock) { + return pullSystemUptimeLocked(atomTag, data); + } case FrameworkStatsLog.PROCESS_MEMORY_STATE: - return pullProcessMemoryState(atomTag, data); + synchronized (mProcessMemoryStateLock) { + return pullProcessMemoryStateLocked(atomTag, data); + } case FrameworkStatsLog.PROCESS_MEMORY_HIGH_WATER_MARK: - return pullProcessMemoryHighWaterMark(atomTag, data); + synchronized (mProcessMemoryHighWaterMarkLock) { + return pullProcessMemoryHighWaterMarkLocked(atomTag, data); + } case FrameworkStatsLog.PROCESS_MEMORY_SNAPSHOT: - return pullProcessMemorySnapshot(atomTag, data); + synchronized (mProcessMemorySnapshotLock) { + return pullProcessMemorySnapshotLocked(atomTag, data); + } case FrameworkStatsLog.SYSTEM_ION_HEAP_SIZE: - return pullSystemIonHeapSize(atomTag, data); + synchronized (mSystemIonHeapSizeLock) { + return pullSystemIonHeapSizeLocked(atomTag, data); + } case FrameworkStatsLog.ION_HEAP_SIZE: - return pullIonHeapSize(atomTag, data); + synchronized (mIonHeapSizeLock) { + return pullIonHeapSizeLocked(atomTag, data); + } case FrameworkStatsLog.PROCESS_SYSTEM_ION_HEAP_SIZE: - return pullProcessSystemIonHeapSize(atomTag, data); + synchronized (mProcessSystemIonHeapSizeLock) { + return pullProcessSystemIonHeapSizeLocked(atomTag, data); + } case FrameworkStatsLog.TEMPERATURE: - return pullTemperature(atomTag, data); + synchronized (mTemperatureLock) { + return pullTemperatureLocked(atomTag, data); + } case FrameworkStatsLog.COOLING_DEVICE: - return pullCooldownDevice(atomTag, data); + synchronized (mCooldownDeviceLock) { + return pullCooldownDeviceLocked(atomTag, data); + } case FrameworkStatsLog.BINDER_CALLS: - return pullBinderCallsStats(atomTag, data); + synchronized (mBinderCallsStatsLock) { + return pullBinderCallsStatsLocked(atomTag, data); + } case FrameworkStatsLog.BINDER_CALLS_EXCEPTIONS: - return pullBinderCallsStatsExceptions(atomTag, data); + synchronized (mBinderCallsStatsExceptionsLock) { + return pullBinderCallsStatsExceptionsLocked(atomTag, data); + } case FrameworkStatsLog.LOOPER_STATS: - return pullLooperStats(atomTag, data); + synchronized (mLooperStatsLock) { + return pullLooperStatsLocked(atomTag, data); + } case FrameworkStatsLog.DISK_STATS: - return pullDiskStats(atomTag, data); + synchronized (mDiskStatsLock) { + return pullDiskStatsLocked(atomTag, data); + } case FrameworkStatsLog.DIRECTORY_USAGE: - return pullDirectoryUsage(atomTag, data); + synchronized (mDirectoryUsageLock) { + return pullDirectoryUsageLocked(atomTag, data); + } case FrameworkStatsLog.APP_SIZE: - return pullAppSize(atomTag, data); + synchronized (mAppSizeLock) { + return pullAppSizeLocked(atomTag, data); + } case FrameworkStatsLog.CATEGORY_SIZE: - return pullCategorySize(atomTag, data); + synchronized (mCategorySizeLock) { + return pullCategorySizeLocked(atomTag, data); + } case FrameworkStatsLog.NUM_FINGERPRINTS_ENROLLED: - return pullNumBiometricsEnrolled( - BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data); + synchronized (mNumBiometricsEnrolledLock) { + return pullNumBiometricsEnrolledLocked( + BiometricsProtoEnums.MODALITY_FINGERPRINT, atomTag, data); + } case FrameworkStatsLog.NUM_FACES_ENROLLED: - return pullNumBiometricsEnrolled( - BiometricsProtoEnums.MODALITY_FACE, atomTag, data); + synchronized (mNumBiometricsEnrolledLock) { + return pullNumBiometricsEnrolledLocked( + BiometricsProtoEnums.MODALITY_FACE, atomTag, data); + } case FrameworkStatsLog.PROC_STATS: - return pullProcStats(ProcessStats.REPORT_ALL, atomTag, data); + synchronized (mProcStatsLock) { + return pullProcStatsLocked(ProcessStats.REPORT_ALL, atomTag, data); + } case FrameworkStatsLog.PROC_STATS_PKG_PROC: - return pullProcStats(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, data); + synchronized (mProcStatsLock) { + return pullProcStatsLocked(ProcessStats.REPORT_PKG_PROC_STATS, atomTag, + data); + } case FrameworkStatsLog.DISK_IO: - return pullDiskIO(atomTag, data); + synchronized (mDiskIoLock) { + return pullDiskIOLocked(atomTag, data); + } case FrameworkStatsLog.POWER_PROFILE: - return pullPowerProfile(atomTag, data); + synchronized (mPowerProfileLock) { + return pullPowerProfileLocked(atomTag, data); + } case FrameworkStatsLog.PROCESS_CPU_TIME: - return pullProcessCpuTime(atomTag, data); + synchronized (mProcessCpuTimeLock) { + return pullProcessCpuTimeLocked(atomTag, data); + } case FrameworkStatsLog.CPU_TIME_PER_THREAD_FREQ: - return pullCpuTimePerThreadFreq(atomTag, data); + synchronized (mCpuTimePerThreadFreqLock) { + return pullCpuTimePerThreadFreqLocked(atomTag, data); + } case FrameworkStatsLog.DEVICE_CALCULATED_POWER_USE: - return pullDeviceCalculatedPowerUse(atomTag, data); + synchronized (mDeviceCalculatedPowerUseLock) { + return pullDeviceCalculatedPowerUseLocked(atomTag, data); + } case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_UID: - return pullDeviceCalculatedPowerBlameUid(atomTag, data); + synchronized (mDeviceCalculatedPowerBlameUidLock) { + return pullDeviceCalculatedPowerBlameUidLocked(atomTag, data); + } case FrameworkStatsLog.DEVICE_CALCULATED_POWER_BLAME_OTHER: - return pullDeviceCalculatedPowerBlameOther(atomTag, data); + synchronized (mDeviceCalculatedPowerBlameOtherLock) { + return pullDeviceCalculatedPowerBlameOtherLocked(atomTag, data); + } case FrameworkStatsLog.DEBUG_ELAPSED_CLOCK: - return pullDebugElapsedClock(atomTag, data); + synchronized (mDebugElapsedClockLock) { + return pullDebugElapsedClockLocked(atomTag, data); + } case FrameworkStatsLog.DEBUG_FAILING_ELAPSED_CLOCK: - return pullDebugFailingElapsedClock(atomTag, data); + synchronized (mDebugFailingElapsedClockLock) { + return pullDebugFailingElapsedClockLocked(atomTag, data); + } case FrameworkStatsLog.BUILD_INFORMATION: - return pullBuildInformation(atomTag, data); + synchronized (mBuildInformationLock) { + return pullBuildInformationLocked(atomTag, data); + } case FrameworkStatsLog.ROLE_HOLDER: - return pullRoleHolder(atomTag, data); + synchronized (mRoleHolderLock) { + return pullRoleHolderLocked(atomTag, data); + } case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE: - return pullDangerousPermissionState(atomTag, data); + case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED: + synchronized (mDangerousPermissionStateLock) { + return pullDangerousPermissionStateLocked(atomTag, data); + } case FrameworkStatsLog.TIME_ZONE_DATA_INFO: - return pullTimeZoneDataInfo(atomTag, data); + synchronized (mTimeZoneDataInfoLock) { + return pullTimeZoneDataInfoLocked(atomTag, data); + } case FrameworkStatsLog.EXTERNAL_STORAGE_INFO: - return pullExternalStorageInfo(atomTag, data); + synchronized (mExternalStorageInfoLock) { + return pullExternalStorageInfoLocked(atomTag, data); + } case FrameworkStatsLog.APPS_ON_EXTERNAL_STORAGE_INFO: - return pullAppsOnExternalStorageInfo(atomTag, data); + synchronized (mAppsOnExternalStorageInfoLock) { + return pullAppsOnExternalStorageInfoLocked(atomTag, data); + } case FrameworkStatsLog.FACE_SETTINGS: - return pullFaceSettings(atomTag, data); + synchronized (mFaceSettingsLock) { + return pullFaceSettingsLocked(atomTag, data); + } case FrameworkStatsLog.APP_OPS: - return pullAppOps(atomTag, data); + synchronized (mAppOpsLock) { + return pullAppOpsLocked(atomTag, data); + } case FrameworkStatsLog.RUNTIME_APP_OP_ACCESS: - return pullRuntimeAppOpAccessMessage(atomTag, data); + synchronized (mRuntimeAppOpAccessMessageLock) { + return pullRuntimeAppOpAccessMessageLocked(atomTag, data); + } case FrameworkStatsLog.NOTIFICATION_REMOTE_VIEWS: - return pullNotificationRemoteViews(atomTag, data); - case FrameworkStatsLog.DANGEROUS_PERMISSION_STATE_SAMPLED: - return pullDangerousPermissionState(atomTag, data); + synchronized (mNotificationRemoteViewsLock) { + return pullNotificationRemoteViewsLocked(atomTag, data); + } case FrameworkStatsLog.BATTERY_LEVEL: case FrameworkStatsLog.REMAINING_BATTERY_CAPACITY: case FrameworkStatsLog.FULL_BATTERY_CAPACITY: case FrameworkStatsLog.BATTERY_VOLTAGE: case FrameworkStatsLog.BATTERY_CYCLE_COUNT: - return pullHealthHal(atomTag, data); + synchronized (mHealthHalLock) { + return pullHealthHalLocked(atomTag, data); + } case FrameworkStatsLog.ATTRIBUTED_APP_OPS: - return pullAttributedAppOps(atomTag, data); + synchronized (mAttributedAppOpsLock) { + return pullAttributedAppOpsLocked(atomTag, data); + } case FrameworkStatsLog.SETTING_SNAPSHOT: - return pullSettingsStats(atomTag, data); - case FrameworkStatsLog.DISPLAY_WAKE_REASON: - return pullDisplayWakeStats(atomTag, data); + synchronized (mSettingsStatsLock) { + return pullSettingsStatsLocked(atomTag, data); + } default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } @@ -500,6 +671,8 @@ public class StatsPullAtomService extends SystemService { } } + // We do not hold locks within this function because it is guaranteed to be called before the + // pullers are ever run, as the pullers are not yet registered with statsd. void initializePullersState() { // Get Context Managers mStatsManager = (StatsManager) mContext.getSystemService(Context.STATS_MANAGER); @@ -515,6 +688,7 @@ public class StatsPullAtomService extends SystemService { // Initialize PROC_STATS mBaseDir = new File(SystemServiceManager.ensureSystemDir(), "stats_pull"); + mBaseDir.mkdirs(); // Disables throttler on CPU time readers. mCpuUidUserSysTimeReader = new KernelCpuUidUserSysTimeReader(false); @@ -542,9 +716,6 @@ public class StatsPullAtomService extends SystemService { mKernelCpuThreadReader = KernelCpuThreadReaderSettingsObserver.getSettingsModifiedReader(mContext); - // Used by PROC_STATS and PROC_STATS_PKG_PROC atoms - mBaseDir.mkdirs(); - // Initialize HealthService mHealthService = new BatteryService.HealthServiceWrapper(); try { @@ -656,7 +827,6 @@ public class StatsPullAtomService extends SystemService { registerBatteryVoltage(); registerBatteryCycleCount(); registerSettingsStats(); - registerDisplayWakeStats(); } private void initAndRegisterNetworkStatsPullers() { @@ -783,7 +953,7 @@ public class StatsPullAtomService extends SystemService { } private IProcessStats getIProcessStatsService() { - synchronized (mProcessStatsLock) { + synchronized (mProcStatsLock) { if (mProcessStatsService == null) { mProcessStatsService = IProcessStats.Stub.asInterface( ServiceManager.getService(ProcessStats.SERVICE_NAME)); @@ -791,7 +961,7 @@ public class StatsPullAtomService extends SystemService { if (mProcessStatsService != null) { try { mProcessStatsService.asBinder().linkToDeath(() -> { - synchronized (mProcessStatsLock) { + synchronized (mProcStatsLock) { mProcessStatsService = null; } }, /* flags */ 0); @@ -882,8 +1052,7 @@ public class StatsPullAtomService extends SystemService { return ret; } - private int pullDataBytesTransfer( - int atomTag, @NonNull List<StatsEvent> pulledData) { + private int pullDataBytesTransferLocked(int atomTag, @NonNull List<StatsEvent> pulledData) { final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag); if (current == null) { @@ -1237,12 +1406,11 @@ public class StatsPullAtomService extends SystemService { return null; } - private synchronized BluetoothActivityEnergyInfo fetchBluetoothData() { - // TODO: Investigate whether the synchronized keyword is needed. + private BluetoothActivityEnergyInfo fetchBluetoothData() { final BluetoothAdapter adapter = BluetoothAdapter.getDefaultAdapter(); if (adapter != null) { - SynchronousResultReceiver bluetoothReceiver = new SynchronousResultReceiver( - "bluetooth"); + SynchronousResultReceiver bluetoothReceiver = + new SynchronousResultReceiver("bluetooth"); adapter.requestControllerActivityEnergyInfo(bluetoothReceiver); return awaitControllerInfo(bluetoothReceiver); } else { @@ -1251,7 +1419,7 @@ public class StatsPullAtomService extends SystemService { } } - int pullBluetoothBytesTransfer(int atomTag, List<StatsEvent> pulledData) { + int pullBluetoothBytesTransferLocked(int atomTag, List<StatsEvent> pulledData) { BluetoothActivityEnergyInfo info = fetchBluetoothData(); if (info == null || info.getUidTraffic() == null) { return StatsManager.PULL_SKIP; @@ -1279,7 +1447,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullKernelWakelock(int atomTag, List<StatsEvent> pulledData) { + int pullKernelWakelockLocked(int atomTag, List<StatsEvent> pulledData) { final KernelWakelockStats wakelockStats = mKernelWakelockReader.readKernelWakelockStats(mTmpWakelockStats); for (Map.Entry<String, KernelWakelockStats.Entry> ent : wakelockStats.entrySet()) { @@ -1310,7 +1478,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuTimePerFreq(int atomTag, List<StatsEvent> pulledData) { + int pullCpuTimePerFreqLocked(int atomTag, List<StatsEvent> pulledData) { for (int cluster = 0; cluster < mKernelCpuSpeedReaders.length; cluster++) { long[] clusterTimeMs = mKernelCpuSpeedReaders[cluster].readAbsolute(); if (clusterTimeMs != null) { @@ -1341,7 +1509,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuTimePerUid(int atomTag, List<StatsEvent> pulledData) { + int pullCpuTimePerUidLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidUserSysTimeReader.readAbsolute((uid, timesUs) -> { long userTimeUs = timesUs[0], systemTimeUs = timesUs[1]; StatsEvent e = StatsEvent.newBuilder() @@ -1371,7 +1539,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuTimeperUidFreq(int atomTag, List<StatsEvent> pulledData) { + int pullCpuTimePerUidFreqLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidFreqTimeReader.readAbsolute((uid, cpuFreqTimeMs) -> { for (int freqIndex = 0; freqIndex < cpuFreqTimeMs.length; ++freqIndex) { if (cpuFreqTimeMs[freqIndex] != 0) { @@ -1404,7 +1572,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuActiveTime(int atomTag, List<StatsEvent> pulledData) { + int pullCpuActiveTimeLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidActiveTimeReader.readAbsolute((uid, cpuActiveTimesMs) -> { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -1432,7 +1600,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuClusterTime(int atomTag, List<StatsEvent> pulledData) { + int pullCpuClusterTimeLocked(int atomTag, List<StatsEvent> pulledData) { mCpuUidClusterTimeReader.readAbsolute((uid, cpuClusterTimesMs) -> { for (int i = 0; i < cpuClusterTimesMs.length; i++) { StatsEvent e = StatsEvent.newBuilder() @@ -1458,7 +1626,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullWifiActivityInfo(int atomTag, List<StatsEvent> pulledData) { + int pullWifiActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) { long token = Binder.clearCallingIdentity(); try { SynchronousResultReceiver wifiReceiver = new SynchronousResultReceiver("wifi"); @@ -1510,7 +1678,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullModemActivityInfo(int atomTag, List<StatsEvent> pulledData) { + int pullModemActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) { long token = Binder.clearCallingIdentity(); try { SynchronousResultReceiver modemReceiver = new SynchronousResultReceiver("telephony"); @@ -1548,7 +1716,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullBluetoothActivityInfo(int atomTag, List<StatsEvent> pulledData) { + int pullBluetoothActivityInfoLocked(int atomTag, List<StatsEvent> pulledData) { BluetoothActivityEnergyInfo info = fetchBluetoothData(); if (info == null) { return StatsManager.PULL_SKIP; @@ -1580,7 +1748,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullSystemElapsedRealtime(int atomTag, List<StatsEvent> pulledData) { + int pullSystemElapsedRealtimeLocked(int atomTag, List<StatsEvent> pulledData) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) .writeLong(SystemClock.elapsedRealtime()) @@ -1599,7 +1767,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullSystemUptime(int atomTag, List<StatsEvent> pulledData) { + int pullSystemUptimeLocked(int atomTag, List<StatsEvent> pulledData) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) .writeLong(SystemClock.uptimeMillis()) @@ -1621,7 +1789,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullProcessMemoryState(int atomTag, List<StatsEvent> pulledData) { + int pullProcessMemoryStateLocked(int atomTag, List<StatsEvent> pulledData) { List<ProcessMemoryState> processMemoryStates = LocalServices.getService(ActivityManagerInternal.class) .getMemoryStateForProcesses(); @@ -1665,7 +1833,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullProcessMemoryHighWaterMark(int atomTag, List<StatsEvent> pulledData) { + int pullProcessMemoryHighWaterMarkLocked(int atomTag, List<StatsEvent> pulledData) { List<ProcessMemoryState> managedProcessList = LocalServices.getService(ActivityManagerInternal.class) .getMemoryStateForProcesses(); @@ -1720,7 +1888,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullProcessMemorySnapshot(int atomTag, List<StatsEvent> pulledData) { + int pullProcessMemorySnapshotLocked(int atomTag, List<StatsEvent> pulledData) { List<ProcessMemoryState> managedProcessList = LocalServices.getService(ActivityManagerInternal.class) .getMemoryStateForProcesses(); @@ -1782,7 +1950,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) { + int pullSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) { final long systemIonHeapSizeInBytes = readSystemIonHeapSizeFromDebugfs(); StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -1805,7 +1973,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullIonHeapSize(int atomTag, List<StatsEvent> pulledData) { + int pullIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) { int ionHeapSizeInKilobytes = (int) getIonHeapsSizeKb(); StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -1825,7 +1993,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullProcessSystemIonHeapSize(int atomTag, List<StatsEvent> pulledData) { + int pullProcessSystemIonHeapSizeLocked(int atomTag, List<StatsEvent> pulledData) { List<IonAllocations> result = readProcessSystemIonHeapSizesFromDebugfs(); for (IonAllocations allocations : result) { StatsEvent e = StatsEvent.newBuilder() @@ -1852,7 +2020,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullTemperature(int atomTag, List<StatsEvent> pulledData) { + int pullTemperatureLocked(int atomTag, List<StatsEvent> pulledData) { IThermalService thermalService = getIThermalService(); if (thermalService == null) { return StatsManager.PULL_SKIP; @@ -1890,7 +2058,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCooldownDevice(int atomTag, List<StatsEvent> pulledData) { + int pullCooldownDeviceLocked(int atomTag, List<StatsEvent> pulledData) { IThermalService thermalService = getIThermalService(); if (thermalService == null) { return StatsManager.PULL_SKIP; @@ -1930,7 +2098,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullBinderCallsStats(int atomTag, List<StatsEvent> pulledData) { + int pullBinderCallsStatsLocked(int atomTag, List<StatsEvent> pulledData) { BinderCallsStatsService.Internal binderStats = LocalServices.getService(BinderCallsStatsService.Internal.class); if (binderStats == null) { @@ -1974,7 +2142,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullBinderCallsStatsExceptions(int atomTag, List<StatsEvent> pulledData) { + int pullBinderCallsStatsExceptionsLocked(int atomTag, List<StatsEvent> pulledData) { BinderCallsStatsService.Internal binderStats = LocalServices.getService(BinderCallsStatsService.Internal.class); if (binderStats == null) { @@ -2009,7 +2177,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullLooperStats(int atomTag, List<StatsEvent> pulledData) { + int pullLooperStatsLocked(int atomTag, List<StatsEvent> pulledData) { LooperStats looperStats = LocalServices.getService(LooperStats.class); if (looperStats == null) { return StatsManager.PULL_SKIP; @@ -2052,7 +2220,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDiskStats(int atomTag, List<StatsEvent> pulledData) { + int pullDiskStatsLocked(int atomTag, List<StatsEvent> pulledData) { // Run a quick-and-dirty performance test: write 512 bytes byte[] junk = new byte[512]; for (int i = 0; i < junk.length; i++) junk[i] = (byte) i; // Write nonzero bytes @@ -2118,7 +2286,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDirectoryUsage(int atomTag, List<StatsEvent> pulledData) { + int pullDirectoryUsageLocked(int atomTag, List<StatsEvent> pulledData) { StatFs statFsData = new StatFs(Environment.getDataDirectory().getAbsolutePath()); StatFs statFsSystem = new StatFs(Environment.getRootDirectory().getAbsolutePath()); StatFs statFsCache = new StatFs(Environment.getDownloadCacheDirectory().getAbsolutePath()); @@ -2159,7 +2327,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullAppSize(int atomTag, List<StatsEvent> pulledData) { + int pullAppSizeLocked(int atomTag, List<StatsEvent> pulledData) { try { String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH); JSONObject json = new JSONObject(jsonStr); @@ -2203,7 +2371,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCategorySize(int atomTag, List<StatsEvent> pulledData) { + int pullCategorySizeLocked(int atomTag, List<StatsEvent> pulledData) { try { String jsonStr = IoUtils.readFileAsString(DiskStatsLoggingService.DUMPSYS_CACHE_PATH); JSONObject json = new JSONObject(jsonStr); @@ -2317,7 +2485,8 @@ public class StatsPullAtomService extends SystemService { ); } - private int pullNumBiometricsEnrolled(int modality, int atomTag, List<StatsEvent> pulledData) { + private int pullNumBiometricsEnrolledLocked(int modality, int atomTag, + List<StatsEvent> pulledData) { final PackageManager pm = mContext.getPackageManager(); FingerprintManager fingerprintManager = null; FaceManager faceManager = null; @@ -2385,43 +2554,41 @@ public class StatsPullAtomService extends SystemService { ); } - private int pullProcStats(int section, int atomTag, List<StatsEvent> pulledData) { + private int pullProcStatsLocked(int section, int atomTag, List<StatsEvent> pulledData) { IProcessStats processStatsService = getIProcessStatsService(); if (processStatsService == null) { return StatsManager.PULL_SKIP; } - synchronized (mProcessStatsLock) { - final long token = Binder.clearCallingIdentity(); - try { - // force procstats to flush & combine old files into one store - long lastHighWaterMark = readProcStatsHighWaterMark(section); - List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); + final long token = Binder.clearCallingIdentity(); + try { + // force procstats to flush & combine old files into one store + long lastHighWaterMark = readProcStatsHighWaterMark(section); + List<ParcelFileDescriptor> statsFiles = new ArrayList<>(); - ProcessStats procStats = new ProcessStats(false); - long highWaterMark = processStatsService.getCommittedStatsMerged( - lastHighWaterMark, section, true, statsFiles, procStats); + ProcessStats procStats = new ProcessStats(false); + long highWaterMark = processStatsService.getCommittedStatsMerged( + lastHighWaterMark, section, true, statsFiles, procStats); - // aggregate the data together for westworld consumption - ProtoOutputStream proto = new ProtoOutputStream(); - procStats.dumpAggregatedProtoForStatsd(proto); + // aggregate the data together for westworld consumption + ProtoOutputStream proto = new ProtoOutputStream(); + procStats.dumpAggregatedProtoForStatsd(proto); - StatsEvent e = StatsEvent.newBuilder() - .setAtomId(atomTag) - .writeByteArray(proto.getBytes()) - .build(); - pulledData.add(e); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeByteArray(proto.getBytes()) + .build(); + pulledData.add(e); - new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark) - .delete(); - new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark) - .createNewFile(); - } catch (RemoteException | IOException e) { - Slog.e(TAG, "Getting procstats failed: ", e); - return StatsManager.PULL_SKIP; - } finally { - Binder.restoreCallingIdentity(token); - } + new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + lastHighWaterMark) + .delete(); + new File(mBaseDir.getAbsolutePath() + "/" + section + "_" + highWaterMark) + .createNewFile(); + } catch (RemoteException | IOException e) { + Slog.e(TAG, "Getting procstats failed: ", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); } return StatsManager.PULL_SUCCESS; } @@ -2461,7 +2628,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDiskIO(int atomTag, List<StatsEvent> pulledData) { + int pullDiskIOLocked(int atomTag, List<StatsEvent> pulledData) { mStoragedUidIoStatsReader.readAbsolute((uid, fgCharsRead, fgCharsWrite, fgBytesRead, fgBytesWrite, bgCharsRead, bgCharsWrite, bgBytesRead, bgBytesWrite, fgFsync, bgFsync) -> { @@ -2495,7 +2662,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullPowerProfile(int atomTag, List<StatsEvent> pulledData) { + int pullPowerProfileLocked(int atomTag, List<StatsEvent> pulledData) { PowerProfile powerProfile = new PowerProfile(mContext); ProtoOutputStream proto = new ProtoOutputStream(); powerProfile.dumpDebug(proto); @@ -2522,25 +2689,23 @@ public class StatsPullAtomService extends SystemService { ); } - int pullProcessCpuTime(int atomTag, List<StatsEvent> pulledData) { - synchronized (mCpuTrackerLock) { - if (mProcessCpuTracker == null) { - mProcessCpuTracker = new ProcessCpuTracker(false); - mProcessCpuTracker.init(); - } - mProcessCpuTracker.update(); - for (int i = 0; i < mProcessCpuTracker.countStats(); i++) { - ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i); - StatsEvent e = StatsEvent.newBuilder() - .setAtomId(atomTag) - .writeInt(st.uid) - .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true) - .writeString(st.name) - .writeLong(st.base_utime) - .writeLong(st.base_stime) - .build(); - pulledData.add(e); - } + int pullProcessCpuTimeLocked(int atomTag, List<StatsEvent> pulledData) { + if (mProcessCpuTracker == null) { + mProcessCpuTracker = new ProcessCpuTracker(false); + mProcessCpuTracker.init(); + } + mProcessCpuTracker.update(); + for (int i = 0; i < mProcessCpuTracker.countStats(); i++) { + ProcessCpuTracker.Stats st = mProcessCpuTracker.getStats(i); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeInt(st.uid) + .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true) + .writeString(st.name) + .writeLong(st.base_utime) + .writeLong(st.base_stime) + .build(); + pulledData.add(e); } return StatsManager.PULL_SUCCESS; } @@ -2558,7 +2723,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullCpuTimePerThreadFreq(int atomTag, List<StatsEvent> pulledData) { + int pullCpuTimePerThreadFreqLocked(int atomTag, List<StatsEvent> pulledData) { if (this.mKernelCpuThreadReader == null) { Slog.e(TAG, "mKernelCpuThreadReader is null"); return StatsManager.PULL_SKIP; @@ -2617,23 +2782,27 @@ public class StatsPullAtomService extends SystemService { } private BatteryStatsHelper getBatteryStatsHelper() { - if (mBatteryStatsHelper == null) { - final long callingToken = Binder.clearCallingIdentity(); - try { - // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly(). - mBatteryStatsHelper = new BatteryStatsHelper(mContext, false); - } finally { - Binder.restoreCallingIdentity(callingToken); + synchronized (mBatteryStatsHelperLock) { + if (mBatteryStatsHelper == null) { + final long callingToken = Binder.clearCallingIdentity(); + try { + // clearCallingIdentity required for BatteryStatsHelper.checkWifiOnly(). + mBatteryStatsHelper = new BatteryStatsHelper(mContext, false); + } finally { + Binder.restoreCallingIdentity(callingToken); + } + mBatteryStatsHelper.create((Bundle) null); + } + long currentTime = SystemClock.elapsedRealtime(); + if (currentTime - mBatteryStatsHelperTimestampMs + >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) { + // Load BatteryStats and do all the calculations. + mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, + UserHandle.USER_ALL); + // Calculations are done so we don't need to save the raw BatteryStats data in RAM. + mBatteryStatsHelper.clearStats(); + mBatteryStatsHelperTimestampMs = currentTime; } - mBatteryStatsHelper.create((Bundle) null); - } - long currentTime = SystemClock.elapsedRealtime(); - if (currentTime - mBatteryStatsHelperTimestampMs >= MAX_BATTERY_STATS_HELPER_FREQUENCY_MS) { - // Load BatteryStats and do all the calculations. - mBatteryStatsHelper.refreshStats(BatteryStats.STATS_SINCE_CHARGED, UserHandle.USER_ALL); - // Calculations are done so we don't need to save the raw BatteryStats data in RAM. - mBatteryStatsHelper.clearStats(); - mBatteryStatsHelperTimestampMs = currentTime; } return mBatteryStatsHelper; } @@ -2652,7 +2821,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDeviceCalculatedPowerUse(int atomTag, List<StatsEvent> pulledData) { + int pullDeviceCalculatedPowerUseLocked(int atomTag, List<StatsEvent> pulledData) { BatteryStatsHelper bsHelper = getBatteryStatsHelper(); StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) @@ -2672,7 +2841,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDeviceCalculatedPowerBlameUid(int atomTag, List<StatsEvent> pulledData) { + int pullDeviceCalculatedPowerBlameUidLocked(int atomTag, List<StatsEvent> pulledData) { final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList(); if (sippers == null) { return StatsManager.PULL_SKIP; @@ -2703,7 +2872,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDeviceCalculatedPowerBlameOther(int atomTag, List<StatsEvent> pulledData) { + int pullDeviceCalculatedPowerBlameOtherLocked(int atomTag, List<StatsEvent> pulledData) { final List<BatterySipper> sippers = getBatteryStatsHelper().getUsageList(); if (sippers == null) { return StatsManager.PULL_SKIP; @@ -2739,41 +2908,37 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDebugElapsedClock(int atomTag, List<StatsEvent> pulledData) { + int pullDebugElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) { final long elapsedMillis = SystemClock.elapsedRealtime(); + final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0 + ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue; - synchronized (mDebugElapsedClockLock) { - final long clockDiffMillis = mDebugElapsedClockPreviousValue == 0 - ? 0 : elapsedMillis - mDebugElapsedClockPreviousValue; + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeLong(mDebugElapsedClockPullCount) + .writeLong(elapsedMillis) + // Log it twice to be able to test multi-value aggregation from ValueMetric. + .writeLong(elapsedMillis) + .writeLong(clockDiffMillis) + .writeInt(1 /* always set */) + .build(); + pulledData.add(e); - StatsEvent e = StatsEvent.newBuilder() + if (mDebugElapsedClockPullCount % 2 == 1) { + StatsEvent e2 = StatsEvent.newBuilder() .setAtomId(atomTag) .writeLong(mDebugElapsedClockPullCount) .writeLong(elapsedMillis) // Log it twice to be able to test multi-value aggregation from ValueMetric. .writeLong(elapsedMillis) .writeLong(clockDiffMillis) - .writeInt(1 /* always set */) + .writeInt(2 /* set on odd pulls */) .build(); - pulledData.add(e); - - if (mDebugElapsedClockPullCount % 2 == 1) { - StatsEvent e2 = StatsEvent.newBuilder() - .setAtomId(atomTag) - .writeLong(mDebugElapsedClockPullCount) - .writeLong(elapsedMillis) - // Log it twice to be able to test multi-value aggregation from ValueMetric. - .writeLong(elapsedMillis) - .writeLong(clockDiffMillis) - .writeInt(2 /* set on odd pulls */) - .build(); - pulledData.add(e2); - } - - mDebugElapsedClockPullCount++; - mDebugElapsedClockPreviousValue = elapsedMillis; + pulledData.add(e2); } + mDebugElapsedClockPullCount++; + mDebugElapsedClockPreviousValue = elapsedMillis; return StatsManager.PULL_SUCCESS; } @@ -2790,31 +2955,27 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDebugFailingElapsedClock(int atomTag, List<StatsEvent> pulledData) { + int pullDebugFailingElapsedClockLocked(int atomTag, List<StatsEvent> pulledData) { final long elapsedMillis = SystemClock.elapsedRealtime(); - - synchronized (mDebugFailingElapsedClockLock) { - // Fails every 5 buckets. - if (mDebugFailingElapsedClockPullCount++ % 5 == 0) { - mDebugFailingElapsedClockPreviousValue = elapsedMillis; - Slog.e(TAG, "Failing debug elapsed clock"); - return StatsManager.PULL_SKIP; - } - - StatsEvent e = StatsEvent.newBuilder() - .setAtomId(atomTag) - .writeLong(mDebugFailingElapsedClockPullCount) - .writeLong(elapsedMillis) - // Log it twice to be able to test multi-value aggregation from ValueMetric. - .writeLong(elapsedMillis) - .writeLong(mDebugFailingElapsedClockPreviousValue == 0 - ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue) - .build(); - pulledData.add(e); - + // Fails every 5 buckets. + if (mDebugFailingElapsedClockPullCount++ % 5 == 0) { mDebugFailingElapsedClockPreviousValue = elapsedMillis; + Slog.e(TAG, "Failing debug elapsed clock"); + return StatsManager.PULL_SKIP; } + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeLong(mDebugFailingElapsedClockPullCount) + .writeLong(elapsedMillis) + // Log it twice to be able to test multi-value aggregation from ValueMetric. + .writeLong(elapsedMillis) + .writeLong(mDebugFailingElapsedClockPreviousValue == 0 + ? 0 : elapsedMillis - mDebugFailingElapsedClockPreviousValue) + .build(); + pulledData.add(e); + + mDebugFailingElapsedClockPreviousValue = elapsedMillis; return StatsManager.PULL_SUCCESS; } @@ -2828,7 +2989,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullBuildInformation(int atomTag, List<StatsEvent> pulledData) { + int pullBuildInformationLocked(int atomTag, List<StatsEvent> pulledData) { StatsEvent e = StatsEvent.newBuilder() .setAtomId(atomTag) .writeString(Build.FINGERPRINT) @@ -2856,7 +3017,7 @@ public class StatsPullAtomService extends SystemService { } // Add a RoleHolder atom for each package that holds a role. - int pullRoleHolder(int atomTag, List<StatsEvent> pulledData) { + int pullRoleHolderLocked(int atomTag, List<StatsEvent> pulledData) { long callingToken = Binder.clearCallingIdentity(); try { PackageManager pm = mContext.getPackageManager(); @@ -2914,7 +3075,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullDangerousPermissionState(int atomTag, List<StatsEvent> pulledData) { + int pullDangerousPermissionStateLocked(int atomTag, List<StatsEvent> pulledData) { final long token = Binder.clearCallingIdentity(); float samplingRate = DeviceConfig.getFloat(DeviceConfig.NAMESPACE_PERMISSIONS, DANGEROUS_PERMISSION_STATE_SAMPLE_RATE, 0.02f); @@ -3007,7 +3168,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullTimeZoneDataInfo(int atomTag, List<StatsEvent> pulledData) { + int pullTimeZoneDataInfoLocked(int atomTag, List<StatsEvent> pulledData) { String tzDbVersion = "Unknown"; try { tzDbVersion = android.icu.util.TimeZone.getTZDataVersion(); @@ -3034,7 +3195,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) { + int pullExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) { if (mStorageManager == null) { return StatsManager.PULL_SKIP; } @@ -3084,7 +3245,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullAppsOnExternalStorageInfo(int atomTag, List<StatsEvent> pulledData) { + int pullAppsOnExternalStorageInfoLocked(int atomTag, List<StatsEvent> pulledData) { if (mStorageManager == null) { return StatsManager.PULL_SKIP; } @@ -3140,7 +3301,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullFaceSettings(int atomTag, List<StatsEvent> pulledData) { + int pullFaceSettingsLocked(int atomTag, List<StatsEvent> pulledData) { final long callingToken = Binder.clearCallingIdentity(); try { List<UserInfo> users = mContext.getSystemService(UserManager.class).getUsers(); @@ -3222,7 +3383,7 @@ public class StatsPullAtomService extends SystemService { } } - int pullAppOps(int atomTag, List<StatsEvent> pulledData) { + int pullAppOpsLocked(int atomTag, List<StatsEvent> pulledData) { final long token = Binder.clearCallingIdentity(); try { AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); @@ -3299,7 +3460,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullAttributedAppOps(int atomTag, List<StatsEvent> pulledData) { + int pullAttributedAppOpsLocked(int atomTag, List<StatsEvent> pulledData) { final long token = Binder.clearCallingIdentity(); try { AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); @@ -3358,7 +3519,7 @@ public class StatsPullAtomService extends SystemService { CompletableFuture<HistoricalOps> ops = new CompletableFuture<>(); HistoricalOpsRequest histOpsRequest = new HistoricalOpsRequest.Builder( - Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(), + Math.max(Instant.now().minus(1, ChronoUnit.DAYS).toEpochMilli(), 0), Long.MAX_VALUE).setFlags( OP_FLAGS_PULLED).build(); appOps.getHistoricalOps(histOpsRequest, AsyncTask.THREAD_POOL_EXECUTOR, ops::complete); @@ -3377,7 +3538,9 @@ public class StatsPullAtomService extends SystemService { } int estimatedSamplingRate = (int) constrain( appOpsTargetCollectionSize * 100 / estimatedSize, 0, 100); - mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate); + synchronized (mAppOpsSamplingRateLock) { + mAppOpsSamplingRate = min(mAppOpsSamplingRate, estimatedSamplingRate); + } } private List<AppOpEntry> processHistoricalOps( @@ -3420,7 +3583,7 @@ public class StatsPullAtomService extends SystemService { } } - int pullRuntimeAppOpAccessMessage(int atomTag, List<StatsEvent> pulledData) { + int pullRuntimeAppOpAccessMessageLocked(int atomTag, List<StatsEvent> pulledData) { final long token = Binder.clearCallingIdentity(); try { AppOpsManager appOps = mContext.getSystemService(AppOpsManager.class); @@ -3507,7 +3670,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullNotificationRemoteViews(int atomTag, List<StatsEvent> pulledData) { + int pullNotificationRemoteViewsLocked(int atomTag, List<StatsEvent> pulledData) { INotificationManager notificationManagerService = getINotificationManagerService(); if (notificationManagerService == null) { return StatsManager.PULL_SKIP; @@ -3601,7 +3764,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullHealthHal(int atomTag, List<StatsEvent> pulledData) { + int pullHealthHalLocked(int atomTag, List<StatsEvent> pulledData) { IHealth healthService = mHealthService.getLastService(); if (healthService == null) { return StatsManager.PULL_SKIP; @@ -3651,7 +3814,7 @@ public class StatsPullAtomService extends SystemService { ); } - int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) { + int pullSettingsStatsLocked(int atomTag, List<StatsEvent> pulledData) { UserManager userManager = mContext.getSystemService(UserManager.class); if (userManager == null) { return StatsManager.PULL_SKIP; @@ -3678,21 +3841,6 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } - private void registerDisplayWakeStats() { - int tagId = FrameworkStatsLog.DISPLAY_WAKE_REASON; - mStatsManager.setPullAtomCallback( - tagId, - null, // use default PullAtomMetadata values - DIRECT_EXECUTOR, - mStatsCallbackImpl - ); - } - - int pullDisplayWakeStats(int atomTag, List<StatsEvent> pulledData) { - //TODO: Denny, implement read/write DisplayWakeStats, b/154172964 - return 0; - } - // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override @@ -3749,11 +3897,13 @@ public class StatsPullAtomService extends SystemService { final SubInfo subInfo = new SubInfo(subId, sub.getCarrierId(), mcc, mnc, subscriberId, sub.isOpportunistic()); Slog.i(TAG, "subId " + subId + " added into historical sub list"); - mHistoricalSubs.add(subInfo); - // Since getting snapshot when pulling will also include data before boot, - // query stats as baseline to prevent double count is needed. - mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo)); + synchronized (mDataBytesTransferLock) { + mHistoricalSubs.add(subInfo); + // Since getting snapshot when pulling will also include data before boot, + // query stats as baseline to prevent double count is needed. + mNetworkStatsBaselines.addAll(getDataUsageBytesTransferSnapshotForSub(subInfo)); + } } } } diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index 34998a025663..b9240c78d711 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -898,11 +898,16 @@ final class AccessibilityController { /* ignore */ } mSurfaceControl = surfaceControl; - mService.mTransactionFactory.get().setLayer(mSurfaceControl, - mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) - * WindowManagerService.TYPE_LAYER_MULTIPLIER) - .setPosition(mSurfaceControl, 0, 0) - .apply(); + + final SurfaceControl.Transaction t = mService.mTransactionFactory.get(); + final int layer = + mService.mPolicy.getWindowLayerFromTypeLw(TYPE_MAGNIFICATION_OVERLAY) * + WindowManagerService.TYPE_LAYER_MULTIPLIER; + t.setLayer(mSurfaceControl, layer).setPosition(mSurfaceControl, 0, 0); + InputMonitor.setTrustedOverlayInputInfo(mSurfaceControl, t, + mDisplayContent.getDisplayId(), "Magnification Overlay"); + t.apply(); + mSurface.copyFrom(mSurfaceControl); mAnimationController = new AnimationController(context, diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index fe2b144bcdd6..be2f9d410475 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -2842,7 +2842,8 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // their client may have activities. // No longer have activities, so update LRU list and oom adj. app.updateProcessInfo(true /* updateServiceConnectionActivities */, - false /* activityChange */, true /* updateOomAdj */); + false /* activityChange */, true /* updateOomAdj */, + false /* addPendingTopUid */); } } @@ -7539,7 +7540,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A public String toString() { if (stringName != null) { return stringName + " t" + (task == null ? INVALID_TASK_ID : task.mTaskId) + - (finishing ? " f}" : "") + (mIsExiting ? " mIsExiting=" : "") + "}"; + (finishing ? " f}" : "") + (mIsExiting ? " isExiting" : "") + "}"; } StringBuilder sb = new StringBuilder(128); sb.append("ActivityRecord{"); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 0d5621dc0e4f..4bede4c3623f 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -1682,7 +1682,8 @@ class ActivityStack extends Task { // happens to be sitting towards the end. if (next.attachedToProcess()) { next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* activityChange */, false /* updateOomAdj */); + true /* activityChange */, false /* updateOomAdj */, + false /* addPendingTopUid */); } else if (!next.isProcessRunning()) { // Since the start-process is asynchronous, if we already know the process of next // activity isn't running, we can start the process earlier to save the time to wait @@ -1839,7 +1840,8 @@ class ActivityStack extends Task { next.setState(RESUMED, "resumeTopActivityInnerLocked"); next.app.updateProcessInfo(false /* updateServiceConnectionActivities */, - true /* activityChange */, true /* updateOomAdj */); + true /* activityChange */, true /* updateOomAdj */, + true /* addPendingTopUid */); // Have the window manager re-evaluate the orientation of // the screen based on the new activity order. @@ -3230,22 +3232,22 @@ class ActivityStack extends Task { @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { - pw.println(prefix + "mStackId=" + getRootTaskId()); - pw.println(prefix + "mDeferRemoval=" + mDeferRemoval); - pw.println(prefix + "mBounds=" + getRawBounds().toShortString()); - for (int taskNdx = mChildren.size() - 1; taskNdx >= 0; taskNdx--) { - mChildren.get(taskNdx).dump(pw, prefix + " ", dumpAll); + if (mDeferRemoval) { + pw.println(prefix + "mDeferRemoval=true"); } + super.dump(pw, prefix, dumpAll); if (!mExitingActivities.isEmpty()) { pw.println(); - pw.println(" Exiting application tokens:"); + pw.println(prefix + "Exiting application tokens:"); + final String doublePrefix = prefix + " "; for (int i = mExitingActivities.size() - 1; i >= 0; i--) { WindowToken token = mExitingActivities.get(i); - pw.print(" Exiting App #"); pw.print(i); + pw.print(doublePrefix + "Exiting App #" + i); pw.print(' '); pw.print(token); pw.println(':'); - token.dump(pw, " ", dumpAll); + token.dump(pw, doublePrefix, dumpAll); } + pw.println(); } mAnimatingActivityRegistry.dump(pw, "AnimatingApps:", prefix); } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index b7ca1a9aeab8..1f9e8609c2ad 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -1886,7 +1886,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { public void dump(PrintWriter pw, String prefix) { pw.println(); pw.println("ActivityStackSupervisor state:"); - mRootWindowContainer.dump(pw, prefix); + mRootWindowContainer.dump(pw, prefix, true /* dumpAll */); getKeyguardController().dump(pw, prefix); mService.getLockTaskController().dump(pw, prefix); pw.print(prefix); diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java index 5f591b54b067..7c935d0ea546 100644 --- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java +++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java @@ -4873,6 +4873,10 @@ public class ActivityTaskManagerService extends IActivityTaskManager.Stub { return; } + if (isInPictureInPictureMode(activity)) { + throw new IllegalStateException("Activity is already in PIP mode"); + } + final boolean canEnterPictureInPicture = activity.checkEnterPictureInPictureState( "requestPictureInPictureMode", /* beforeStopping */ false); if (!canEnterPictureInPicture) { diff --git a/services/core/java/com/android/server/wm/AlertWindowNotification.java b/services/core/java/com/android/server/wm/AlertWindowNotification.java index 7b511ec20541..fde036950245 100644 --- a/services/core/java/com/android/server/wm/AlertWindowNotification.java +++ b/services/core/java/com/android/server/wm/AlertWindowNotification.java @@ -18,6 +18,7 @@ package com.android.server.wm; import static android.app.NotificationManager.IMPORTANCE_MIN; import static android.app.PendingIntent.FLAG_CANCEL_CURRENT; +import static android.app.PendingIntent.FLAG_IMMUTABLE; import static android.content.Context.NOTIFICATION_SERVICE; import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; @@ -139,7 +140,8 @@ class AlertWindowNotification { Uri.fromParts("package", packageName, null)); intent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK); // Calls into activity manager... - return PendingIntent.getActivity(context, mRequestCode, intent, FLAG_CANCEL_CURRENT); + return PendingIntent.getActivity(context, mRequestCode, intent, + FLAG_CANCEL_CURRENT | FLAG_IMMUTABLE); } private void createNotificationChannel(Context context, String appName) { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index a5b94b327699..4e19a5224bb4 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -2977,12 +2977,10 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo pw.println(); mWallpaperController.dump(pw, " "); - pw.println(); - pw.print("mSystemGestureExclusion="); if (mSystemGestureExclusionListeners.getRegisteredCallbackCount() > 0) { + pw.println(); + pw.print(" mSystemGestureExclusion="); pw.println(mSystemGestureExclusion); - } else { - pw.println("<no lstnrs>"); } pw.println(); @@ -3506,22 +3504,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo * doesn't support IME/system decorations. * * @param target current IME target. - * @return {@link WindowState} that can host IME. + * @return {@link InsetsControlTarget} that can host IME. */ - WindowState getImeHostOrFallback(WindowState target) { + InsetsControlTarget getImeHostOrFallback(WindowState target) { if (target != null && target.getDisplayContent().canShowIme()) { return target; } return getImeFallback(); } - WindowState getImeFallback() { - + InsetsControlTarget getImeFallback() { // host is in non-default display that doesn't support system decor, default to - // default display's StatusBar to control IME. - // TODO: (b/148234093)find a better host OR control IME animation/visibility directly - // because it won't work when statusbar isn't available. - return mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar(); + // default display's StatusBar to control IME (when available), else let system control it. + WindowState statusBar = + mWmService.getDefaultDisplayContentLocked().getDisplayPolicy().getStatusBar(); + return statusBar != null ? statusBar : mRemoteInsetsControlTarget; } boolean canShowIme() { diff --git a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java index 2165b0e8b593..c9cc94423fe2 100644 --- a/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java +++ b/services/core/java/com/android/server/wm/EmulatorDisplayOverlay.java @@ -66,6 +66,9 @@ class EmulatorDisplayOverlay { t.setLayer(ctrl, zOrder); t.setPosition(ctrl, 0, 0); t.show(ctrl); + // Ensure we aren't considered as obscuring for Input purposes. + InputMonitor.setTrustedOverlayInputInfo(ctrl, t, + dc.getDisplayId(), "EmulatorDisplayOverlay"); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java index efcd61df5c75..8734b5efa45d 100644 --- a/services/core/java/com/android/server/wm/InputMonitor.java +++ b/services/core/java/com/android/server/wm/InputMonitor.java @@ -16,13 +16,17 @@ package com.android.server.wm; +import static android.os.Process.myPid; +import static android.os.Process.myUid; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.WindowManager.INPUT_CONSUMER_NAVIGATION; import static android.view.WindowManager.INPUT_CONSUMER_PIP; import static android.view.WindowManager.INPUT_CONSUMER_RECENTS_ANIMATION; import static android.view.WindowManager.INPUT_CONSUMER_WALLPAPER; import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL; +import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_DISABLE_WALLPAPER_TOUCH_EVENTS; +import static android.view.WindowManager.LayoutParams.TYPE_SECURE_SYSTEM_OVERLAY; import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; @@ -550,4 +554,26 @@ final class InputMonitor { } } } + + /** + * Helper function to generate an InputInfo with type SECURE_SYSTEM_OVERLAY. This input + * info will not have an input channel or be touchable, but is used to omit Surfaces + * from occlusion detection, so that System global overlays like the Watermark aren't + * counted by the InputDispatcher as occluding applications below. + */ + static void setTrustedOverlayInputInfo(SurfaceControl sc, SurfaceControl.Transaction t, + int displayId, String name) { + InputWindowHandle inputWindowHandle = new InputWindowHandle(null, displayId); + inputWindowHandle.name = name; + inputWindowHandle.layoutParamsType = TYPE_SECURE_SYSTEM_OVERLAY; + inputWindowHandle.dispatchingTimeoutNanos = -1; + inputWindowHandle.visible = true; + inputWindowHandle.canReceiveKeys = false; + inputWindowHandle.hasFocus = false; + inputWindowHandle.ownerPid = myPid(); + inputWindowHandle.ownerUid = myUid(); + inputWindowHandle.inputFeatures = INPUT_FEATURE_NO_INPUT_CHANNEL; + inputWindowHandle.scaleFactor = 1; + t.setInputWindowInfo(sc, inputWindowHandle); + } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index ae5adcae5b9b..583663c5455f 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -3570,12 +3570,14 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } } - public void dump(PrintWriter pw, String prefix) { + @Override + public void dump(PrintWriter pw, String prefix, boolean dumpAll) { + super.dump(pw, prefix, dumpAll); pw.print(prefix); pw.println("topDisplayFocusedStack=" + getTopDisplayFocusedStack()); for (int i = getChildCount() - 1; i >= 0; --i) { final DisplayContent display = getChildAt(i); - display.dump(pw, prefix, true /* dumpAll */); + display.dump(pw, prefix, dumpAll); } pw.println(); } diff --git a/services/core/java/com/android/server/wm/StrictModeFlash.java b/services/core/java/com/android/server/wm/StrictModeFlash.java index f537005c955c..fa62daaff3fc 100644 --- a/services/core/java/com/android/server/wm/StrictModeFlash.java +++ b/services/core/java/com/android/server/wm/StrictModeFlash.java @@ -54,6 +54,10 @@ class StrictModeFlash { t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 101); t.setPosition(ctrl, 0, 0); t.show(ctrl); + // Ensure we aren't considered as obscuring for Input purposes. + InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), + "StrictModeFlash"); + mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 1b77fd2e8782..0e5d7d910084 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -428,16 +428,11 @@ class SurfaceAnimator { void dump(PrintWriter pw, String prefix) { pw.print(prefix); pw.print("mLeash="); pw.print(mLeash); - if (mAnimationStartDelayed) { - pw.print(" mAnimationStartDelayed="); pw.println(mAnimationStartDelayed); - } else { - pw.println(); - } - pw.print(prefix); pw.println("Animation:"); + pw.print(" mAnimationType=" + mAnimationType); + pw.println(mAnimationStartDelayed ? " mAnimationStartDelayed=true" : ""); + pw.print(prefix); pw.print("Animation: "); pw.println(mAnimation); if (mAnimation != null) { mAnimation.dump(pw, prefix + " "); - } else { - pw.print(prefix); pw.println("null"); } } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 48609e17ba40..3ee7ee7a4276 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -3519,20 +3519,17 @@ class Task extends WindowContainer<WindowContainer> { @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { super.dump(pw, prefix, dumpAll); + pw.println(prefix + "bounds=" + getBounds().toShortString()); final String doublePrefix = prefix + " "; - - pw.println(prefix + "taskId=" + mTaskId); - pw.println(doublePrefix + "mBounds=" + getBounds().toShortString()); - pw.println(doublePrefix + "appTokens=" + mChildren); - - final String triplePrefix = doublePrefix + " "; - final String quadruplePrefix = triplePrefix + " "; - - int[] index = { 0 }; - forAllActivities((r) -> { - pw.println(triplePrefix + "Activity #" + index[0]++ + " " + r); - r.dump(pw, quadruplePrefix, dumpAll); - }); + for (int i = mChildren.size() - 1; i >= 0; i--) { + final WindowContainer<?> child = mChildren.get(i); + pw.println(prefix + "* " + child); + // Only dump non-activity because full activity info is already printed by + // RootWindowContainer#dumpActivities. + if (child.asActivityRecord() == null) { + child.dump(pw, doublePrefix, dumpAll); + } + } } /** diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 22054db20bbd..102c2a6364f4 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -1772,16 +1772,20 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { @Override void dump(PrintWriter pw, String prefix, boolean dumpAll) { pw.println(prefix + "TaskDisplayArea " + getName()); + super.dump(pw, prefix, dumpAll); if (mPreferredTopFocusableStack != null) { pw.println(prefix + " mPreferredTopFocusableStack=" + mPreferredTopFocusableStack); } if (mLastFocusedStack != null) { pw.println(prefix + " mLastFocusedStack=" + mLastFocusedStack); } - pw.println(prefix + " Application tokens in top down Z order:"); + final String doublePrefix = prefix + " "; + final String triplePrefix = doublePrefix + " "; + pw.println(doublePrefix + "Application tokens in top down Z order:"); for (int stackNdx = getChildCount() - 1; stackNdx >= 0; --stackNdx) { final ActivityStack stack = getChildAt(stackNdx); - stack.dump(pw, prefix + " ", dumpAll); + pw.println(doublePrefix + "* " + stack); + stack.dump(pw, triplePrefix, dumpAll); } } } diff --git a/services/core/java/com/android/server/wm/Watermark.java b/services/core/java/com/android/server/wm/Watermark.java index 4e1b2177c87c..3d49ebe306e6 100644 --- a/services/core/java/com/android/server/wm/Watermark.java +++ b/services/core/java/com/android/server/wm/Watermark.java @@ -29,6 +29,7 @@ import android.util.DisplayMetrics; import android.util.Log; import android.util.TypedValue; import android.view.Display; +import android.view.InputWindowHandle; import android.view.Surface; import android.view.Surface.OutOfResourcesException; import android.view.SurfaceControl; @@ -124,6 +125,8 @@ class Watermark { t.setLayer(ctrl, WindowManagerService.TYPE_LAYER_MULTIPLIER * 100) .setPosition(ctrl, 0, 0) .show(ctrl); + // Ensure we aren't considered as obscuring for Input purposes. + InputMonitor.setTrustedOverlayInputInfo(ctrl, t, dc.getDisplayId(), "Watermark"); mSurface.copyFrom(ctrl); } catch (OutOfResourcesException e) { } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index d1366bd2976e..0590288a7f8b 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -5616,11 +5616,6 @@ public class WindowManagerService extends IWindowManager.Stub mLatencyTracker.onActionStart(ACTION_ROTATE_SCREEN); mExitAnimId = exitAnim; mEnterAnimId = enterAnim; - ScreenRotationAnimation screenRotationAnimation = - displayContent.getRotationAnimation(); - if (screenRotationAnimation != null) { - screenRotationAnimation.kill(); - } displayContent.updateDisplayInfo(); final int originalRotation = overrideOriginalRotation != ROTATION_UNDEFINED @@ -7628,8 +7623,12 @@ public class WindowManagerService extends IWindowManager.Stub if (imeTarget == null) { return; } - imeTarget = imeTarget.getImeControlTarget(); - imeTarget.getDisplayContent().getInsetsStateController().getImeSourceProvider() + imeTarget = imeTarget.getImeControlTarget().getWindow(); + // If InsetsControlTarget doesn't have a window, its using remoteControlTarget which + // is controlled by default display + final DisplayContent dc = imeTarget != null + ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked(); + dc.getInsetsStateController().getImeSourceProvider() .scheduleShowImePostLayout(imeTarget); } } @@ -7642,7 +7641,9 @@ public class WindowManagerService extends IWindowManager.Stub // The target window no longer exists. return; } - final DisplayContent dc = imeTarget.getImeControlTarget().getDisplayContent(); + imeTarget = imeTarget.getImeControlTarget().getWindow(); + final DisplayContent dc = imeTarget != null + ? imeTarget.getDisplayContent() : getDefaultDisplayContentLocked(); // If there was a pending IME show(), reset it as IME has been // requested to be hidden. dc.getInsetsStateController().getImeSourceProvider().abortShowImePostLayout(); diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java index 2ec6df5878ef..29cf1776df9c 100644 --- a/services/core/java/com/android/server/wm/WindowProcessController.java +++ b/services/core/java/com/android/server/wm/WindowProcessController.java @@ -1007,8 +1007,11 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } void updateProcessInfo(boolean updateServiceConnectionActivities, boolean activityChange, - boolean updateOomAdj) { + boolean updateOomAdj, boolean addPendingTopUid) { if (mListener == null) return; + if (addPendingTopUid) { + mAtm.mAmInternal.addPendingTopUid(mUid, mPid); + } // Posting on handler so WM lock isn't held when we call into AM. final Message m = PooledLambda.obtainMessage(WindowProcessListener::updateProcessInfo, mListener, updateServiceConnectionActivities, activityChange, updateOomAdj); @@ -1068,7 +1071,7 @@ public class WindowProcessController extends ConfigurationContainer<Configuratio } // update ActivityManagerService.PendingStartActivityUids list. if (topProcessState == ActivityManager.PROCESS_STATE_TOP) { - mAtm.mAmInternal.updatePendingTopUid(mUid, true); + mAtm.mAmInternal.addPendingTopUid(mUid, mPid); } // Posting the message at the front of queue so WM lock isn't held when we call into AM, // and the process state of starting activity can be updated quicker which will give it a diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 36232e13fcf1..fe3ee50c34c5 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -5404,10 +5404,10 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * {@link android.view.inputmethod.InputMethodManager#showSoftInput(View, int)} is unknown, * use {@link DisplayContent#getImeControlTarget()} instead. * - * @return {@link WindowState} of host that controls the IME. + * @return {@link InsetsControlTarget} of host that controls the IME. * When window is doesn't have a parent, it is returned as-is. */ - WindowState getImeControlTarget() { + InsetsControlTarget getImeControlTarget() { final DisplayContent dc = getDisplayContent(); final WindowState parentWindow = dc.getParentWindow(); diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index f1064d153814..df55b3bbd1a4 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -2616,6 +2616,8 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { mSetupContentObserver = new SetupContentObserver(mHandler); mUserManagerInternal.addUserRestrictionsListener(new RestrictionsListener(mContext)); + + loadOwners(); } /** @@ -2676,12 +2678,23 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } } + /** + * Load information about device and profile owners of the device, populating mOwners and + * pushing owner info to other system services. This is called at a fairly early stage of + * system server initialiation (via DevicePolicyManagerService's ctor), so care should to + * be taken to not interact with system services that are initialiated after DPMS. + * onLockSettingsReady() is a safer place to do initialization work not critical during + * the first boot stage. + * Note this only loads the list of owners, and not their actual policy (DevicePolicyData). + * The policy is normally loaded lazily when it's first accessed. In several occasions + * the list of owners is necessary for providing callers with aggregated policies across + * multiple owners, hence the owner list is loaded as part of DPMS's construction here. + */ void loadOwners() { synchronized (getLockObject()) { mOwners.load(); setDeviceOwnershipSystemPropertyLocked(); findOwnerComponentIfNecessaryLocked(); - migrateUserRestrictionsIfNecessaryLocked(); // TODO PO may not have a class name either due to b/17652534. Address that too. updateDeviceOwnerLocked(); @@ -4104,8 +4117,10 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { } private void onLockSettingsReady() { + synchronized (getLockObject()) { + migrateUserRestrictionsIfNecessaryLocked(); + } getUserData(UserHandle.USER_SYSTEM); - loadOwners(); cleanUpOldUsers(); maybeSetDefaultProfileOwnerUserRestrictions(); handleStartUser(UserHandle.USER_SYSTEM); diff --git a/services/tests/mockingservicestests/Android.bp b/services/tests/mockingservicestests/Android.bp index ff34ebd8aa9d..b4e0f10f14b0 100644 --- a/services/tests/mockingservicestests/Android.bp +++ b/services/tests/mockingservicestests/Android.bp @@ -21,7 +21,7 @@ android_test { "services.core", "services.net", "service-jobscheduler", - "service-permission", + "service-permission.impl", "service-blobstore", "androidx.test.runner", "androidx.test.ext.truth", diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp index 40a17061c7f1..979f4e179e95 100644 --- a/services/tests/servicestests/Android.bp +++ b/services/tests/servicestests/Android.bp @@ -44,7 +44,7 @@ android_test { "hamcrest-library", "servicestests-utils", "service-jobscheduler", - "service-permission", + "service-permission.impl", // TODO: remove once Android migrates to JUnit 4.12, // which provides assertThrows "testng", diff --git a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk Binary files differindex 8056e0bf6e50..211e064399a8 100644 --- a/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk +++ b/services/tests/servicestests/assets/AppIntegrityManagerServiceImplTest/SourceStampTestApk.apk diff --git a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java index 53c9bb22e752..9ca84d33998c 100644 --- a/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java +++ b/services/tests/servicestests/src/com/android/server/integrity/AppIntegrityManagerServiceImplTest.java @@ -121,7 +121,7 @@ public class AppIntegrityManagerServiceImplTest { private static final String INSTALLER_SHA256 = "30F41A7CBF96EE736A54DD6DF759B50ED3CC126ABCEF694E167C324F5976C227"; private static final String SOURCE_STAMP_CERTIFICATE_HASH = - "681B0E56A796350C08647352A4DB800CC44B2ADC8F4C72FA350BD05D4D50264D"; + "C6E737809CEF2B08CC6694892215F82A5E8FBC3C2A0F6212770310B90622D2D9"; private static final String DUMMY_APP_TWO_CERTS_CERT_1 = "C0369C2A1096632429DFA8433068AECEAD00BAC337CA92A175036D39CC9AFE94"; diff --git a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java index f205fde88c0d..399a00f0cb5a 100644 --- a/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/AppsFilterTest.java @@ -23,6 +23,7 @@ import static org.hamcrest.Matchers.empty; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -57,6 +58,7 @@ import org.junit.runners.JUnit4; import org.mockito.Mock; import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import org.mockito.stubbing.Answer; import java.security.cert.CertificateException; import java.util.ArrayList; @@ -69,16 +71,20 @@ import java.util.Set; @RunWith(JUnit4.class) public class AppsFilterTest { - private static final int DUMMY_CALLING_UID = 10345; - private static final int DUMMY_TARGET_UID = 10556; - private static final int DUMMY_ACTOR_UID = 10656; - private static final int DUMMY_OVERLAY_UID = 10756; - private static final int DUMMY_ACTOR_TWO_UID = 10856; + private static final int DUMMY_CALLING_APPID = 10345; + private static final int DUMMY_TARGET_APPID = 10556; + private static final int DUMMY_ACTOR_APPID = 10656; + private static final int DUMMY_OVERLAY_APPID = 10756; + private static final int SYSTEM_USER = 0; + private static final int[] SINGLE_USER_ARRAY = {SYSTEM_USER}; @Mock AppsFilter.FeatureConfig mFeatureConfigMock; + @Mock + AppsFilter.StateProvider mStateProvider; private ArrayMap<String, PackageSetting> mExisting = new ArrayMap<>(); + private Object mDummyLock = new Object(); private static ParsingPackage pkg(String packageName) { return PackageImpl.forTesting(packageName) @@ -170,15 +176,24 @@ public class AppsFilterTest { mExisting = new ArrayMap<>(); MockitoAnnotations.initMocks(this); + doAnswer(invocation -> { + ((AppsFilter.StateProvider.CurrentStateCallback) invocation.getArgument(0)) + .currentState(mExisting, SINGLE_USER_ARRAY); + return null; + }).when(mStateProvider) + .runWithState(any(AppsFilter.StateProvider.CurrentStateCallback.class)); + when(mFeatureConfigMock.isGloballyEnabled()).thenReturn(true); - when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) - .thenReturn(true); + when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))).thenAnswer( + (Answer<Boolean>) invocation -> + ((AndroidPackage)invocation.getArgument(SYSTEM_USER)).getTargetSdkVersion() + >= Build.VERSION_CODES.R); } @Test public void testSystemReadyPropogates() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); verify(mFeatureConfigMock).onSystemReady(); } @@ -186,22 +201,23 @@ public class AppsFilterTest { @Test public void testQueriesAction_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_UID); + pkg("com.some.package", new IntentFilter("TEST_ACTION")), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesProtectedAction_FilterDoesNotMatch() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); final Signature frameworkSignature = Mockito.mock(Signature.class); final PackageParser.SigningDetails frameworkSigningDetails = new PackageParser.SigningDetails(new Signature[]{frameworkSignature}, 1); @@ -211,164 +227,174 @@ public class AppsFilterTest { b -> b.setSigningDetails(frameworkSigningDetails)); appsFilter.onSystemReady(); - final int activityUid = DUMMY_TARGET_UID; + final int activityUid = DUMMY_TARGET_APPID; PackageSetting targetActivity = simulateAddPackage(appsFilter, pkg("com.target.activity", new IntentFilter("TEST_ACTION")), activityUid); - final int receiverUid = DUMMY_TARGET_UID + 1; + final int receiverUid = DUMMY_TARGET_APPID + 1; PackageSetting targetReceiver = simulateAddPackage(appsFilter, pkgWithReceiver("com.target.receiver", new IntentFilter("TEST_ACTION")), receiverUid); - final int callingUid = DUMMY_CALLING_UID; + final int callingUid = DUMMY_CALLING_APPID; PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.calling.action", new Intent("TEST_ACTION")), callingUid); - final int wildcardUid = DUMMY_CALLING_UID + 1; + final int wildcardUid = DUMMY_CALLING_APPID + 1; PackageSetting callingWildCard = simulateAddPackage(appsFilter, pkg("com.calling.wildcard", new Intent("*")), wildcardUid); - assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, 0)); - assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, 0)); + assertFalse(appsFilter.shouldFilterApplication(callingUid, calling, targetActivity, + SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(callingUid, calling, targetReceiver, + SYSTEM_USER)); assertFalse(appsFilter.shouldFilterApplication( - wildcardUid, callingWildCard, targetActivity, 0)); + wildcardUid, callingWildCard, targetActivity, SYSTEM_USER)); assertTrue(appsFilter.shouldFilterApplication( - wildcardUid, callingWildCard, targetReceiver, 0)); + wildcardUid, callingWildCard, targetReceiver, SYSTEM_USER)); } @Test public void testQueriesProvider_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID); + pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), - DUMMY_CALLING_UID); + DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesDifferentProvider_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_UID); + pkgWithProvider("com.some.package", "com.some.authority"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.other.authority"), - DUMMY_CALLING_UID); + DUMMY_CALLING_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesProviderWithSemiColon_FilterMatches() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkgWithProvider("com.some.package", "com.some.authority;com.some.other.authority"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkgQueriesProvider("com.some.other.package", "com.some.authority"), - DUMMY_CALLING_UID); + DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesAction_NoMatchingAction_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesAction_NoMatchingActionFilterLowSdk_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); - PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", - new Intent("TEST_ACTION")) - .setTargetSdkVersion(Build.VERSION_CODES.P), - DUMMY_CALLING_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); + ParsingPackage callingPkg = pkg("com.some.other.package", + new Intent("TEST_ACTION")) + .setTargetSdkVersion(Build.VERSION_CODES.P); + PackageSetting calling = simulateAddPackage(appsFilter, callingPkg, + DUMMY_CALLING_APPID); - when(mFeatureConfigMock.packageIsEnabled(calling.pkg)).thenReturn(false); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testNoQueries_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testForceQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_UID); + pkg("com.some.package").setForceQueryable(true), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testForceQueryableByDevice_SystemCaller_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, + false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID, + pkg("com.some.package"), DUMMY_TARGET_APPID, setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testSystemSignedTarget_DoesntFilter() throws CertificateException { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); appsFilter.onSystemReady(); final Signature frameworkSignature = Mockito.mock(Signature.class); @@ -382,62 +408,67 @@ public class AppsFilterTest { simulateAddPackage(appsFilter, pkg("android"), 1000, b -> b.setSigningDetails(frameworkSigningDetails)); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID, + DUMMY_TARGET_APPID, b -> b.setSigningDetails(frameworkSigningDetails) .setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID, + pkg("com.some.other.package"), DUMMY_CALLING_APPID, b -> b.setSigningDetails(otherSigningDetails)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testForceQueryableByDevice_NonSystemCaller_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{"com.some.package"}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{"com.some.package"}, + false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testSystemQueryable_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, true /* system force queryable */, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID, + pkg("com.some.package"), DUMMY_TARGET_APPID, setting -> setting.setPkgFlags(ApplicationInfo.FLAG_SYSTEM)); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testQueriesPackage_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_UID); + pkg("com.some.other.package", "com.some.package"), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test @@ -445,63 +476,67 @@ public class AppsFilterTest { when(mFeatureConfigMock.packageIsEnabled(any(AndroidPackage.class))) .thenReturn(false); final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage( - appsFilter, pkg("com.some.package"), DUMMY_TARGET_UID); + appsFilter, pkg("com.some.package"), DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage( - appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_UID); + appsFilter, pkg("com.some.other.package"), DUMMY_CALLING_APPID); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testSystemUid_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); - assertFalse(appsFilter.shouldFilterApplication(0, null, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(SYSTEM_USER, null, target, SYSTEM_USER)); assertFalse(appsFilter.shouldFilterApplication(Process.FIRST_APPLICATION_UID - 1, - null, target, 0)); + null, target, SYSTEM_USER)); } @Test public void testNonSystemUid_NoCallingSetting_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, - pkg("com.some.package"), DUMMY_TARGET_UID); + pkg("com.some.package"), DUMMY_TARGET_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, null, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, null, target, + SYSTEM_USER)); } @Test public void testNoTargetPackage_filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = new PackageSettingBuilder() + .setAppId(DUMMY_TARGET_APPID) .setName("com.some.package") .setCodePath("/") .setResourcePath("/") .setPVersionCode(1L) .build(); PackageSetting calling = simulateAddPackage(appsFilter, - pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_UID); + pkg("com.some.other.package", new Intent("TEST_ACTION")), DUMMY_CALLING_APPID); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test @@ -516,7 +551,11 @@ public class AppsFilterTest { .setOverlayTargetName("overlayableName"); ParsingPackage actor = pkg("com.some.package.actor"); - final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, + final AppsFilter appsFilter = new AppsFilter( + mStateProvider, + mFeatureConfigMock, + new String[]{}, + false, new OverlayReferenceMapper.Provider() { @Nullable @Override @@ -544,31 +583,34 @@ public class AppsFilterTest { simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); - PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); - PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); - PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_UID); + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID); + PackageSetting overlaySetting = + simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID); + PackageSetting actorSetting = simulateAddPackage(appsFilter, actor, DUMMY_ACTOR_APPID); // Actor can see both target and overlay - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, - targetSetting, 0)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_UID, actorSetting, - overlaySetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting, + targetSetting, SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSetting, + overlaySetting, SYSTEM_USER)); // But target/overlay can't see each other - assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, - overlaySetting, 0)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, - targetSetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting, + overlaySetting, SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting, + targetSetting, SYSTEM_USER)); // And can't see the actor - assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, targetSetting, - actorSetting, 0)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_UID, overlaySetting, - actorSetting, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, targetSetting, + actorSetting, SYSTEM_USER)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_OVERLAY_APPID, overlaySetting, + actorSetting, SYSTEM_USER)); } @Test public void testActsOnTargetOfOverlayThroughSharedUser() throws Exception { +// Debug.waitForDebugger(); + final String actorName = "overlay://test/actorName"; ParsingPackage target = pkg("com.some.package.target") @@ -580,7 +622,11 @@ public class AppsFilterTest { ParsingPackage actorOne = pkg("com.some.package.actor.one"); ParsingPackage actorTwo = pkg("com.some.package.actor.two"); - final AppsFilter appsFilter = new AppsFilter(mFeatureConfigMock, new String[]{}, false, + final AppsFilter appsFilter = new AppsFilter( + mStateProvider, + mFeatureConfigMock, + new String[]{}, + false, new OverlayReferenceMapper.Provider() { @Nullable @Override @@ -609,108 +655,114 @@ public class AppsFilterTest { simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); - PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_UID); - PackageSetting overlaySetting = simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_UID); - PackageSetting actorOneSetting = simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_UID); - PackageSetting actorTwoSetting = simulateAddPackage(appsFilter, actorTwo, - DUMMY_ACTOR_TWO_UID); - + PackageSetting targetSetting = simulateAddPackage(appsFilter, target, DUMMY_TARGET_APPID); SharedUserSetting actorSharedSetting = new SharedUserSetting("actorSharedUser", - actorOneSetting.pkgFlags, actorOneSetting.pkgPrivateFlags); - actorSharedSetting.addPackage(actorOneSetting); - actorSharedSetting.addPackage(actorTwoSetting); + targetSetting.pkgFlags, targetSetting.pkgPrivateFlags); + PackageSetting overlaySetting = + simulateAddPackage(appsFilter, overlay, DUMMY_OVERLAY_APPID); + simulateAddPackage(appsFilter, actorOne, DUMMY_ACTOR_APPID, + null /*settingBuilder*/, actorSharedSetting); + simulateAddPackage(appsFilter, actorTwo, DUMMY_ACTOR_APPID, + null /*settingBuilder*/, actorSharedSetting); + // actorTwo can see both target and overlay - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, - targetSetting, 0)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_TWO_UID, actorSharedSetting, - overlaySetting, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting, + targetSetting, SYSTEM_USER)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_ACTOR_APPID, actorSharedSetting, + overlaySetting, SYSTEM_USER)); } @Test public void testInitiatingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_UID, withInstallSource(target.name, null, null, false)); + DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, false)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testUninstalledInitiatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_UID, withInstallSource(target.name, null, null, true)); + DUMMY_CALLING_APPID, withInstallSource(target.name, null, null, true)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testOriginatingApp_Filters() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_UID, withInstallSource(null, target.name, null, false)); + DUMMY_CALLING_APPID, withInstallSource(null, target.name, null, false)); - assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertTrue(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testInstallingApp_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting calling = simulateAddPackage(appsFilter, pkg("com.some.other.package"), - DUMMY_CALLING_UID, withInstallSource(null, null, target.name, false)); + DUMMY_CALLING_APPID, withInstallSource(null, null, target.name, false)); - assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, calling, target, 0)); + assertFalse(appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, calling, target, + SYSTEM_USER)); } @Test public void testInstrumentation_DoesntFilter() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); PackageSetting target = simulateAddPackage(appsFilter, pkg("com.some.package"), - DUMMY_TARGET_UID); + DUMMY_TARGET_APPID); PackageSetting instrumentation = simulateAddPackage(appsFilter, pkgWithInstrumentation("com.some.other.package", "com.some.package"), - DUMMY_CALLING_UID); + DUMMY_CALLING_APPID); assertFalse( - appsFilter.shouldFilterApplication(DUMMY_CALLING_UID, instrumentation, target, 0)); + appsFilter.shouldFilterApplication(DUMMY_CALLING_APPID, instrumentation, target, + SYSTEM_USER)); assertFalse( - appsFilter.shouldFilterApplication(DUMMY_TARGET_UID, target, instrumentation, 0)); + appsFilter.shouldFilterApplication(DUMMY_TARGET_APPID, target, instrumentation, + SYSTEM_USER)); } @Test public void testWhoCanSee() throws Exception { final AppsFilter appsFilter = - new AppsFilter(mFeatureConfigMock, new String[]{}, false, null); + new AppsFilter(mStateProvider, mFeatureConfigMock, new String[]{}, false, null); simulateAddBasicAndroid(appsFilter); appsFilter.onSystemReady(); @@ -728,21 +780,25 @@ public class AppsFilterTest { queriesProviderAppId); final int[] systemFilter = - appsFilter.getVisibilityWhitelist(system, new int[]{0}, mExisting).get(0); + appsFilter.getVisibilityWhitelist(system, SINGLE_USER_ARRAY, mExisting) + .get(SYSTEM_USER); assertThat(toList(systemFilter), empty()); final int[] seesNothingFilter = - appsFilter.getVisibilityWhitelist(seesNothing, new int[]{0}, mExisting).get(0); + appsFilter.getVisibilityWhitelist(seesNothing, SINGLE_USER_ARRAY, mExisting) + .get(SYSTEM_USER); assertThat(toList(seesNothingFilter), contains(seesNothingAppId)); final int[] hasProviderFilter = - appsFilter.getVisibilityWhitelist(hasProvider, new int[]{0}, mExisting).get(0); + appsFilter.getVisibilityWhitelist(hasProvider, SINGLE_USER_ARRAY, mExisting) + .get(SYSTEM_USER); assertThat(toList(hasProviderFilter), contains(hasProviderAppId, queriesProviderAppId)); int[] queriesProviderFilter = - appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); + appsFilter.getVisibilityWhitelist(queriesProvider, SINGLE_USER_ARRAY, mExisting) + .get(SYSTEM_USER); assertThat(toList(queriesProviderFilter), contains(queriesProviderAppId)); @@ -751,7 +807,8 @@ public class AppsFilterTest { // ensure implicit access is included in the filter queriesProviderFilter = - appsFilter.getVisibilityWhitelist(queriesProvider, new int[]{0}, mExisting).get(0); + appsFilter.getVisibilityWhitelist(queriesProvider, SINGLE_USER_ARRAY, mExisting) + .get(SYSTEM_USER); assertThat(toList(queriesProviderFilter), contains(hasProviderAppId, queriesProviderAppId)); } @@ -779,11 +836,17 @@ public class AppsFilterTest { private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId) { - return simulateAddPackage(filter, newPkgBuilder, appId, null); + return simulateAddPackage(filter, newPkgBuilder, appId, null /*settingBuilder*/); } private PackageSetting simulateAddPackage(AppsFilter filter, ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action) { + return simulateAddPackage(filter, newPkgBuilder, appId, action, null /*sharedUserSetting*/); + } + + private PackageSetting simulateAddPackage(AppsFilter filter, + ParsingPackage newPkgBuilder, int appId, @Nullable WithSettingBuilder action, + @Nullable SharedUserSetting sharedUserSetting) { AndroidPackage newPkg = ((ParsedPackage) newPkgBuilder.hideAsParsed()).hideAsFinal(); final PackageSettingBuilder settingBuilder = new PackageSettingBuilder() @@ -795,8 +858,12 @@ public class AppsFilterTest { .setPVersionCode(1L); final PackageSetting setting = (action == null ? settingBuilder : action.withBuilder(settingBuilder)).build(); - filter.addPackage(setting, mExisting); mExisting.put(newPkg.getPackageName(), setting); + if (sharedUserSetting != null) { + sharedUserSetting.addPackage(setting); + setting.sharedUser = sharedUserSetting; + } + filter.addPackage(setting); return setting; } @@ -809,4 +876,3 @@ public class AppsFilterTest { return setting -> setting.setInstallSource(installSource); } } - diff --git a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java index c55df512bd1e..87979fb00021 100644 --- a/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/UserSystemPackageInstallerTest.java @@ -366,9 +366,75 @@ public class UserSystemPackageInstallerTest { for (PackageInfo p : packageInfos) { actualPackages.add(p.packageName); } + + // Add auto-generated RRO package to expectedPackages since they are not (supposed to be) + // in the whitelist but they should be installed. + for (PackageInfo p : packageInfos) { + if (p.isOverlayPackage() + && UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName) + && expectedPackages.contains(p.overlayTarget)) { + expectedPackages.add(p.packageName); + } + } checkPackageDifferences(expectedPackages, actualPackages); } + @Test + public void testAutoGeneratedRROMatchesSuffix() { + final List<PackageInfo> packageInfos = mContext.getPackageManager() + .getInstalledPackages(PackageManager.GET_UNINSTALLED_PACKAGES); + + Log.v(TAG, "Found total packages: " + packageInfos.size()); + + for (PackageInfo p : packageInfos) { + if (p.packageName.contains(".auto_generated_rro_")) { + assertTrue("Auto-generated RRO package name does not match the suffix: " + + p.packageName, + UserSystemPackageInstaller.hasAutoGeneratedRROSuffix(p.packageName)); + } + } + } + + /** + * Test that overlay package not in whitelist should be installed for all user at Explicit mode. + */ + @Test + public void testInstallOverlayPackagesExplicitMode() { + setUserTypePackageWhitelistMode(USER_TYPE_PACKAGE_WHITELIST_MODE_ENFORCE); + + final String[] userTypes = new String[]{"type"}; + final long maskOfType = 0b0001L; + + final String packageName1 = "whitelistedPkg"; + final String packageName2 = "nonWhitelistedPkg"; + final String overlayName1 = String.format("%s.auto_generated_rro_product__", packageName1); + final String overlayName2 = String.format("%s.auto_generated_rro_product__", packageName2); + + final AndroidPackage overlayPackage1 = ((ParsedPackage) PackageImpl.forTesting(overlayName1) + .setOverlay(true) + .setOverlayTarget(packageName1) + .hideAsParsed()) + .hideAsFinal(); + + final AndroidPackage overlayPackage2 = ((ParsedPackage) PackageImpl.forTesting(overlayName2) + .setOverlay(true) + .setOverlayTarget(packageName2) + .hideAsParsed()) + .hideAsFinal(); + + final ArrayMap<String, Long> userTypeWhitelist = new ArrayMap<>(); + userTypeWhitelist.put(packageName1, maskOfType); + + final Set<String> userWhitelist = new ArraySet<>(); + userWhitelist.add(packageName1); + + boolean implicit = false; + assertTrue("Overlay for package1 should be installed", UserSystemPackageInstaller + .shouldInstallPackage(overlayPackage1, userTypeWhitelist, userWhitelist, implicit)); + assertFalse("Overlay for package2 should not be installed", UserSystemPackageInstaller + .shouldInstallPackage(overlayPackage2, userTypeWhitelist, userWhitelist, implicit)); + } + /** Asserts that actual is a subset of expected. */ private void checkPackageDifferences(Set<String> expected, Set<String> actual) { final Set<String> uniqueToExpected = new ArraySet<>(expected); diff --git a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java index a13823441665..45574fc29ddc 100644 --- a/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java +++ b/services/tests/servicestests/src/com/android/server/power/PreRebootLoggerTest.java @@ -23,6 +23,9 @@ import static com.google.common.truth.Truth.assertThat; import static org.mockito.Mockito.when; import android.content.Context; +import android.content.pm.PackageInstaller; +import android.content.pm.PackageInstaller.SessionInfo; +import android.content.pm.PackageManager; import android.provider.Settings; import android.test.mock.MockContentResolver; @@ -36,12 +39,15 @@ import com.google.common.io.Files; import org.junit.AfterClass; import org.junit.Before; import org.junit.BeforeClass; +import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; -import org.mockito.MockitoAnnotations; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; import java.io.File; +import java.util.List; /** * Tests for {@link PreRebootLogger} @@ -49,7 +55,11 @@ import java.io.File; @SmallTest @RunWith(AndroidJUnit4.class) public class PreRebootLoggerTest { + @Rule public final MockitoRule mocks = MockitoJUnit.rule(); @Mock Context mContext; + @Mock PackageManager mPackageManager; + @Mock PackageInstaller mPackageInstaller; + @Mock List<SessionInfo> mSessions; private MockContentResolver mContentResolver; private File mDumpDir; @@ -64,29 +74,53 @@ public class PreRebootLoggerTest { } @Before - public void setup() { - MockitoAnnotations.initMocks(this); + public void enableAdbConfig() { mContentResolver = new MockContentResolver(getInstrumentation().getTargetContext()); when(mContext.getContentResolver()).thenReturn(mContentResolver); mContentResolver.addProvider(Settings.AUTHORITY, new FakeSettingsProvider()); + Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1); + } + + @Before + public void prepareActiveStagedSessions() { + when(mContext.getPackageManager()).thenReturn(mPackageManager); + when(mPackageManager.getPackageInstaller()).thenReturn(mPackageInstaller); + when(mPackageInstaller.getActiveStagedSessions()).thenReturn(mSessions); + when(mSessions.isEmpty()).thenReturn(false); + } + @Before + public void setupDumpDir() { mDumpDir = Files.createTempDir(); - mDumpDir.mkdir(); mDumpDir.deleteOnExit(); } @Test - public void log_adbEnabled_dumpsInformationProperly() { - Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1); - + public void log_dumpsInformationProperly() { PreRebootLogger.log(mContext, mDumpDir); assertThat(mDumpDir.list()).asList().containsExactly("system", "package", "rollback"); } @Test + public void dump_exceedTimeout_wontBlockCurrentThread() { + PreRebootLogger.dump(mDumpDir, 1 /* maxWaitTime */); + + assertThat(mDumpDir.listFiles()).asList().containsNoneOf("system", "package", "rollback"); + } + + @Test + public void log_noActiveStagedSession_wipesDumpedInformation() { + PreRebootLogger.log(mContext, mDumpDir); + when(mSessions.isEmpty()).thenReturn(true); + + PreRebootLogger.log(mContext, mDumpDir); + + assertThat(mDumpDir.listFiles()).isEmpty(); + } + + @Test public void log_adbDisabled_wipesDumpedInformation() { - Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 1); PreRebootLogger.log(mContext, mDumpDir); Settings.Global.putInt(mContentResolver, Settings.Global.ADB_ENABLED, 0); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java index de9b77c68336..ae22b2be0c69 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -5455,25 +5455,49 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { } @Test - public void testCancelNotificationsFromListener_ignoresBubbles() throws Exception { - final NotificationRecord nrNormal = generateNotificationRecord(mTestNotificationChannel); - final NotificationRecord nrBubble = generateNotificationRecord(mTestNotificationChannel); - nrBubble.getSbn().getNotification().flags |= FLAG_BUBBLE; + public void testCancelNotificationsFromListener_cancelsNonBubble() throws Exception { + // Add non-bubble notif + final NotificationRecord nr = generateNotificationRecord(mTestNotificationChannel); + mService.addNotification(nr); - mService.addNotification(nrNormal); - mService.addNotification(nrBubble); + // Cancel via listener + String[] keys = {nr.getSbn().getKey()}; + mService.getBinderService().cancelNotificationsFromListener(null, keys); + waitForIdle(); + + // Notif not active anymore + StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); + assertEquals(0, notifs.length); + assertEquals(0, mService.getNotificationRecordCount()); + // Cancel event is logged + assertEquals(1, mNotificationRecordLogger.numCalls()); + assertEquals(NotificationRecordLogger.NotificationCancelledEvent + .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0)); + } + + @Test + public void testCancelNotificationsFromListener_suppressesBubble() throws Exception { + // Add bubble notif + setUpPrefsForBubbles(PKG, mUid, + true /* global */, + BUBBLE_PREFERENCE_ALL /* app */, + true /* channel */); + NotificationRecord nr = generateMessageBubbleNotifRecord(mTestNotificationChannel, "tag"); - String[] keys = {nrNormal.getSbn().getKey(), nrBubble.getSbn().getKey()}; + mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(), + nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); + waitForIdle(); + + // Cancel via listener + String[] keys = {nr.getSbn().getKey()}; mService.getBinderService().cancelNotificationsFromListener(null, keys); waitForIdle(); + // Bubble notif active and suppressed StatusBarNotification[] notifs = mBinderService.getActiveNotifications(PKG); assertEquals(1, notifs.length); assertEquals(1, mService.getNotificationRecordCount()); - - assertEquals(1, mNotificationRecordLogger.numCalls()); - assertEquals(NotificationRecordLogger.NotificationCancelledEvent - .NOTIFICATION_CANCEL_LISTENER_CANCEL, mNotificationRecordLogger.event(0)); + assertTrue(notifs[0].getNotification().getBubbleMetadata().isNotificationSuppressed()); } @Test diff --git a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java index f4f64d779d30..89adc724f600 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/WrappedSysUiStatsEvent.java @@ -88,11 +88,21 @@ public class WrappedSysUiStatsEvent { return index < mValues.size() ? mValues.get(index) : null; } - /** useful to make assertTrue() statemetns more readable. */ + /** useful to make assertTrue() statements more readable. */ public boolean getBoolean(int index) { return (Boolean) mValues.get(index); } + /** useful to make assertTrue() statements more readable. */ + public int getInt(int index) { + return (Integer) mValues.get(index); + } + + /** useful to make assertTrue() statements more readable. */ + public String getString(int index) { + return (String) mValues.get(index); + } + private void addValue(Object value) { mLastIndex = mValues.size(); mValues.add(value); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java index f7b435ed937b..013a99433041 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java @@ -101,11 +101,39 @@ public class ZenModeConfigTest extends UiServiceTestCase { Policy expectedPolicy = new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders, suppressedVisualEffects, 0, priorityConversationsSenders); - assertEquals(expectedPolicy, config.toNotificationPolicy(zenPolicy)); } @Test + public void testZenConfigToZenPolicy() { + ZenPolicy expected = new ZenPolicy.Builder() + .allowAlarms(true) + .allowReminders(true) + .allowEvents(true) + .showLights(false) + .showBadges(false) + .showInAmbientDisplay(false) + .build(); + + ZenModeConfig config = getMutedAllConfig(); + config.allowAlarms = true; + config.allowReminders = true; + config.allowEvents = true; + config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_BADGE; + config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS; + config.suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_AMBIENT; + ZenPolicy actual = config.toZenPolicy(); + + assertEquals(expected.getVisualEffectBadge(), actual.getVisualEffectBadge()); + assertEquals(expected.getPriorityCategoryAlarms(), actual.getPriorityCategoryAlarms()); + assertEquals(expected.getPriorityCategoryReminders(), + actual.getPriorityCategoryReminders()); + assertEquals(expected.getPriorityCategoryEvents(), actual.getPriorityCategoryEvents()); + assertEquals(expected.getVisualEffectLights(), actual.getVisualEffectLights()); + assertEquals(expected.getVisualEffectAmbient(), actual.getVisualEffectAmbient()); + } + + @Test public void testPriorityOnlyMutingAll() { ZenModeConfig config = getMutedAllConfig(); assertTrue(ZenModeConfig.areAllPriorityOnlyRingerSoundsMuted(config)); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java index 108af892c7dd..3c7206fee9d1 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java @@ -27,16 +27,25 @@ import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REMINDERS import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_REPEAT_CALLERS; import static android.app.NotificationManager.Policy.PRIORITY_CATEGORY_SYSTEM; import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_ANY; -import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_CONTACTS; import static android.app.NotificationManager.Policy.PRIORITY_SENDERS_STARRED; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_BADGE; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_FULL_SCREEN_INTENT; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS; import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK; +import static android.provider.Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + +import static com.android.internal.util.FrameworkStatsLog.ANNOTATION_ID_IS_UID; +import static com.android.internal.util.FrameworkStatsLog.DND_MODE_RULE; +import static com.android.os.AtomsProto.DNDModeProto.CHANNELS_BYPASSING_FIELD_NUMBER; +import static com.android.os.AtomsProto.DNDModeProto.ENABLED_FIELD_NUMBER; +import static com.android.os.AtomsProto.DNDModeProto.ID_FIELD_NUMBER; +import static com.android.os.AtomsProto.DNDModeProto.UID_FIELD_NUMBER; +import static com.android.os.AtomsProto.DNDModeProto.ZEN_MODE_FIELD_NUMBER; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertFalse; import static junit.framework.TestCase.assertTrue; +import static junit.framework.TestCase.fail; import static org.junit.Assert.assertNotEquals; import static org.mockito.ArgumentMatchers.any; @@ -70,10 +79,12 @@ import android.media.AudioManagerInternal; import android.media.AudioSystem; import android.media.VolumePolicy; import android.net.Uri; +import android.os.Process; import android.os.UserHandle; import android.provider.Settings; import android.provider.Settings.Global; import android.service.notification.Condition; +import android.service.notification.DNDModeProto; import android.service.notification.ZenModeConfig; import android.service.notification.ZenModeConfig.ScheduleInfo; import android.service.notification.ZenPolicy; @@ -82,6 +93,7 @@ import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.ArrayMap; import android.util.Log; +import android.util.StatsEvent; import android.util.Xml; import com.android.internal.R; @@ -106,6 +118,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.Reader; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; import java.util.Objects; @SmallTest @@ -115,6 +130,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private static final String EVENTS_DEFAULT_RULE_ID = "EVENTS_DEFAULT_RULE"; private static final String SCHEDULE_DEFAULT_RULE_ID = "EVERY_NIGHT_DEFAULT_RULE"; + private static final int ZEN_MODE_FOR_TESTING = 99; ConditionProviders mConditionProviders; @Mock NotificationManager mNotificationManager; @@ -124,6 +140,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { private Context mContext; private ContentResolver mContentResolver; @Mock AppOpsManager mAppOps; + private WrappedSysUiStatsEvent.WrappedBuilderFactory mStatsEventBuilderFactory; @Before public void setUp() { @@ -140,6 +157,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { Log.d("ZenModeHelperTest", "Couldn't mock default zen mode config xml file err=" + e.toString()); } + mStatsEventBuilderFactory = new WrappedSysUiStatsEvent.WrappedBuilderFactory(); when(mContext.getSystemService(AppOpsManager.class)).thenReturn(mAppOps); when(mContext.getSystemService(NotificationManager.class)).thenReturn(mNotificationManager); @@ -147,7 +165,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { AppGlobals.getPackageManager()); mConditionProviders.addSystemProvider(new CountdownConditionProvider()); mZenModeHelperSpy = spy(new ZenModeHelper(mContext, mTestableLooper.getLooper(), - mConditionProviders)); + mConditionProviders, mStatsEventBuilderFactory)); } private XmlResourceParser getDefaultConfigParser() throws IOException, XmlPullParserException { @@ -212,6 +230,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { } private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules() { + return getCustomAutomaticRules(ZEN_MODE_IMPORTANT_INTERRUPTIONS); + } + + private ArrayMap<String, ZenModeConfig.ZenRule> getCustomAutomaticRules(int zenMode) { ArrayMap<String, ZenModeConfig.ZenRule> automaticRules = new ArrayMap<>(); ZenModeConfig.ZenRule customRule = new ZenModeConfig.ZenRule(); final ScheduleInfo customRuleInfo = new ScheduleInfo(); @@ -219,10 +241,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { customRule.creationTime = 0; customRule.id = "customRule"; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = zenMode; customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo); customRule.configurationActivity = - new ComponentName("android", "ScheduleConditionProvider"); + new ComponentName("not.android", "ScheduleConditionProvider"); customRule.pkg = customRule.configurationActivity.getPackageName(); automaticRules.put("customRule", customRule); return automaticRules; @@ -244,7 +266,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenOn_NotificationApplied() { - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; // The most permissive policy mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES @@ -267,7 +289,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenOn_StarredCallers_CallTypesBlocked() { - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; // The most permissive policy mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES @@ -287,7 +309,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenOn_AllCallers_CallTypesAllowed() { - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; // The most permissive policy mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA | PRIORITY_CATEGORY_MESSAGES @@ -307,7 +329,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenOn_AllowAlarmsMedia_NoAlarmMediaMuteApplied() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(Policy.PRIORITY_CATEGORY_ALARMS | PRIORITY_CATEGORY_MEDIA, 0, 0, 0, 0, 0); @@ -320,7 +342,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testZenOn_DisallowAlarmsMedia_AlarmMediaMuteApplied() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); verify(mZenModeHelperSpy, atLeastOnce()).applyRestrictions(true, true, @@ -406,7 +428,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { public void testZenAllCannotBypass() { // Only audio attributes with SUPPRESIBLE_NEVER can bypass // with special case USAGE_ASSISTANCE_SONIFICATION - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); @@ -428,7 +450,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testApplyRestrictions_whitelist_priorityOnlyMode() { mZenModeHelperSpy.setPriorityOnlyDndExemptPackages(new String[] {PKG_O}); - mZenModeHelperSpy.mZenMode = Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); mZenModeHelperSpy.applyRestrictions(); @@ -479,7 +501,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0); mZenModeHelperSpy.mIsBootComplete = true; mZenModeHelperSpy.mConsolidatedPolicy = new Policy(0, 0, 0, 0, 0, 0); - mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); verify(mZenModeHelperSpy, times(1)).createZenUpgradeNotification(); verify(mNotificationManager, times(1)).notify(eq(ZenModeHelper.TAG), @@ -494,7 +516,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0); Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 0); mZenModeHelperSpy.mIsBootComplete = true; - mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); verify(mZenModeHelperSpy, never()).createZenUpgradeNotification(); verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG), @@ -507,7 +529,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { Settings.Secure.putInt(mContentResolver, Settings.Secure.SHOW_ZEN_UPGRADE_NOTIFICATION, 0); Settings.Secure.putInt(mContentResolver, Settings.Secure.ZEN_SETTINGS_UPDATED, 1); mZenModeHelperSpy.mIsBootComplete = true; - mZenModeHelperSpy.setZenModeSetting(Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS); + mZenModeHelperSpy.setZenModeSetting(ZEN_MODE_IMPORTANT_INTERRUPTIONS); verify(mZenModeHelperSpy, never()).createZenUpgradeNotification(); verify(mNotificationManager, never()).notify(eq(ZenModeHelper.TAG), @@ -524,7 +546,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); // Set zen to priority-only with all notification sounds muted (so ringer will be muted) - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowReminders = false; mZenModeHelperSpy.mConfig.allowCalls = false; mZenModeHelperSpy.mConfig.allowMessages = false; @@ -568,7 +590,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // ringtone, notification and system streams are affected by ringer mode mZenModeHelperSpy.mConfig.allowAlarms = true; mZenModeHelperSpy.mConfig.allowReminders = true; - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; ZenModeHelper.RingerModeDelegate ringerModeDelegateRingerMuted = mZenModeHelperSpy.new RingerModeDelegate(); @@ -615,7 +637,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowReminders = true; // 2. apply priority only zen - verify ringer is normal @@ -640,7 +662,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // 1. Current ringer is silent when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowReminders = true; // 2. apply priority only zen - verify ringer is silent @@ -666,7 +688,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // 1. Current ringer is normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_NORMAL); // Set zen to priority-only with all notification sounds muted (so ringer will be muted) - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowReminders = true; // 2. apply priority only zen - verify zen will still be normal @@ -728,7 +750,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // apply zen off multiple times - verify ringer is not set to normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_SILENT); - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer mZenModeHelperSpy.evaluateZenMode("test", true); @@ -756,7 +778,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { // apply zen off multiple times - verify ringer is not set to normal when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE); - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; for (int i = 0; i < 3; i++) { // if zen doesn't change, zen should not reapply itself to the ringer mZenModeHelperSpy.evaluateZenMode("test", true); @@ -768,7 +790,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testParcelConfig() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; mZenModeHelperSpy.mConfig.allowMedia = false; mZenModeHelperSpy.mConfig.allowSystem = false; @@ -792,7 +814,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testWriteXml() throws Exception { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; mZenModeHelperSpy.mConfig.allowMedia = false; mZenModeHelperSpy.mConfig.allowSystem = false; @@ -806,7 +828,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { mZenModeHelperSpy.mConfig.suppressedVisualEffects = SUPPRESSED_EFFECT_BADGE; mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); mZenModeHelperSpy.mConfig.manualRule.zenMode = - Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.manualRule.component = new ComponentName("a", "a"); mZenModeHelperSpy.mConfig.manualRule.pkg = "a"; mZenModeHelperSpy.mConfig.manualRule.enabled = true; @@ -822,6 +844,102 @@ public class ZenModeHelperTest extends UiServiceTestCase { } @Test + public void testProto() { + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); + + int n = mZenModeHelperSpy.mConfig.automaticRules.size(); + List<String> ids = new ArrayList<>(n); + for (ZenModeConfig.ZenRule rule : mZenModeHelperSpy.mConfig.automaticRules.values()) { + ids.add(rule.id); + } + ids.add(""); + + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelperSpy.pullRules(events); + assertEquals(n + 1, events.size()); + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == DND_MODE_RULE) { + if (builder.getInt(ZEN_MODE_FIELD_NUMBER) == DNDModeProto.ROOT_CONFIG) { + assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER)); + assertFalse(builder.getBoolean(CHANNELS_BYPASSING_FIELD_NUMBER)); + } + assertEquals(Process.SYSTEM_UID, builder.getInt(UID_FIELD_NUMBER)); + assertTrue(builder.getBooleanAnnotation(UID_FIELD_NUMBER, ANNOTATION_ID_IS_UID)); + String name = (String) builder.getValue(ID_FIELD_NUMBER); + assertTrue("unexpected rule id", ids.contains(name)); + ids.remove(name); + } else { + fail("unexpected atom id: " + builder.getAtomId()); + } + } + assertEquals("extra rule in output", 0, ids.size()); + } + + @Test + public void testProtoWithAutoRule() throws Exception { + setupZenConfig(); + // one enabled automatic rule + mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(ZEN_MODE_FOR_TESTING); + + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelperSpy.pullRules(events); + + boolean foundCustomEvent = false; + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == DND_MODE_RULE) { + if (ZEN_MODE_FOR_TESTING == builder.getInt(ZEN_MODE_FIELD_NUMBER)) { + foundCustomEvent = true; + assertEquals(0, builder.getInt(UID_FIELD_NUMBER)); + assertTrue(builder.getBoolean(ENABLED_FIELD_NUMBER)); + } + } else { + fail("unexpected atom id: " + builder.getAtomId()); + } + } + assertTrue("couldn't find custom rule", foundCustomEvent); + } + + @Test + public void testProtoRedactsIds() throws Exception { + setupZenConfig(); + // one enabled automatic rule + mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); + + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelperSpy.pullRules(events); + + boolean foundCustomEvent = false; + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == DND_MODE_RULE + && "customRule".equals(builder.getString(ID_FIELD_NUMBER))) { + fail("non-default IDs should be redacted"); + } + } + } + + @Test + public void testProtoWithManualRule() throws Exception { + setupZenConfig(); + mZenModeHelperSpy.mConfig.automaticRules = getCustomAutomaticRules(); + mZenModeHelperSpy.mConfig.manualRule = new ZenModeConfig.ZenRule(); + mZenModeHelperSpy.mConfig.manualRule.enabled = true; + mZenModeHelperSpy.mConfig.manualRule.enabler = "com.enabler"; + + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelperSpy.pullRules(events); + + boolean foundManualRule = false; + for (WrappedSysUiStatsEvent.WrappedBuilder builder : mStatsEventBuilderFactory.builders) { + if (builder.getAtomId() == DND_MODE_RULE + && ZenModeConfig.MANUAL_RULE_ID.equals(builder.getString(ID_FIELD_NUMBER))) { + assertEquals(0, builder.getInt(UID_FIELD_NUMBER)); + foundManualRule = true; + } + } + assertTrue("couldn't find manual rule", foundManualRule); } + + @Test public void testWriteXml_onlyBackupsTargetUser() throws Exception { // Setup configs for user 10 and 11. setupZenConfig(); @@ -906,7 +1024,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { customRule.creationTime = 0; customRule.id = "customRule"; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo); customRule.configurationActivity = new ComponentName("android", "ScheduleConditionProvider"); @@ -951,7 +1069,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { customRule.creationTime = 0; customRule.id = ruleId; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo); customRule.configurationActivity = new ComponentName("android", "ScheduleConditionProvider"); @@ -986,7 +1104,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo weeknights = new ScheduleInfo(); customRule.enabled = true; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); enabledAutoRule.put("customRule", customRule); @@ -1151,7 +1269,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo weeknights = new ScheduleInfo(); customRule.enabled = false; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(weeknights); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); disabledAutoRule.put("customRule", customRule); @@ -1187,7 +1305,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo customRuleInfo = new ScheduleInfo(); customRule.enabled = false; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); customRule.zenPolicy = new ZenPolicy.Builder() @@ -1200,7 +1318,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo(); defaultScheduleRule.enabled = false; defaultScheduleRule.name = "Default Schedule Rule"; - defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId( defaultScheduleRuleInfo); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); @@ -1238,7 +1356,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo customRuleInfo = new ScheduleInfo(); customRule.enabled = false; customRule.name = "Custom Rule"; - customRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customRule.conditionId = ZenModeConfig.toScheduleConditionId(customRuleInfo); customRule.component = new ComponentName("android", "ScheduleConditionProvider"); customRule.zenPolicy = new ZenPolicy.Builder() @@ -1251,7 +1369,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo defaultScheduleRuleInfo = new ScheduleInfo(); defaultScheduleRule.enabled = false; defaultScheduleRule.name = "Default Schedule Rule"; - defaultScheduleRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + defaultScheduleRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; defaultScheduleRule.conditionId = ZenModeConfig.toScheduleConditionId( defaultScheduleRuleInfo); defaultScheduleRule.id = ZenModeConfig.EVERY_NIGHT_DEFAULT_RULE_ID; @@ -1265,7 +1383,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { final ScheduleInfo defaultEventRuleInfo = new ScheduleInfo(); defaultEventRule.enabled = false; defaultEventRule.name = "Default Event Rule"; - defaultEventRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + defaultEventRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; defaultEventRule.conditionId = ZenModeConfig.toScheduleConditionId( defaultEventRuleInfo); defaultEventRule.id = ZenModeConfig.EVENTS_DEFAULT_RULE_ID; @@ -1295,6 +1413,10 @@ public class ZenModeHelperTest extends UiServiceTestCase { assertTrue(rules.containsKey("customRule")); setupZenConfigMaintained(); + + List<StatsEvent> events = new LinkedList<>(); + mZenModeHelperSpy.pullRules(events); + assertEquals(4, events.size()); } @Test @@ -1323,10 +1445,12 @@ public class ZenModeHelperTest extends UiServiceTestCase { @Test public void testEmptyDefaultRulesMap() { + List<StatsEvent> events = new LinkedList<>(); ZenModeConfig config = new ZenModeConfig(); config.automaticRules = new ArrayMap<>(); mZenModeHelperSpy.mConfig = config; mZenModeHelperSpy.updateDefaultZenRules(); // shouldn't throw null pointer + mZenModeHelperSpy.pullRules(events); // shouldn't throw null pointer } @Test @@ -1342,7 +1466,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { updatedDefaultRule.creationTime = 0; updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; updatedDefaultRule.name = "Schedule Default Rule"; - updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); @@ -1368,7 +1492,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { updatedDefaultRule.creationTime = 0; updatedDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; updatedDefaultRule.name = "Schedule Default Rule"; - updatedDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + updatedDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; updatedDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); updatedDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); @@ -1395,7 +1519,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { customDefaultRule.creationTime = 0; customDefaultRule.id = SCHEDULE_DEFAULT_RULE_ID; customDefaultRule.name = "Schedule Default Rule"; - customDefaultRule.zenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + customDefaultRule.zenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; customDefaultRule.conditionId = ZenModeConfig.toScheduleConditionId(new ScheduleInfo()); customDefaultRule.component = new ComponentName("android", "ScheduleConditionProvider"); @@ -1433,7 +1557,7 @@ public class ZenModeHelperTest extends UiServiceTestCase { } private void setupZenConfig() { - mZenModeHelperSpy.mZenMode = Settings.Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS; + mZenModeHelperSpy.mZenMode = ZEN_MODE_IMPORTANT_INTERRUPTIONS; mZenModeHelperSpy.mConfig.allowAlarms = false; mZenModeHelperSpy.mConfig.allowMedia = false; mZenModeHelperSpy.mConfig.allowSystem = false; diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java index a0ee417c8b47..b16ca8b92848 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java @@ -17,14 +17,18 @@ package com.android.server.notification; import static junit.framework.Assert.assertEquals; +import static junit.framework.Assert.fail; import android.service.notification.ZenPolicy; +import android.service.notification.nano.DNDPolicyProto; import android.test.suitebuilder.annotation.SmallTest; import androidx.test.runner.AndroidJUnit4; import com.android.server.UiServiceTestCase; +import com.google.protobuf.nano.InvalidProtocolBufferNanoException; + import org.junit.Test; import org.junit.runner.RunWith; @@ -190,6 +194,7 @@ public class ZenPolicyTest extends UiServiceTestCase { ZenPolicy policy = builder.build(); assertEquals(ZenPolicy.STATE_UNSET, policy.getPriorityCategoryMessages()); assertEquals(ZenPolicy.PEOPLE_TYPE_UNSET, policy.getPriorityMessageSenders()); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -201,6 +206,7 @@ public class ZenPolicyTest extends UiServiceTestCase { ZenPolicy policy = builder.build(); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls()); assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders()); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -210,6 +216,7 @@ public class ZenPolicyTest extends UiServiceTestCase { ZenPolicy policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, -1); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -221,12 +228,14 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryReminders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowReminders(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REMINDERS); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryReminders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -238,12 +247,14 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryEvents()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowEvents(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_EVENTS); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryEvents()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -256,6 +267,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages()); assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityMessageSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowMessages(ZenPolicy.PEOPLE_TYPE_CONTACTS); policy = builder.build(); @@ -263,6 +275,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages()); assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityMessageSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED); policy = builder.build(); @@ -270,6 +283,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMessages()); assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityMessageSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowMessages(ZenPolicy.PEOPLE_TYPE_NONE); policy = builder.build(); @@ -277,11 +291,13 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMessages()); assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityMessageSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowMessages(ZenPolicy.PEOPLE_TYPE_UNSET); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, -1); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -294,6 +310,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls()); assertEquals(ZenPolicy.PEOPLE_TYPE_ANYONE, policy.getPriorityCallSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS); policy = builder.build(); @@ -301,6 +318,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls()); assertEquals(ZenPolicy.PEOPLE_TYPE_CONTACTS, policy.getPriorityCallSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowCalls(ZenPolicy.PEOPLE_TYPE_STARRED); policy = builder.build(); @@ -308,6 +326,7 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryCalls()); assertEquals(ZenPolicy.PEOPLE_TYPE_STARRED, policy.getPriorityCallSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowCalls(ZenPolicy.PEOPLE_TYPE_NONE); policy = builder.build(); @@ -315,11 +334,13 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryCalls()); assertEquals(ZenPolicy.PEOPLE_TYPE_NONE, policy.getPriorityCallSenders()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowCalls(ZenPolicy.PEOPLE_TYPE_UNSET); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, -1); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -331,12 +352,14 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryRepeatCallers()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowRepeatCallers(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_REPEAT_CALLERS); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryRepeatCallers()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -348,12 +371,14 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryAlarms()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowAlarms(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_ALARMS); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryAlarms()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -365,12 +390,14 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategoryMedia()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowMedia(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_MEDIA); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategoryMedia()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); } @Test @@ -382,12 +409,119 @@ public class ZenPolicyTest extends UiServiceTestCase { assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM); assertEquals(ZenPolicy.STATE_ALLOW, policy.getPriorityCategorySystem()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); builder.allowSystem(false); policy = builder.build(); assertAllPriorityCategoriesUnsetExcept(policy, ZenPolicy.PRIORITY_CATEGORY_SYSTEM); assertEquals(ZenPolicy.STATE_DISALLOW, policy.getPriorityCategorySystem()); assertAllVisualEffectsUnsetExcept(policy, -1); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowFullScreenIntent() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showFullScreenIntent(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT); + assertProtoMatches(policy, policy.toProto()); + + builder.showFullScreenIntent(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_FULL_SCREEN_INTENT); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowLights() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showLights(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS); + assertProtoMatches(policy, policy.toProto()); + + builder.showLights(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_LIGHTS); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowPeeking() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showPeeking(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK); + assertProtoMatches(policy, policy.toProto()); + + builder.showPeeking(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_PEEK); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowStatusBarIcons() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showStatusBarIcons(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR); + assertProtoMatches(policy, policy.toProto()); + + builder.showStatusBarIcons(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_STATUS_BAR); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowBadges() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showBadges(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE); + assertProtoMatches(policy, policy.toProto()); + + builder.showBadges(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_BADGE); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowInAmbientDisplay() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showInAmbientDisplay(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT); + assertProtoMatches(policy, policy.toProto()); + + builder.showInAmbientDisplay(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_AMBIENT); + assertProtoMatches(policy, policy.toProto()); + } + + @Test + public void tesShowInNotificationList() { + ZenPolicy.Builder builder = new ZenPolicy.Builder(); + + builder.showInNotificationList(true); + ZenPolicy policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST); + assertProtoMatches(policy, policy.toProto()); + + builder.showInNotificationList(false); + policy = builder.build(); + assertAllVisualEffectsUnsetExcept(policy, ZenPolicy.VISUAL_EFFECT_NOTIFICATION_LIST); + assertProtoMatches(policy, policy.toProto()); } private void assertAllPriorityCategoriesUnsetExcept(ZenPolicy policy, int except) { @@ -453,4 +587,35 @@ public class ZenPolicyTest extends UiServiceTestCase { assertEquals(ZenPolicy.STATE_UNSET, policy.getVisualEffectNotificationList()); } } + + private void assertProtoMatches(ZenPolicy policy, byte[] bytes) { + try { + DNDPolicyProto proto = DNDPolicyProto.parseFrom(bytes); + + assertEquals(policy.getPriorityCategoryCalls(), proto.calls); + assertEquals(policy.getPriorityCategoryRepeatCallers(), proto.repeatCallers); + assertEquals(policy.getPriorityCategoryMessages(), proto.messages); + assertEquals(policy.getPriorityCategoryConversations(), proto.conversations); + assertEquals(policy.getPriorityCategoryReminders(), proto.reminders); + assertEquals(policy.getPriorityCategoryEvents(), proto.events); + assertEquals(policy.getPriorityCategoryAlarms(), proto.alarms); + assertEquals(policy.getPriorityCategoryMedia(), proto.media); + assertEquals(policy.getPriorityCategorySystem(), proto.system); + + assertEquals(policy.getVisualEffectFullScreenIntent(), proto.fullscreen); + assertEquals(policy.getVisualEffectLights(), proto.lights); + assertEquals(policy.getVisualEffectPeek(), proto.peek); + assertEquals(policy.getVisualEffectStatusBar(), proto.statusBar); + assertEquals(policy.getVisualEffectBadge(), proto.badge); + assertEquals(policy.getVisualEffectAmbient(), proto.ambient); + assertEquals(policy.getVisualEffectNotificationList(), proto.notificationList); + + assertEquals(policy.getPriorityCallSenders(), proto.allowCallsFrom); + assertEquals(policy.getPriorityMessageSenders(), proto.allowMessagesFrom); + assertEquals(policy.getPriorityConversationSenders(), proto.allowConversationsFrom); + } catch (InvalidProtocolBufferNanoException e) { + fail("could not parse proto bytes"); + } + + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java index bd616a3a96f3..64b5eca1beb8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java @@ -17,7 +17,6 @@ package com.android.server.wm; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; -import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession; @@ -111,7 +110,7 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); - doNothing().when(lifecycleManager).scheduleTransaction(any()); + doReturn(false).when(activity).inPinnedWindowingMode(); doReturn(false).when(activity).checkEnterPictureInPictureState(anyString(), anyBoolean()); mService.requestPictureInPictureMode(activity.token); @@ -120,6 +119,19 @@ public class ActivityTaskManagerServiceTests extends ActivityTestsBase { verify(lifecycleManager, times(0)).scheduleTransaction(any()); } + @Test(expected = IllegalStateException.class) + public void testOnPictureInPictureRequested_alreadyInPIPMode() throws RemoteException { + final ActivityStack stack = new StackBuilder(mRootWindowContainer).build(); + final ActivityRecord activity = stack.getBottomMostTask().getTopNonFinishingActivity(); + ClientLifecycleManager lifecycleManager = mService.getLifecycleManager(); + doReturn(true).when(activity).inPinnedWindowingMode(); + + mService.requestPictureInPictureMode(activity.token); + + // Check that no transactions with enter pip requests are made. + verify(lifecycleManager, times(0)).scheduleTransaction(any()); + } + @Test public void testDisplayWindowListener() { final ArrayList<Integer> added = new ArrayList<>(); |