diff options
564 files changed, 8569 insertions, 6710 deletions
diff --git a/Android.bp b/Android.bp index ee381a42d728..557c3209248d 100644 --- a/Android.bp +++ b/Android.bp @@ -670,7 +670,7 @@ java_library { filegroup { name: "framework-ike-shared-srcs", - visibility: ["//frameworks/opt/net/ike"], + visibility: ["//packages/modules/IPsec"], srcs: [ "core/java/android/annotation/StringDef.java", "core/java/android/net/annotations/PolicyDirection.java", @@ -930,6 +930,8 @@ filegroup { srcs: [ "core/java/android/os/incremental/IIncrementalService.aidl", "core/java/android/os/incremental/IncrementalNewFileParams.aidl", + "core/java/android/os/incremental/IStorageHealthListener.aidl", + "core/java/android/os/incremental/StorageHealthCheckParams.aidl", ], path: "core/java", } @@ -1223,4 +1225,4 @@ metalava_framework_docs_args = "--manifest $(location core/res/AndroidManifest.x build = [ "StubLibraries.bp", "ApiDocs.bp", -]
\ No newline at end of file +] diff --git a/ApiDocs.bp b/ApiDocs.bp index 90df19a9491a..a81342a5160f 100644 --- a/ApiDocs.bp +++ b/ApiDocs.bp @@ -66,7 +66,7 @@ stubs_defaults { ":opt-telephony-srcs", ":opt-net-voip-srcs", ":art-module-public-api-stubs-source", - ":conscrypt.module.public.api.stubs.source", + ":conscrypt.module.public.api{.public.stubs.source}", ":android_icu4j_public_api_files", "test-mock/src/**/*.java", "test-runner/src/**/*.java", diff --git a/StubLibraries.bp b/StubLibraries.bp index 6e6efe50309a..c0197c4b2acf 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -69,7 +69,7 @@ stubs_defaults { name: "metalava-full-api-stubs-default", defaults: ["metalava-base-api-stubs-default"], srcs: [ - ":conscrypt.module.public.api.stubs.source", + ":conscrypt.module.public.api{.public.stubs.source}", ":framework-updatable-sources", ], sdk_version: "core_platform", diff --git a/apex/Android.bp b/apex/Android.bp index de4b24aa274c..c1715a002d6d 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -100,6 +100,8 @@ java_defaults { // Configure framework module specific metalava options. droiddoc_options: [mainline_stubs_args], + annotations_enabled: true, + // The stub libraries must be visible to frameworks/base so they can be combined // into API specific libraries. stubs_library_visibility: [ diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java index dbfdcba05a73..656749d1a8c4 100644 --- a/apex/blobstore/framework/java/android/app/blob/XmlTags.java +++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java @@ -27,6 +27,7 @@ public final class XmlTags { public static final String ATTR_ID = "id"; public static final String ATTR_PACKAGE = "p"; public static final String ATTR_UID = "u"; + public static final String ATTR_CREATION_TIME_MS = "crt"; // For BlobMetadata public static final String TAG_BLOB = "b"; diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java index 49b3ec1d113b..cea7fcca6e20 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -212,7 +212,10 @@ class BlobMetadata { } boolean isAccessAllowedForCaller(@NonNull String callingPackage, int callingUid) { - // TODO: verify blob is still valid (expiryTime is not elapsed) + // Don't allow the blob to be accessed after it's expiry time has passed. + if (getBlobHandle().isExpired()) { + return false; + } synchronized (mMetadataLock) { // Check if packageName already holds a lease on the blob. for (int i = 0, size = mLeasees.size(); i < size; ++i) { diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java index b4a7cd4de2ae..656726622cfd 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java @@ -18,7 +18,6 @@ package com.android.server.blob; import static android.provider.DeviceConfig.NAMESPACE_BLOBSTORE; import static android.text.format.Formatter.FLAG_IEC_UNITS; import static android.text.format.Formatter.formatFileSize; -import static android.util.TimeUtils.formatDuration; import android.annotation.NonNull; import android.annotation.Nullable; @@ -46,8 +45,9 @@ class BlobStoreConfig { public static final int XML_VERSION_ADD_STRING_DESC = 2; public static final int XML_VERSION_ADD_DESC_RES_NAME = 3; public static final int XML_VERSION_ADD_COMMIT_TIME = 4; + public static final int XML_VERSION_ADD_SESSION_CREATION_TIME = 5; - public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_COMMIT_TIME; + public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_SESSION_CREATION_TIME; private static final String ROOT_DIR_NAME = "blobstore"; private static final String BLOBS_DIR_NAME = "blobs"; @@ -58,18 +58,24 @@ class BlobStoreConfig { * Job Id for idle maintenance job ({@link BlobStoreIdleJobService}). */ public static final int IDLE_JOB_ID = 0xB70B1D7; // 191934935L - /** - * Max time period (in millis) between each idle maintenance job run. - */ - public static final long IDLE_JOB_PERIOD_MILLIS = TimeUnit.DAYS.toMillis(1); - - /** - * Timeout in millis after which sessions with no updates will be deleted. - */ - public static final long SESSION_EXPIRY_TIMEOUT_MILLIS = TimeUnit.DAYS.toMillis(7); public static class DeviceConfigProperties { /** + * Denotes the max time period (in millis) between each idle maintenance job run. + */ + public static final String KEY_IDLE_JOB_PERIOD_MS = "idle_job_period_ms"; + public static final long DEFAULT_IDLE_JOB_PERIOD_MS = TimeUnit.DAYS.toMillis(1); + public static long IDLE_JOB_PERIOD_MS = DEFAULT_IDLE_JOB_PERIOD_MS; + + /** + * Denotes the timeout in millis after which sessions with no updates will be deleted. + */ + public static final String KEY_SESSION_EXPIRY_TIMEOUT_MS = + "session_expiry_timeout_ms"; + public static final long DEFAULT_SESSION_EXPIRY_TIMEOUT_MS = TimeUnit.DAYS.toMillis(7); + public static long SESSION_EXPIRY_TIMEOUT_MS = DEFAULT_SESSION_EXPIRY_TIMEOUT_MS; + + /** * Denotes how low the limit for the amount of data, that an app will be allowed to acquire * a lease on, can be. */ @@ -119,6 +125,13 @@ class BlobStoreConfig { } properties.getKeyset().forEach(key -> { switch (key) { + case KEY_IDLE_JOB_PERIOD_MS: + IDLE_JOB_PERIOD_MS = properties.getLong(key, DEFAULT_IDLE_JOB_PERIOD_MS); + break; + case KEY_SESSION_EXPIRY_TIMEOUT_MS: + SESSION_EXPIRY_TIMEOUT_MS = properties.getLong(key, + DEFAULT_SESSION_EXPIRY_TIMEOUT_MS); + break; case KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR: TOTAL_BYTES_PER_APP_LIMIT_FLOOR = properties.getLong(key, DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR); @@ -143,6 +156,12 @@ class BlobStoreConfig { static void dump(IndentingPrintWriter fout, Context context) { final String dumpFormat = "%s: [cur: %s, def: %s]"; + fout.println(String.format(dumpFormat, KEY_IDLE_JOB_PERIOD_MS, + TimeUtils.formatDuration(IDLE_JOB_PERIOD_MS), + TimeUtils.formatDuration(DEFAULT_IDLE_JOB_PERIOD_MS))); + fout.println(String.format(dumpFormat, KEY_SESSION_EXPIRY_TIMEOUT_MS, + TimeUtils.formatDuration(SESSION_EXPIRY_TIMEOUT_MS), + TimeUtils.formatDuration(DEFAULT_SESSION_EXPIRY_TIMEOUT_MS))); fout.println(String.format(dumpFormat, KEY_TOTAL_BYTES_PER_APP_LIMIT_FLOOR, formatFileSize(context, TOTAL_BYTES_PER_APP_LIMIT_FLOOR, FLAG_IEC_UNITS), formatFileSize(context, DEFAULT_TOTAL_BYTES_PER_APP_LIMIT_FLOOR, @@ -167,6 +186,22 @@ class BlobStoreConfig { } /** + * Returns the max time period (in millis) between each idle maintenance job run. + */ + public static long getIdleJobPeriodMs() { + return DeviceConfigProperties.IDLE_JOB_PERIOD_MS; + } + + /** + * Returns whether a session is expired or not. A session is considered expired if the session + * has not been modified in a while (i.e. SESSION_EXPIRY_TIMEOUT_MS). + */ + public static boolean hasSessionExpired(long sessionLastModifiedMs) { + return sessionLastModifiedMs + < System.currentTimeMillis() - DeviceConfigProperties.SESSION_EXPIRY_TIMEOUT_MS; + } + + /** * Returns the maximum amount of data that an app can acquire a lease on. */ public static long getAppDataBytesLimit() { @@ -277,9 +312,6 @@ class BlobStoreConfig { fout.println("XML current version: " + XML_VERSION_CURRENT); fout.println("Idle job ID: " + IDLE_JOB_ID); - fout.println("Idle job period: " + formatDuration(IDLE_JOB_PERIOD_MILLIS)); - - fout.println("Session expiry timeout: " + formatDuration(SESSION_EXPIRY_TIMEOUT_MILLIS)); fout.println("Total bytes per app limit: " + formatFileSize(context, getAppDataBytesLimit(), FLAG_IEC_UNITS)); diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java index 460e776b9ff6..4b0f719b13be 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreIdleJobService.java @@ -16,7 +16,6 @@ package com.android.server.blob; import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_ID; -import static com.android.server.blob.BlobStoreConfig.IDLE_JOB_PERIOD_MILLIS; import static com.android.server.blob.BlobStoreConfig.LOGV; import static com.android.server.blob.BlobStoreConfig.TAG; @@ -60,7 +59,7 @@ public class BlobStoreIdleJobService extends JobService { new ComponentName(context, BlobStoreIdleJobService.class)) .setRequiresDeviceIdle(true) .setRequiresCharging(true) - .setPeriodic(IDLE_JOB_PERIOD_MILLIS) + .setPeriodic(BlobStoreConfig.getIdleJobPeriodMs()) .build(); jobScheduler.schedule(job); if (LOGV) { 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 9376198b8eaf..8fff0d9c950b 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -29,7 +29,6 @@ import static android.os.UserHandle.USER_CURRENT; import static android.os.UserHandle.USER_NULL; import static com.android.server.blob.BlobStoreConfig.LOGV; -import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS; import static com.android.server.blob.BlobStoreConfig.TAG; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_CURRENT; import static com.android.server.blob.BlobStoreConfig.getAdjustedCommitTimeMs; @@ -987,8 +986,7 @@ public class BlobStoreManagerService extends SystemService { boolean shouldRemove = false; // Cleanup sessions which haven't been modified in a while. - if (blobStoreSession.getSessionFile().lastModified() - < System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS) { + if (blobStoreSession.isExpired()) { shouldRemove = true; } @@ -1059,6 +1057,18 @@ public class BlobStoreManagerService extends SystemService { } } + boolean isBlobAvailable(long blobId, int userId) { + synchronized (mBlobsLock) { + final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId); + for (BlobMetadata blobMetadata : userBlobs.values()) { + if (blobMetadata.getBlobId() == blobId) { + return true; + } + } + return false; + } + } + @GuardedBy("mBlobsLock") private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) { for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) { diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java index 72af323e9d5f..a4a2e80c195a 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java @@ -46,6 +46,8 @@ class BlobStoreManagerShellCommand extends ShellCommand { return runDeleteBlob(pw); case "idle-maintenance": return runIdleMaintenance(pw); + case "query-blob-existence": + return runQueryBlobExistence(pw); default: return handleDefaultCommands(cmd); } @@ -91,6 +93,16 @@ class BlobStoreManagerShellCommand extends ShellCommand { return 0; } + private int runQueryBlobExistence(PrintWriter pw) { + final ParsedArgs args = new ParsedArgs(); + if (parseOptions(pw, args) < 0) { + return -1; + } + + pw.println(mService.isBlobAvailable(args.blobId, args.userId) ? 1 : 0); + return 0; + } + @Override public void onHelp() { final PrintWriter pw = getOutPrintWriter(); @@ -121,6 +133,8 @@ class BlobStoreManagerShellCommand extends ShellCommand { pw.println(" --tag: Tag of the blob to delete."); pw.println("idle-maintenance"); pw.println(" Run idle maintenance which takes care of removing stale data."); + pw.println("query-blob-existence [-b BLOB_ID]"); + pw.println(" Prints 1 if blob exists, otherwise 0."); pw.println(); } @@ -147,6 +161,9 @@ class BlobStoreManagerShellCommand extends ShellCommand { case "--tag": args.tag = getNextArgRequired(); break; + case "-b": + args.blobId = Long.parseLong(getNextArgRequired()); + break; default: pw.println("Error: unknown option '" + opt + "'"); return -1; @@ -166,6 +183,7 @@ class BlobStoreManagerShellCommand extends ShellCommand { public long expiryTimeMillis; public CharSequence label; public String tag; + public long blobId; public BlobHandle getBlobHandle() { return BlobHandle.create(algorithm, digest, label, expiryTimeMillis, tag); 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 62701e52781d..2b0458303a23 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java @@ -16,6 +16,7 @@ package com.android.server.blob; import static android.app.blob.BlobStoreManager.COMMIT_RESULT_ERROR; +import static android.app.blob.XmlTags.ATTR_CREATION_TIME_MS; import static android.app.blob.XmlTags.ATTR_ID; import static android.app.blob.XmlTags.ATTR_PACKAGE; import static android.app.blob.XmlTags.ATTR_UID; @@ -29,6 +30,8 @@ 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; import android.annotation.BytesLong; import android.annotation.NonNull; @@ -89,6 +92,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { private final long mSessionId; private final int mOwnerUid; private final String mOwnerPackageName; + private final long mCreationTimeMs; // Do not access this directly, instead use getSessionFile(). private File mSessionFile; @@ -109,16 +113,24 @@ class BlobStoreSession extends IBlobStoreSession.Stub { @GuardedBy("mSessionLock") private IBlobCommitCallback mBlobCommitCallback; - BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle, - int ownerUid, String ownerPackageName, SessionStateChangeListener listener) { + private BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle, + int ownerUid, String ownerPackageName, long creationTimeMs, + SessionStateChangeListener listener) { this.mContext = context; this.mBlobHandle = blobHandle; this.mSessionId = sessionId; this.mOwnerUid = ownerUid; this.mOwnerPackageName = ownerPackageName; + this.mCreationTimeMs = creationTimeMs; this.mListener = listener; } + BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle, + int ownerUid, String ownerPackageName, SessionStateChangeListener listener) { + this(context, sessionId, blobHandle, ownerUid, ownerPackageName, + System.currentTimeMillis(), listener); + } + public BlobHandle getBlobHandle() { return mBlobHandle; } @@ -178,6 +190,12 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } } + boolean isExpired() { + final long lastModifiedTimeMs = getSessionFile().lastModified(); + return hasSessionExpired(lastModifiedTimeMs == 0 + ? mCreationTimeMs : lastModifiedTimeMs); + } + @Override @NonNull public ParcelFileDescriptor openWrite(@BytesLong long offsetBytes, @@ -491,6 +509,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { fout.println("state: " + stateToString(mState)); fout.println("ownerUid: " + mOwnerUid); fout.println("ownerPkg: " + mOwnerPackageName); + fout.println("creation time: " + BlobStoreUtils.formatTime(mCreationTimeMs)); fout.println("blobHandle:"); fout.increaseIndent(); @@ -511,6 +530,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { XmlUtils.writeLongAttribute(out, ATTR_ID, mSessionId); XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, mOwnerPackageName); XmlUtils.writeIntAttribute(out, ATTR_UID, mOwnerUid); + XmlUtils.writeLongAttribute(out, ATTR_CREATION_TIME_MS, mCreationTimeMs); out.startTag(null, TAG_BLOB_HANDLE); mBlobHandle.writeToXml(out); @@ -529,6 +549,9 @@ class BlobStoreSession extends IBlobStoreSession.Stub { final long sessionId = XmlUtils.readLongAttribute(in, ATTR_ID); final String ownerPackageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); final int ownerUid = XmlUtils.readIntAttribute(in, ATTR_UID); + final long creationTimeMs = version >= XML_VERSION_ADD_SESSION_CREATION_TIME + ? XmlUtils.readLongAttribute(in, ATTR_CREATION_TIME_MS) + : System.currentTimeMillis(); final int depth = in.getDepth(); BlobHandle blobHandle = null; @@ -551,7 +574,7 @@ class BlobStoreSession extends IBlobStoreSession.Stub { } final BlobStoreSession blobStoreSession = new BlobStoreSession(context, sessionId, - blobHandle, ownerUid, ownerPackageName, stateChangeListener); + blobHandle, ownerUid, ownerPackageName, creationTimeMs, stateChangeListener); blobStoreSession.mBlobAccessMode.allow(blobAccessMode); return blobStoreSession; } diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java index 94e5d0b2591b..40328b300cee 100644 --- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java +++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java @@ -1322,6 +1322,8 @@ public class AppStandbyController implements AppStandbyInternal { private void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket, int reason, long elapsedRealtime, boolean resetTimeout) { + if (!mAppIdleEnabled) return; + synchronized (mAppIdleLock) { // If the package is not installed, don't allow the bucket to be set. if (!mInjector.isPackageInstalled(packageName, 0, userId)) { diff --git a/apex/sdkextensions/Android.bp b/apex/sdkextensions/Android.bp deleted file mode 100644 index fdb078e00d92..000000000000 --- a/apex/sdkextensions/Android.bp +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_visibility: [":__subpackages__"], -} - -apex { - name: "com.android.sdkext", - defaults: [ "com.android.sdkext-defaults" ], - binaries: [ "derive_sdk" ], - prebuilts: [ "cur_sdkinfo" ], - manifest: "manifest.json", - min_sdk_version: "current", -} - -apex_defaults { - name: "com.android.sdkext-defaults", - updatable: true, - min_sdk_version: "R", - java_libs: [ "framework-sdkextensions" ], - prebuilts: [ - "derive_sdk.rc", - ], - key: "com.android.sdkext.key", - certificate: ":com.android.sdkext.certificate", -} - -sdk { - name: "sdkextensions-sdk", - java_sdk_libs: [ "framework-sdkextensions" ], -} - -apex_key { - name: "com.android.sdkext.key", - public_key: "com.android.sdkext.avbpubkey", - private_key: "com.android.sdkext.pem", -} - -android_app_certificate { - name: "com.android.sdkext.certificate", - certificate: "com.android.sdkext", -} - -python_binary_host { - name: "gen_sdkinfo", - srcs: [ - "sdk.proto", - "gen_sdkinfo.py", - ], - proto: { - canonical_path_from_root: false, - }, - version: { - py3: { - embedded_launcher: true, - }, - }, -} - -gensrcs { - name: "cur_sdkinfo_src", - srcs: [""], - tools: [ "gen_sdkinfo" ], - cmd: "$(location) -v 0 -o $(out)", -} - -prebuilt_etc { - name: "cur_sdkinfo", - src: ":cur_sdkinfo_src", - filename: "sdkinfo.binarypb", - installable: false, -} diff --git a/apex/sdkextensions/OWNERS b/apex/sdkextensions/OWNERS deleted file mode 100644 index a6e55228596b..000000000000 --- a/apex/sdkextensions/OWNERS +++ /dev/null @@ -1,2 +0,0 @@ -dariofreni@google.com -hansson@google.com diff --git a/apex/sdkextensions/TEST_MAPPING b/apex/sdkextensions/TEST_MAPPING deleted file mode 100644 index 3dc1b9fa5dd0..000000000000 --- a/apex/sdkextensions/TEST_MAPPING +++ /dev/null @@ -1,10 +0,0 @@ -{ - "presubmit": [ - { - "name": "CtsSdkExtensionsTestCases" - }, - { - "name": "sdkextensions_e2e_tests" - } - ] -} diff --git a/apex/sdkextensions/com.android.sdkext.avbpubkey b/apex/sdkextensions/com.android.sdkext.avbpubkey Binary files differdeleted file mode 100644 index 8f47741ed3b8..000000000000 --- a/apex/sdkextensions/com.android.sdkext.avbpubkey +++ /dev/null diff --git a/apex/sdkextensions/com.android.sdkext.pem b/apex/sdkextensions/com.android.sdkext.pem deleted file mode 100644 index 816460183aa3..000000000000 --- a/apex/sdkextensions/com.android.sdkext.pem +++ /dev/null @@ -1,51 +0,0 @@ ------BEGIN RSA PRIVATE KEY----- -MIIJKQIBAAKCAgEAr72pTSavrziDP54AtQZlRclDxJf9HXRZwFRbYx9hWZ4z7ZtO -pNBDPvPJCiAOVUsILgCQhBUolz2dyLob25Fd0PVp0n9ibIPEQYjTfHjOK40qb57N -LhEp2ceGiAfsywPSi0TH1PQ6JgbCe/RM4TefI/sj3gYJPka3ksMvylhMIgUVLgME -kYizhzwHqlLMspB858SioREZdGwcdZrMMIajGFU69Q9ZRDBzhPvxyKhYoObcOtk1 -uVaiE/fNoi3wKGJz2l2vhUuNrQW7MWlVMag+Qes4YACUTk9LZrOVFEJFjWc8xGUi -ABtfKGs5JgNr/sWnhvifLn8lJuf0/BJmjD+L5QwXYs2cS7gcZJtTM12J94r0Twgw -wF2lNmIxAE9sYqj5Rh3dIlTPE5vMUECmQEGjIBB/hzT65VxVqSjU/IlS506JTg3p -IOQtZ15cUzTBpda4jrvqcq6RNVvgBCu2bV5D8Z4z9FUlPyvD+Zq/6lcoJfLtznAs -G2463hyPAHTGBIcZ5p5bTuGxoAb6ivyqo4b9Qi4yYA6je9HJmuy8T3Mn5JROoeu9 -BH1K54r/mpT4TQPwuKUvRRtBAV2OPHjo+zp0Gd4Y6rxDYxEIdfEae7pQr/QExSPB -q/QCr9RhixR1mO373LHuja+MxdAxIxugb2HTS61PQo+PbYrhJMcVuxTwJOECAwEA -AQKCAgAH7ToRrMkH0ji5SdsmTx+KQkW4PFLCXVke/68PjX7KmAQnl3W4oVwnHr/W -oROEbVn1GTlre7jU+YaAY0SWZrwgjLE1OWGrG1ZizlUbrCdAd6GOX09J4KROml1L -DXB0x7tbZMLOrCVjSbLD/ITrM6MN8Gnxvbv0/yOQjxU8vzbP4gLOjHxMRCo001RV -Ll7lPvcjTQ84zJilU6sE8vJ6zdfVZSK/ou2X0cekG+kP7+fvefo8/UcbEPlGhUrV -IdVPPQGUu90K2hmN0FBdLi8Vik0klAN68Qu/bHwuKbNzsnmIoztucFFUR+fG3u84 -87aPS0L/J3+mjT2Tv6qhJANUGBmrK/h7MkelpKXlRTCITJLX9xP7hfSbJ4f6aLVq -ZYPPciGxSBbUDgAwvPtOlMDzccg7YsYyiBBO28wh8MN97rePmc0z6nGmjeXhcbCC -QktG50VYFCyqp5muKgqQmRfRjHFHLWs8GEqgxMeEL3U3HjYfCYr+6E8Sr5OnOBeH -3buCi1+zgnNYCvbamgY/OJmW7f9h5O31hxmTplc2E1ZuxUGQZthabt1rN3bmNkyf -KUmPwnIYkDkWBSV5lzyQExfS3/EVvj0EnHhx8faamimNrGo8xCcfnLT3c0WEFVmo -yIyVRX3EpXJFM2JkeJ21/IEZXTzHSoNxk12CBG8i8lLSflWSMQKCAQEA2ZqVnOuV -SZfLCUYUUh8Hvhc5zONstfq7ma1Zsttsdaj9t68nLRiBDvLOGnMjDkYZzoSd4fyl -oy+YqWGBqcqa5kg1NOCH0I46p9d8RcWAfDnB4sqbLgWh70qsvni6igRijmsMDvkA -U9HeEdPaLCjQ4UXw7GQvN5rRxuRt+OSqV3tV/Pk9JYyYjz7faC8dmbKDrWHHuOvm -/9y6Xy+L5IgftykNlUeddSCIoMOAadM7BiRjsrHnOYBQ8xBcn0OYafpIswItrgVi -IrsPJaBFidx8QYK4MVibyka6U0cm28OocDSPtSk/4jrnCEEhLjFUnWwuMXuBGlrd -W7wP/muoJqb1VwKCAQEAzsAT90kkOCvAcrfGRE3KkUjwWAsQyP8u2+27JIQPqrpW -GfWAzJXFt80TSp0Zf/Lrq3/SQ9n4AaL4K9dcMoreedoQN9C9JI7zPtZAWNrJVUcV -dq2gZjBQ78+oK7uQgvFNWxga5D+Nh+Y+9Tp537fc5HIh0Y13PgsxxPk2OnZJTvLX -HM5H7Aua9ssmqChsrKihuUsDSPozfBz+H7FNHEdKMqVLqJJSK6m0uMxuLovdVfka -5S7iBMjEGZc46Iz3ckE0pdOiQLooNqfEQqFe5Uou/KZxxKI1NW25rEEBTVyQWt+2 -BNUCfKP7noZ45u5sUY3eJrgI7BrPEDbNS81WYaLchwKCAQA8Q4mHyd6wYO+EA/qA -u8NDK9+AFMP4qhXme5HJ7Obetwx9IG7zGEQ1xZy6yoQ84cEn5qZq/bNJvFbFIhHs -2gWIHRtPJ5e1dI5eCVmLYSUyQjSmAIJ1fm3YfY/VuE3BB3HcC11tkBw9GnQr78YO -UMd4fAw7C4vgFGpgcMbcFUfvrmKkCsqaaZOeqETq75F9DWlWTSwo1HxHA/RBhENz -6RcPfLkcTJcY5wevrjUUGcHQ86cAyDBHRngkuLVODkRZpU0Y9lN8TFVfVPre6sIX -ag6nffJRCD8tB+V2RtBGMKunV4ctHt1oY/Oz34W260aJynoIjjG1ANEpJK4xQdNx -0O9FAoIBAQCz2AGGKemHswdEwveEkuaSWpA3Bekj7lYkmTchHH9EU7JyAkx3qhDD -QXB2hxGXawf1tsqAmypQwiJ+gGeCz6mW9UkGRF1DX9XX4yc2I5rew2a4RXAxc/Xz -pP70i8O5I43Wn7FEusOyY2aAis1Y/eb4EQ+56QTAw5wXa3DwidRbCIJ2XDnT6oRy -CWUnAYMG7ek/9TB2Wq5OWCn2B5S79IdmZsLZb+5qbMT3u1xcwO1Xy8jJc27IGpv6 -ZsDqCTV1/aJ+XQnWpBg28tiV3Sle6pjUzTRJh5AhWcEZRbKMSOiJI/CBY4k2Qq6t -xuuEdgFjL7T+mTepqehUglcyiPuLEtAhAoIBAQDDQ5pTFOlunfYzm+CIvvImAgy7 -vrEabJYABATytAbXRMMbrKoEdU2ApEDyEW7PgysDnYLAZ+icObnJlBTYvNdlWFly -XiviGVfpjFWDT9U/gUwFQu2lfEjoiivoGS92USHUy4UMVHiiznnm20VLLkgd3xna -HUNSDdHIEgzOTmDsKJwMfA9zGckx23JJimPR5ekv6vr6QllYtECs4lTC1gVQAp2f -5daxHRbkmO6gw1RgQADLkAnYz3aI1jNuHm5VyAZGt/d3JCtZ3Wwwejll8uJ4J09G -oEtqyY9RVeHK50bLO4lyAXFiE+J6qqXjsGC20cpxeZYW5llMY/dhA6WV4YXV ------END RSA PRIVATE KEY----- diff --git a/apex/sdkextensions/com.android.sdkext.pk8 b/apex/sdkextensions/com.android.sdkext.pk8 Binary files differdeleted file mode 100644 index ccc0bf438cd1..000000000000 --- a/apex/sdkextensions/com.android.sdkext.pk8 +++ /dev/null diff --git a/apex/sdkextensions/com.android.sdkext.x509.pem b/apex/sdkextensions/com.android.sdkext.x509.pem deleted file mode 100644 index 45d2ade354d4..000000000000 --- a/apex/sdkextensions/com.android.sdkext.x509.pem +++ /dev/null @@ -1,35 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIGIzCCBAugAwIBAgIUXuDL7QvzQh7S6rihWz2KRvCFVT0wDQYJKoZIhvcNAQEL -BQAwgZ8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQH -DA1Nb3VudGFpbiBWaWV3MRAwDgYDVQQKDAdBbmRyb2lkMRAwDgYDVQQLDAdBbmRy -b2lkMRswGQYDVQQDDBJjb20uYW5kcm9pZC5zZGtleHQxIjAgBgkqhkiG9w0BCQEW -E2FuZHJvaWRAYW5kcm9pZC5jb20wIBcNMTkxMjAyMTQyNDM0WhgPNDc1NzEwMjgx -NDI0MzRaMIGfMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQG -A1UEBwwNTW91bnRhaW4gVmlldzEQMA4GA1UECgwHQW5kcm9pZDEQMA4GA1UECwwH -QW5kcm9pZDEbMBkGA1UEAwwSY29tLmFuZHJvaWQuc2RrZXh0MSIwIAYJKoZIhvcN -AQkBFhNhbmRyb2lkQGFuZHJvaWQuY29tMIICIjANBgkqhkiG9w0BAQEFAAOCAg8A -MIICCgKCAgEAxFvZZ6ES1oqAu1K74/ZxnC3SOhHnLISLBgJEe7DqtdpuNFAwvdVO -RL/HULhDbjYlOhpU2x3SavDIZZ2lRfiS9Q+M25WftxTRHVjBcpgwbV77TVxPKlAa -tVN2lUVOY+s4QAVMNIXjC4kCKK/pCQtacH715EtdV47fWdg/Nx4iP/Aord8k3KGI -9iI2ZOUjaugTRxu5lKRNDrv0bw5rEzyYmDyMud+kR/iS3/5oog57wPE0ffAkZXWE -p3L2Cejre3ekCizsvVh6EmH6ForKLtL6f0z5Zir1f4R9+YcENspTlJR3pDhg7y3I -uTQT/iDCtV0l+g2PjGZPEeAQHND3+kDQR7Sno/WC1Nhws6vcu1MdrC+kIh1ewx4y -8moy/yqb5M98PJDzTSi/AOTB/OiqLXo/T8rjLBmirs9y3fTT6gJ6qXxOWgt8dle9 -7TBfa84Xi8uVY61c+A+YI0nLal7QDPsP3RPv5sJSQ9x9YnweVfD9Q0EOi52sSNu+ -QuN/kcUrMgPgha20VhfH/CkkPDyIp6aZyHHM69MIl+cYEm8vPa5uy3dosuRomT0f -I4HOBjULDIuj+rIi+Rg3qHvmpuejwZXI/FBNWIhLEUG3ytgksjMaBoYAYflGdrcj -BQexuF3EO+j4uo7JGjNcaT7wRoCH9gt29VHckDg2qz6VWXrlpmME4UkCAwEAAaNT -MFEwHQYDVR0OBBYEFISN2nmUHllgPZMZ62U7mU3ZxzlXMB8GA1UdIwQYMBaAFISN -2nmUHllgPZMZ62U7mU3ZxzlXMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQEL -BQADggIBAFHIwyBNIVyHXUsDUdcjxfojXQsF/BCL9ehE3pgdkvDfQanaIREWn0nc -oCFDFkYMRqaXOGC5TKq4OCjXOLsdfODt8HQ3F9J1B0ghQ5tfOdw7xDugNAszqP/Q -h7kpvqLTycjrqOeZ5KjxEEYtP/KlUmALgOKcTcSH+XhWyxhjF4j24T9F2yJRr3/A -r1NGU/djH953bHKC8OpJ2teUpDLA4TxVp/EhslH2eVigF80c/w74QPLEWkD9zv/4 -YeRg/R5N83zHs99NtlWMIeHfK6fUbzMyaSZtvm+jK20tkByQb/OQRed+drk25MtL -68IRvxqri367qRScdpTZbu0ByLO4X8gFdubRUWr+tcO4pZX+DJRVriExbOkU2xhS -Vtslq23V/hwTuUNm1CXjR70mPS13BTmHrIQDqLoIw/WTQlGh+vxnlAFRIHM3KB2c -OdzUBu+NcB4aZEd0KKtct600A0DKPr1MQPb5jDq9wEtPSQYwMF0nRFNnXltbrXMd -4hhwnhKr74fVMUmb+7eQP56XE/Nk4D+npMO54vv1pav+DI2/nxCND9BOLBweY38p -Tvd2RjesMok0zXuVXiCIu4GEpwo7WkSnv25xrb0Ey2M8QWnGNnCcX7Kv6ip3RdWy -HiN0G8RJrs/yNEVSDRx8ZhtwTpXVPQxbARbmhNF4/fnolElkmrMP ------END CERTIFICATE----- diff --git a/apex/sdkextensions/derive_sdk/Android.bp b/apex/sdkextensions/derive_sdk/Android.bp deleted file mode 100644 index 41eae09b1351..000000000000 --- a/apex/sdkextensions/derive_sdk/Android.bp +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -cc_defaults { - name: "derive_sdk-defaults", - srcs: [ - "derive_sdk.cpp", - "sdk.proto", - ], - proto: { - type: "lite", - static: true, - }, - min_sdk_version: "current", - shared_libs: ["liblog"], - // static c++/libbase for smaller size - stl: "c++_static", - static_libs: ["libbase"], -} - -cc_binary { - name: "derive_sdk", - defaults: [ "derive_sdk-defaults" ], - apex_available: [ "com.android.sdkext" ], - visibility: [ "//frameworks/base/apex/sdkextensions" ] -} - -// Work around testing using a 64-bit test suite on 32-bit test device by -// using a prefer32 version of derive_sdk in testing. -cc_binary { - name: "derive_sdk_prefer32", - defaults: [ "derive_sdk-defaults" ], - compile_multilib: "prefer32", - stem: "derive_sdk", - apex_available: [ "test_com.android.sdkext" ], - visibility: [ "//frameworks/base/apex/sdkextensions/testing" ], - installable: false, -} - -prebuilt_etc { - name: "derive_sdk.rc", - src: "derive_sdk.rc", - installable: false, -} diff --git a/apex/sdkextensions/derive_sdk/derive_sdk.cpp b/apex/sdkextensions/derive_sdk/derive_sdk.cpp deleted file mode 100644 index 900193a6bd0d..000000000000 --- a/apex/sdkextensions/derive_sdk/derive_sdk.cpp +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#define LOG_TAG "derive_sdk" - -#include <algorithm> -#include <dirent.h> -#include <iostream> -#include <sys/stat.h> -#include <vector> - -#include <android-base/file.h> -#include <android-base/logging.h> -#include <android-base/properties.h> - -#include "frameworks/base/apex/sdkextensions/derive_sdk/sdk.pb.h" - -using com::android::sdkext::proto::SdkVersion; - -int main(int, char**) { - std::unique_ptr<DIR, decltype(&closedir)> apex(opendir("/apex"), closedir); - if (!apex) { - LOG(ERROR) << "Could not read /apex"; - return EXIT_FAILURE; - } - struct dirent* de; - std::vector<std::string> paths; - while ((de = readdir(apex.get()))) { - std::string name = de->d_name; - if (name[0] == '.' || name.find('@') != std::string::npos) { - // Skip <name>@<ver> dirs, as they are bind-mounted to <name> - continue; - } - std::string path = "/apex/" + name + "/etc/sdkinfo.binarypb"; - struct stat statbuf; - if (stat(path.c_str(), &statbuf) == 0) { - paths.push_back(path); - } - } - - std::vector<int> versions; - for (const auto& path : paths) { - std::string contents; - if (!android::base::ReadFileToString(path, &contents, true)) { - LOG(ERROR) << "failed to read " << path; - continue; - } - SdkVersion sdk_version; - if (!sdk_version.ParseFromString(contents)) { - LOG(ERROR) << "failed to parse " << path; - continue; - } - LOG(INFO) << "Read version " << sdk_version.version() << " from " << path; - versions.push_back(sdk_version.version()); - } - auto itr = std::min_element(versions.begin(), versions.end()); - std::string prop_value = itr == versions.end() ? "0" : std::to_string(*itr); - - if (!android::base::SetProperty("build.version.extensions.r", prop_value)) { - LOG(ERROR) << "failed to set sdk_info prop"; - return EXIT_FAILURE; - } - - LOG(INFO) << "R extension version is " << prop_value; - return EXIT_SUCCESS; -} diff --git a/apex/sdkextensions/derive_sdk/derive_sdk.rc b/apex/sdkextensions/derive_sdk/derive_sdk.rc deleted file mode 100644 index 18f021ccadff..000000000000 --- a/apex/sdkextensions/derive_sdk/derive_sdk.rc +++ /dev/null @@ -1,5 +0,0 @@ -service derive_sdk /apex/com.android.sdkext/bin/derive_sdk - user nobody - group nobody - oneshot - disabled diff --git a/apex/sdkextensions/framework/Android.bp b/apex/sdkextensions/framework/Android.bp deleted file mode 100644 index b8aad7d8204f..000000000000 --- a/apex/sdkextensions/framework/Android.bp +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_visibility: [ ":__pkg__" ] -} - -filegroup { - name: "framework-sdkextensions-sources", - srcs: [ - "java/**/*.java", - ], - path: "java", - visibility: [ "//frameworks/base" ] // For the "global" stubs. -} - -java_sdk_library { - name: "framework-sdkextensions", - srcs: [ ":framework-sdkextensions-sources" ], - defaults: ["framework-module-defaults"], - - // TODO(b/155480189) - Remove naming_scheme once references have been resolved. - // Temporary java_sdk_library component naming scheme to use to ease the transition from separate - // modules to java_sdk_library. - naming_scheme: "framework-modules", - - permitted_packages: [ "android.os.ext" ], - installable: true, - visibility: [ - "//frameworks/base/apex/sdkextensions", - "//frameworks/base/apex/sdkextensions/testing", - ], - hostdex: true, // for hiddenapi check - apex_available: [ - "com.android.sdkext", - "test_com.android.sdkext", - ], -} diff --git a/apex/sdkextensions/framework/api/current.txt b/apex/sdkextensions/framework/api/current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/module-lib-current.txt b/apex/sdkextensions/framework/api/module-lib-current.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/module-lib-current.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/module-lib-removed.txt b/apex/sdkextensions/framework/api/module-lib-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/module-lib-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/removed.txt b/apex/sdkextensions/framework/api/removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/api/system-current.txt b/apex/sdkextensions/framework/api/system-current.txt deleted file mode 100644 index bbff4c5ae6f4..000000000000 --- a/apex/sdkextensions/framework/api/system-current.txt +++ /dev/null @@ -1,9 +0,0 @@ -// Signature format: 2.0 -package android.os.ext { - - public class SdkExtensions { - method public static int getExtensionVersion(int); - } - -} - diff --git a/apex/sdkextensions/framework/api/system-removed.txt b/apex/sdkextensions/framework/api/system-removed.txt deleted file mode 100644 index d802177e249b..000000000000 --- a/apex/sdkextensions/framework/api/system-removed.txt +++ /dev/null @@ -1 +0,0 @@ -// Signature format: 2.0 diff --git a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java b/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java deleted file mode 100644 index 6c25f2849cea..000000000000 --- a/apex/sdkextensions/framework/java/android/os/ext/SdkExtensions.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.os.ext; - -import android.annotation.IntDef; -import android.annotation.SystemApi; -import android.os.Build.VERSION_CODES; -import android.os.SystemProperties; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; - -/** - * Methods for interacting with the extension SDK. - * - * This class provides information about the extension SDK version present - * on this device. Use the {@link #getExtensionVersion(int) getExtension} to - * query for the extension version for the given SDK version. - - * @hide - */ -@SystemApi -public class SdkExtensions { - - private static final int R_EXTENSION_INT; - static { - // Note: when adding more extension versions, the logic that records current - // extension versions when saving a rollback must also be updated. - // At the time of writing this is in RollbackManagerServiceImpl#getExtensionVersions() - R_EXTENSION_INT = SystemProperties.getInt("build.version.extensions.r", 0); - } - - /** - * Values suitable as parameters for {@link #getExtensionVersion(int)}. - * @hide - */ - @IntDef(value = { VERSION_CODES.R }) - @Retention(RetentionPolicy.SOURCE) - public @interface SdkVersion {} - - private SdkExtensions() { } - - /** - * Return the version of the extension to the given SDK. - * - * @param sdk the SDK version to get the extension version of. - * @see SdkVersion - * @throws IllegalArgumentException if sdk is not an sdk version with extensions - */ - public static int getExtensionVersion(@SdkVersion int sdk) { - if (sdk < VERSION_CODES.R) { - throw new IllegalArgumentException(String.valueOf(sdk) + " does not have extensions"); - } - - if (sdk == VERSION_CODES.R) { - return R_EXTENSION_INT; - } - return 0; - } - -} diff --git a/apex/sdkextensions/framework/java/android/os/ext/package.html b/apex/sdkextensions/framework/java/android/os/ext/package.html deleted file mode 100644 index 34c1697c01fd..000000000000 --- a/apex/sdkextensions/framework/java/android/os/ext/package.html +++ /dev/null @@ -1,5 +0,0 @@ -<HTML> -<BODY> -Provides APIs to interface with the SDK extensions. -</BODY> -</HTML> diff --git a/apex/sdkextensions/gen_sdkinfo.py b/apex/sdkextensions/gen_sdkinfo.py deleted file mode 100644 index 5af478ba7fe6..000000000000 --- a/apex/sdkextensions/gen_sdkinfo.py +++ /dev/null @@ -1,19 +0,0 @@ -import sdk_pb2 -import sys - -if __name__ == '__main__': - argv = sys.argv[1:] - if not len(argv) == 4 or sorted([argv[0], argv[2]]) != ['-o', '-v']: - print('usage: gen_sdkinfo -v <version> -o <output-file>') - sys.exit(1) - - for i in range(len(argv)): - if sys.argv[i] == '-o': - filename = sys.argv[i+1] - if sys.argv[i] == '-v': - version = int(sys.argv[i+1]) - - proto = sdk_pb2.SdkVersion() - proto.version = version - with open(filename, 'wb') as f: - f.write(proto.SerializeToString()) diff --git a/apex/sdkextensions/manifest.json b/apex/sdkextensions/manifest.json deleted file mode 100644 index deeb29e155c0..000000000000 --- a/apex/sdkextensions/manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.sdkext", - "version": 300000000 -} diff --git a/apex/sdkextensions/sdk.proto b/apex/sdkextensions/sdk.proto deleted file mode 100644 index d15b93552ff4..000000000000 --- a/apex/sdkextensions/sdk.proto +++ /dev/null @@ -1,25 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -syntax = "proto3"; -package com.android.sdkext.proto; - -option java_outer_classname = "SdkProto"; -option optimize_for = LITE_RUNTIME; - -message SdkVersion { - int32 version = 1; -} diff --git a/apex/sdkextensions/testing/Android.bp b/apex/sdkextensions/testing/Android.bp deleted file mode 100644 index f2f5b321fafe..000000000000 --- a/apex/sdkextensions/testing/Android.bp +++ /dev/null @@ -1,46 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -apex_test { - name: "test_com.android.sdkext", - visibility: [ "//system/apex/tests" ], - defaults: ["com.android.sdkext-defaults"], - manifest: "test_manifest.json", - prebuilts: [ "sdkinfo_45" ], - file_contexts: ":com.android.sdkext-file_contexts", - installable: false, // Should never be installed on the systemimage - multilib: { - prefer32: { - binaries: ["derive_sdk_prefer32"], - }, - }, - // The automated test infra ends up building this apex for 64+32-bit and - // then installs it on a 32-bit-only device. Work around this weirdness - // by preferring 32-bit. - compile_multilib: "prefer32", -} - -genrule { - name: "sdkinfo_45_src", - out: [ "sdkinfo.binarypb" ], - tools: [ "gen_sdkinfo" ], - cmd: "$(location) -v 45 -o $(out)", -} - -prebuilt_etc { - name: "sdkinfo_45", - src: ":sdkinfo_45_src", - filename: "sdkinfo.binarypb", - installable: false, -} diff --git a/apex/sdkextensions/testing/test_manifest.json b/apex/sdkextensions/testing/test_manifest.json deleted file mode 100644 index 1b4a2b0c6e60..000000000000 --- a/apex/sdkextensions/testing/test_manifest.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "name": "com.android.sdkext", - "version": 2147483647 -} diff --git a/apex/statsd/framework/Android.bp b/apex/statsd/framework/Android.bp index 9f5d933bb48a..27bd2e31168d 100644 --- a/apex/statsd/framework/Android.bp +++ b/apex/statsd/framework/Android.bp @@ -46,11 +46,15 @@ filegroup { "//frameworks/base/apex/statsd:__subpackages__", ], } -java_library { +java_sdk_library { name: "framework-statsd", + defaults: ["framework-module-defaults"], installable: true, - sdk_version: "module_current", - libs: [ "framework-annotations-lib" ], + + // TODO(b/155480189) - Remove naming_scheme once references have been resolved. + // Temporary java_sdk_library component naming scheme to use to ease the transition from separate + // modules to java_sdk_library. + naming_scheme: "framework-modules", srcs: [ ":framework-statsd-sources", @@ -60,125 +64,30 @@ java_library { "android.app", "android.os", "android.util", + // From :statslog-statsd-java-gen + "com.android.internal.util", ], - plugins: ["java_api_finder"], + api_packages: [ + "android.app", + "android.os", + "android.util", + ], hostdex: true, // for hiddenapi check visibility: [ "//frameworks/base/apex/statsd:__subpackages__", ], - apex_available: [ - "com.android.os.statsd", - "test_com.android.os.statsd", - ], -} - -stubs_defaults { - name: "framework-statsd-stubs-srcs-defaults", - srcs: [ - ":framework-statsd-sources", - ], - - libs: [ - "framework-annotations-lib", - ], - sdk_version: "system_current", - dist: { dest: "framework-statsd.txt" }, -} - -droidstubs { - name: "framework-statsd-stubs-srcs-publicapi", - defaults: [ - "framework-module-stubs-defaults-publicapi", - "framework-statsd-stubs-srcs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-statsd.api.public.latest", - removed_api_file: ":framework-statsd-removed.api.public.latest", - }, - api_lint: { - new_since: ":framework-statsd.api.public.latest", - }, - }, -} - -droidstubs { - name: "framework-statsd-stubs-srcs-systemapi", - defaults: [ - "framework-module-stubs-defaults-systemapi", - "framework-statsd-stubs-srcs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-statsd.api.system.latest", - removed_api_file: ":framework-statsd-removed.api.system.latest", - }, - api_lint: { - new_since: ":framework-statsd.api.system.latest", - }, - }, -} - -droidstubs { - name: "framework-statsd-api-module_libs_api", - defaults: [ - "framework-module-api-defaults-module_libs_api", - "framework-statsd-stubs-srcs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-statsd.api.module-lib.latest", - removed_api_file: ":framework-statsd-removed.api.module-lib.latest", - }, - api_lint: { - new_since: ":framework-statsd.api.module-lib.latest", - }, - }, -} - -droidstubs { - name: "framework-statsd-stubs-srcs-module_libs_api", - defaults: [ - "framework-module-stubs-defaults-module_libs_api", - "framework-statsd-stubs-srcs-defaults", - ], -} - -java_library { - name: "framework-statsd-stubs-publicapi", - defaults: ["framework-module-stubs-lib-defaults-publicapi"], - srcs: [ ":framework-statsd-stubs-srcs-publicapi" ], - visibility: [ - "//frameworks/base", // Framework - "//frameworks/base/apex/statsd", // statsd apex - ], - dist: { dest: "framework-statsd.jar" }, -} - -java_library { - name: "framework-statsd-stubs-systemapi", - defaults: ["framework-module-stubs-lib-defaults-systemapi"], - srcs: [ ":framework-statsd-stubs-srcs-systemapi" ], - visibility: [ - "//frameworks/base", // Framework - "//frameworks/base/apex/statsd", // statsd apex - ], - dist: { dest: "framework-statsd.jar" }, -} - -java_library { - name: "framework-statsd-stubs-module_libs_api", - defaults: ["framework-module-stubs-lib-defaults-module_libs_api"], - srcs: [ ":framework-statsd-stubs-srcs-module_libs_api" ], - visibility: [ + stubs_library_visibility: [ "//frameworks/base", // Framework "//frameworks/base/apex/statsd", // statsd apex "//frameworks/opt/net/wifi/service", // wifi service "//packages/providers/MediaProvider", // MediaProvider apk ], - dist: { dest: "framework-statsd.jar" }, + apex_available: [ + "com.android.os.statsd", + "test_com.android.os.statsd", + ], } android_test { diff --git a/api/test-current.txt b/api/test-current.txt index 5dc7bdb9a940..a163dea35755 100644 --- a/api/test-current.txt +++ b/api/test-current.txt @@ -1728,6 +1728,15 @@ package android.media.audiopolicy { } +package android.media.tv { + + public final class TvInputManager { + method public void addHardwareDevice(int); + method public void removeHardwareDevice(int); + } + +} + package android.metrics { public class LogMaker { diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp index ecb95bd11c2f..3bcabe56f89e 100644 --- a/cmds/bootanimation/BootAnimation.cpp +++ b/cmds/bootanimation/BootAnimation.cpp @@ -48,6 +48,7 @@ #include <ui/Region.h> #include <gui/ISurfaceComposer.h> +#include <gui/DisplayEventReceiver.h> #include <gui/Surface.h> #include <gui/SurfaceComposerClient.h> @@ -113,8 +114,8 @@ static constexpr size_t TEXT_POS_LEN_MAX = 16; // --------------------------------------------------------------------------- BootAnimation::BootAnimation(sp<Callbacks> callbacks) - : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), - mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) { + : Thread(false), mClockEnabled(true), mTimeIsAccurate(false), mTimeFormat12Hour(false), + mTimeCheckThread(nullptr), mCallbacks(callbacks), mLooper(new Looper(false)) { mSession = new SurfaceComposerClient(); std::string powerCtl = android::base::GetProperty("sys.powerctl", ""); @@ -154,8 +155,7 @@ sp<SurfaceComposerClient> BootAnimation::session() const { return mSession; } -void BootAnimation::binderDied(const wp<IBinder>&) -{ +void BootAnimation::binderDied(const wp<IBinder>&) { // woah, surfaceflinger died! SLOGD("SurfaceFlinger died, exiting..."); @@ -219,8 +219,7 @@ status_t BootAnimation::initTexture(Texture* texture, AssetManager& assets, return NO_ERROR; } -status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) -{ +status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) { SkBitmap bitmap; sk_sp<SkData> data = SkData::MakeWithoutCopy(map->getDataPtr(), map->getDataLength()); @@ -278,6 +277,78 @@ status_t BootAnimation::initTexture(FileMap* map, int* width, int* height) return NO_ERROR; } +class BootAnimation::DisplayEventCallback : public LooperCallback { + BootAnimation* mBootAnimation; + +public: + DisplayEventCallback(BootAnimation* bootAnimation) { + mBootAnimation = bootAnimation; + } + + int handleEvent(int /* fd */, int events, void* /* data */) { + if (events & (Looper::EVENT_ERROR | Looper::EVENT_HANGUP)) { + ALOGE("Display event receiver pipe was closed or an error occurred. events=0x%x", + events); + return 0; // remove the callback + } + + if (!(events & Looper::EVENT_INPUT)) { + ALOGW("Received spurious callback for unhandled poll event. events=0x%x", events); + return 1; // keep the callback + } + + constexpr int kBufferSize = 100; + DisplayEventReceiver::Event buffer[kBufferSize]; + ssize_t numEvents; + do { + numEvents = mBootAnimation->mDisplayEventReceiver->getEvents(buffer, kBufferSize); + for (size_t i = 0; i < static_cast<size_t>(numEvents); i++) { + const auto& event = buffer[i]; + if (event.header.type == DisplayEventReceiver::DISPLAY_EVENT_HOTPLUG) { + SLOGV("Hotplug received"); + + if (!event.hotplug.connected) { + // ignore hotplug disconnect + continue; + } + auto token = SurfaceComposerClient::getPhysicalDisplayToken( + event.header.displayId); + + if (token != mBootAnimation->mDisplayToken) { + // ignore hotplug of a secondary display + continue; + } + + DisplayConfig displayConfig; + const status_t error = SurfaceComposerClient::getActiveDisplayConfig( + mBootAnimation->mDisplayToken, &displayConfig); + if (error != NO_ERROR) { + SLOGE("Can't get active display configuration."); + } + mBootAnimation->resizeSurface(displayConfig.resolution.getWidth(), + displayConfig.resolution.getHeight()); + } + } + } while (numEvents > 0); + + return 1; // keep the callback + } +}; + +EGLConfig BootAnimation::getEglConfig(const EGLDisplay& display) { + const EGLint attribs[] = { + EGL_RED_SIZE, 8, + EGL_GREEN_SIZE, 8, + EGL_BLUE_SIZE, 8, + EGL_DEPTH_SIZE, 0, + EGL_NONE + }; + EGLint numConfigs; + EGLConfig config; + eglChooseConfig(display, attribs, &config, 1, &numConfigs); + return config; +} + status_t BootAnimation::readyToRun() { mAssets.addDefaultAssets(); @@ -346,25 +417,12 @@ status_t BootAnimation::readyToRun() { sp<Surface> s = control->getSurface(); // initialize opengl and egl - const EGLint attribs[] = { - EGL_RED_SIZE, 8, - EGL_GREEN_SIZE, 8, - EGL_BLUE_SIZE, 8, - EGL_DEPTH_SIZE, 0, - EGL_NONE - }; - EGLint w, h; - EGLint numConfigs; - EGLConfig config; - EGLSurface surface; - EGLContext context; - EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY); - eglInitialize(display, nullptr, nullptr); - eglChooseConfig(display, attribs, &config, 1, &numConfigs); - surface = eglCreateWindowSurface(display, config, s.get(), nullptr); - context = eglCreateContext(display, config, nullptr, nullptr); + EGLConfig config = getEglConfig(display); + EGLSurface surface = eglCreateWindowSurface(display, config, s.get(), nullptr); + EGLContext context = eglCreateContext(display, config, nullptr, nullptr); + EGLint w, h; eglQuerySurface(display, surface, EGL_WIDTH, &w); eglQuerySurface(display, surface, EGL_HEIGHT, &h); @@ -380,9 +438,46 @@ status_t BootAnimation::readyToRun() { mFlingerSurface = s; mTargetInset = -1; + // Register a display event receiver + mDisplayEventReceiver = std::make_unique<DisplayEventReceiver>(); + status_t status = mDisplayEventReceiver->initCheck(); + SLOGE_IF(status != NO_ERROR, "Initialization of DisplayEventReceiver failed with status: %d", + status); + mLooper->addFd(mDisplayEventReceiver->getFd(), 0, Looper::EVENT_INPUT, + new DisplayEventCallback(this), nullptr); + return NO_ERROR; } +void BootAnimation::resizeSurface(int newWidth, int newHeight) { + // We assume this function is called on the animation thread. + if (newWidth == mWidth && newHeight == mHeight) { + return; + } + SLOGV("Resizing the boot animation surface to %d %d", newWidth, newHeight); + + eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); + eglDestroySurface(mDisplay, mSurface); + + mWidth = newWidth; + mHeight = newHeight; + + SurfaceComposerClient::Transaction t; + t.setSize(mFlingerSurfaceControl, mWidth, mHeight); + t.apply(); + + EGLConfig config = getEglConfig(mDisplay); + EGLSurface surface = eglCreateWindowSurface(mDisplay, config, mFlingerSurface.get(), nullptr); + if (eglMakeCurrent(mDisplay, surface, surface, mContext) == EGL_FALSE) { + SLOGE("Can't make the new surface current. Error %d", eglGetError()); + return; + } + glViewport(0, 0, mWidth, mHeight); + glScissor(0, 0, mWidth, mHeight); + + mSurface = surface; +} + bool BootAnimation::preloadAnimation() { findBootAnimationFile(); if (!mZipFileName.isEmpty()) { @@ -443,15 +538,14 @@ void BootAnimation::findBootAnimationFile() { } } -bool BootAnimation::threadLoop() -{ - bool r; +bool BootAnimation::threadLoop() { + bool result; // We have no bootanimation file, so we use the stock android logo // animation. if (mZipFileName.isEmpty()) { - r = android(); + result = android(); } else { - r = movie(); + result = movie(); } eglMakeCurrent(mDisplay, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); @@ -462,11 +556,10 @@ bool BootAnimation::threadLoop() eglTerminate(mDisplay); eglReleaseThread(); IPCThreadState::self()->stopProcess(); - return r; + return result; } -bool BootAnimation::android() -{ +bool BootAnimation::android() { SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); initTexture(&mAndroid[0], mAssets, "images/android-logo-mask.png"); @@ -485,19 +578,19 @@ bool BootAnimation::android() glEnable(GL_TEXTURE_2D); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); - const GLint xc = (mWidth - mAndroid[0].w) / 2; - const GLint yc = (mHeight - mAndroid[0].h) / 2; - const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h); - - glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), - updateRect.height()); - // Blend state glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTexEnvx(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); const nsecs_t startTime = systemTime(); do { + processDisplayEvents(); + const GLint xc = (mWidth - mAndroid[0].w) / 2; + const GLint yc = (mHeight - mAndroid[0].h) / 2; + const Rect updateRect(xc, yc, xc + mAndroid[0].w, yc + mAndroid[0].h); + glScissor(updateRect.left, mHeight - updateRect.bottom, updateRect.width(), + updateRect.height()); + nsecs_t now = systemTime(); double time = now - startTime; float t = 4.0f * float(time / us2ns(16667)) / mAndroid[1].w; @@ -612,8 +705,7 @@ static bool parseColor(const char str[7], float color[3]) { } -static bool readFile(ZipFileRO* zip, const char* name, String8& outString) -{ +static bool readFile(ZipFileRO* zip, const char* name, String8& outString) { ZipEntryRO entry = zip->findEntryByName(name); SLOGE_IF(!entry, "couldn't find %s", name); if (!entry) { @@ -734,8 +826,7 @@ void BootAnimation::drawClock(const Font& font, const int xPos, const int yPos) drawText(out, font, false, &x, &y); } -bool BootAnimation::parseAnimationDesc(Animation& animation) -{ +bool BootAnimation::parseAnimationDesc(Animation& animation) { String8 desString; if (!readFile(animation.zip, "desc.txt", desString)) { @@ -802,8 +893,7 @@ bool BootAnimation::parseAnimationDesc(Animation& animation) return true; } -bool BootAnimation::preloadZip(Animation& animation) -{ +bool BootAnimation::preloadZip(Animation& animation) { // read all the data structures const size_t pcount = animation.parts.size(); void *cookie = nullptr; @@ -900,8 +990,7 @@ bool BootAnimation::preloadZip(Animation& animation) return true; } -bool BootAnimation::movie() -{ +bool BootAnimation::movie() { if (mAnimation == nullptr) { mAnimation = loadAnimation(mZipFileName); } @@ -987,12 +1076,9 @@ bool BootAnimation::movie() return false; } -bool BootAnimation::playAnimation(const Animation& animation) -{ +bool BootAnimation::playAnimation(const Animation& animation) { const size_t pcount = animation.parts.size(); nsecs_t frameDuration = s2ns(1) / animation.fps; - const int animationX = (mWidth - animation.width) / 2; - const int animationY = (mHeight - animation.height) / 2; SLOGD("%sAnimationShownTiming start time: %" PRId64 "ms", mShuttingDown ? "Shutdown" : "Boot", elapsedRealtime()); @@ -1023,6 +1109,11 @@ bool BootAnimation::playAnimation(const Animation& animation) 1.0f); for (size_t j=0 ; j<fcount && (!exitPending() || part.playUntilComplete) ; j++) { + processDisplayEvents(); + + const int animationX = (mWidth - animation.width) / 2; + const int animationY = (mHeight - animation.height) / 2; + const Animation::Frame& frame(part.frames[j]); nsecs_t lastFrame = systemTime(); @@ -1106,6 +1197,12 @@ bool BootAnimation::playAnimation(const Animation& animation) return true; } +void BootAnimation::processDisplayEvents() { + // This will poll mDisplayEventReceiver and if there are new events it'll call + // displayEventCallback synchronously. + mLooper->pollOnce(0); +} + void BootAnimation::handleViewport(nsecs_t timestep) { if (mShuttingDown || !mFlingerSurfaceControl || mTargetInset == 0) { return; @@ -1148,8 +1245,7 @@ void BootAnimation::handleViewport(nsecs_t timestep) { mCurrentInset += delta; } -void BootAnimation::releaseAnimation(Animation* animation) const -{ +void BootAnimation::releaseAnimation(Animation* animation) const { for (Vector<Animation::Part>::iterator it = animation->parts.begin(), e = animation->parts.end(); it != e; ++it) { if (it->animation) @@ -1160,8 +1256,7 @@ void BootAnimation::releaseAnimation(Animation* animation) const delete animation; } -BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) -{ +BootAnimation::Animation* BootAnimation::loadAnimation(const String8& fn) { if (mLoadedFiles.indexOf(fn) >= 0) { SLOGE("File \"%s\" is already loaded. Cyclic ref is not allowed", fn.string()); @@ -1323,5 +1418,4 @@ status_t BootAnimation::TimeCheckThread::readyToRun() { // --------------------------------------------------------------------------- -} -; // namespace android +} // namespace android diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h index 574d65e425cf..36cd91bdee0d 100644 --- a/cmds/bootanimation/BootAnimation.h +++ b/cmds/bootanimation/BootAnimation.h @@ -18,11 +18,14 @@ #define ANDROID_BOOTANIMATION_H #include <vector> +#include <queue> #include <stdint.h> #include <sys/types.h> #include <androidfw/AssetManager.h> +#include <gui/DisplayEventReceiver.h> +#include <utils/Looper.h> #include <utils/Thread.h> #include <binder/IBinder.h> @@ -145,6 +148,11 @@ private: BootAnimation* mBootAnimation; }; + // Display event handling + class DisplayEventCallback; + int displayEventCallback(int fd, int events, void* data); + void processDisplayEvents(); + status_t initTexture(Texture* texture, AssetManager& asset, const char* name); status_t initTexture(FileMap* map, int* width, int* height); status_t initFont(Font* font, const char* fallback); @@ -161,6 +169,8 @@ private: void findBootAnimationFile(); bool findBootAnimationFileInternal(const std::vector<std::string>& files); bool preloadAnimation(); + EGLConfig getEglConfig(const EGLDisplay&); + void resizeSurface(int newWidth, int newHeight); void checkExit(); @@ -189,6 +199,8 @@ private: sp<TimeCheckThread> mTimeCheckThread = nullptr; sp<Callbacks> mCallbacks; Animation* mAnimation = nullptr; + std::unique_ptr<DisplayEventReceiver> mDisplayEventReceiver; + sp<Looper> mLooper; }; // --------------------------------------------------------------------------- diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index f30ed17c392f..3dbe41395024 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -292,6 +292,7 @@ cc_test { name: "statsd_test", defaults: ["statsd_defaults"], test_suites: ["device-tests", "mts"], + test_config: "statsd_test.xml", //TODO(b/153588990): Remove when the build system properly separates //32bit and 64bit architectures. @@ -299,7 +300,10 @@ cc_test { multilib: { lib64: { suffix: "64", - } + }, + lib32: { + suffix: "32", + }, }, cflags: [ diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 4ffa040fafd4..47bab2947aaf 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1298,7 +1298,6 @@ Status StatsService::getRegisteredExperimentIds(std::vector<int64_t>* experiment return Status::ok(); } - void StatsService::statsCompanionServiceDied(void* cookie) { auto thiz = static_cast<StatsService*>(cookie); thiz->statsCompanionServiceDiedImpl(); diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto index c6e9e01cc0d7..62e156767cb4 100644 --- a/cmds/statsd/src/atoms.proto +++ b/cmds/statsd/src/atoms.proto @@ -6713,11 +6713,11 @@ message NetworkDnsEventReported { * Logs when a data stall event occurs. * * Log from: - * frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java + * packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java */ message DataStallEvent { // Data stall evaluation type. - // See frameworks/base/services/core/java/com/android/server/connectivity/NetworkMonitor.java + // See packages/modules/NetworkStack/src/com/android/server/connectivity/NetworkMonitor.java // Refer to the definition of DATA_STALL_EVALUATION_TYPE_*. optional int32 evaluation_type = 1; // See definition in data_stall_event.proto. @@ -6730,6 +6730,10 @@ message DataStallEvent { optional com.android.server.connectivity.CellularData cell_info = 5 [(log_mode) = MODE_BYTES]; // See definition in data_stall_event.proto. optional com.android.server.connectivity.DnsEvent dns_event = 6 [(log_mode) = MODE_BYTES]; + // The tcp packets fail rate from the latest tcp polling. + optional int32 tcp_fail_rate = 7; + // Number of packets sent since the last received packet. + optional int32 tcp_sent_since_last_recv = 8; } /* diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h index e86fdf06e836..673f668cda82 100644 --- a/cmds/statsd/src/metrics/MetricProducer.h +++ b/cmds/statsd/src/metrics/MetricProducer.h @@ -82,7 +82,9 @@ enum BucketDropReason { DIMENSION_GUARDRAIL_REACHED = 6, MULTIPLE_BUCKETS_SKIPPED = 7, // Not an invalid bucket case, but the bucket is dropped. - BUCKET_TOO_SMALL = 8 + BUCKET_TOO_SMALL = 8, + // Not an invalid bucket case, but the bucket is skipped. + NO_DATA = 9 }; struct Activation { diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp index f03ce4550bc4..dbec24bf3f6c 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp +++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp @@ -108,7 +108,7 @@ ValueMetricProducer::ValueMetricProducer( mSkipZeroDiffOutput(metric.skip_zero_diff_output()), mUseZeroDefaultBase(metric.use_zero_default_base()), mHasGlobalBase(false), - mCurrentBucketIsInvalid(false), + mCurrentBucketIsSkipped(false), mMaxPullDelayNs(metric.max_pull_delay_sec() > 0 ? metric.max_pull_delay_sec() * NS_PER_SEC : StatsdStats::kPullMaxDelayNs), mSplitBucketForAppUpgrade(metric.split_bucket_for_app_upgrade()), @@ -383,15 +383,12 @@ void ValueMetricProducer::onDumpReportLocked(const int64_t dumpTimeNs, void ValueMetricProducer::invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs, const BucketDropReason reason) { - if (!mCurrentBucketIsInvalid) { + if (!mCurrentBucketIsSkipped) { // Only report to StatsdStats once per invalid bucket. StatsdStats::getInstance().noteInvalidatedBucket(mMetricId); } - if (!maxDropEventsReached()) { - mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason)); - } - mCurrentBucketIsInvalid = true; + skipCurrentBucket(dropTimeNs, reason); } void ValueMetricProducer::invalidateCurrentBucket(const int64_t dropTimeNs, @@ -400,6 +397,14 @@ void ValueMetricProducer::invalidateCurrentBucket(const int64_t dropTimeNs, resetBase(); } +void ValueMetricProducer::skipCurrentBucket(const int64_t dropTimeNs, + const BucketDropReason reason) { + if (!maxDropEventsReached()) { + mCurrentSkippedBucket.dropEvents.emplace_back(buildDropEvent(dropTimeNs, reason)); + } + mCurrentBucketIsSkipped = true; +} + void ValueMetricProducer::resetBase() { for (auto& slice : mCurrentBaseInfo) { for (auto& baseInfo : slice.second) { @@ -961,12 +966,10 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, int64_t conditionTrueDuration = mConditionTimer.newBucketStart(bucketEndTime); bool isBucketLargeEnough = bucketEndTime - mCurrentBucketStartTimeNs >= mMinBucketSizeNs; if (!isBucketLargeEnough) { - if (!maxDropEventsReached()) { - mCurrentSkippedBucket.dropEvents.emplace_back( - buildDropEvent(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL)); - } + skipCurrentBucket(eventTimeNs, BucketDropReason::BUCKET_TOO_SMALL); } - if (isBucketLargeEnough && !mCurrentBucketIsInvalid) { + bool bucketHasData = false; + if (!mCurrentBucketIsSkipped) { // The current bucket is large enough to keep. for (const auto& slice : mCurrentSlicedBucket) { ValueBucket bucket = buildPartialBucket(bucketEndTime, slice.second); @@ -975,14 +978,33 @@ void ValueMetricProducer::flushCurrentBucketLocked(const int64_t& eventTimeNs, if (bucket.valueIndex.size() > 0) { auto& bucketList = mPastBuckets[slice.first]; bucketList.push_back(bucket); + bucketHasData = true; } } - } else { + } + + if (!bucketHasData && !mCurrentBucketIsSkipped) { + skipCurrentBucket(eventTimeNs, BucketDropReason::NO_DATA); + } + + if (mCurrentBucketIsSkipped) { mCurrentSkippedBucket.bucketStartTimeNs = mCurrentBucketStartTimeNs; - mCurrentSkippedBucket.bucketEndTimeNs = bucketEndTime; + // Fill in the gap if we skipped multiple buckets. + mCurrentSkippedBucket.bucketEndTimeNs = + numBucketsForward > 1 ? nextBucketStartTimeNs : bucketEndTime; mSkippedBuckets.emplace_back(mCurrentSkippedBucket); } + // This means that the current bucket was not flushed before a forced bucket split. + if (bucketEndTime < nextBucketStartTimeNs && numBucketsForward <= 1) { + SkippedBucket bucketInGap; + bucketInGap.bucketStartTimeNs = bucketEndTime; + bucketInGap.bucketEndTimeNs = nextBucketStartTimeNs; + bucketInGap.dropEvents.emplace_back( + buildDropEvent(eventTimeNs, BucketDropReason::NO_DATA)); + mSkippedBuckets.emplace_back(bucketInGap); + } + appendToFullBucket(eventTimeNs, fullBucketEndTimeNs); initCurrentSlicedBucket(nextBucketStartTimeNs); // Update the condition timer again, in case we skipped buckets. @@ -1036,13 +1058,13 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) // TODO: remove mCurrentBaseInfo entries when obsolete } - mCurrentBucketIsInvalid = false; + mCurrentBucketIsSkipped = false; mCurrentSkippedBucket.reset(); // If we do not have a global base when the condition is true, // we will have incomplete bucket for the next bucket. if (mUseDiff && !mHasGlobalBase && mCondition) { - mCurrentBucketIsInvalid = false; + mCurrentBucketIsSkipped = false; } mCurrentBucketStartTimeNs = nextBucketStartTimeNs; VLOG("metric %lld: new bucket start time: %lld", (long long)mMetricId, @@ -1051,7 +1073,7 @@ void ValueMetricProducer::initCurrentSlicedBucket(int64_t nextBucketStartTimeNs) void ValueMetricProducer::appendToFullBucket(int64_t eventTimeNs, int64_t fullBucketEndTimeNs) { bool isFullBucketReached = eventTimeNs > fullBucketEndTimeNs; - if (mCurrentBucketIsInvalid) { + if (mCurrentBucketIsSkipped) { if (isFullBucketReached) { // If the bucket is invalid, we ignore the full bucket since it contains invalid data. mCurrentFullBucket.clear(); diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h index 751fef2bf2b1..bb4a66164860 100644 --- a/cmds/statsd/src/metrics/ValueMetricProducer.h +++ b/cmds/statsd/src/metrics/ValueMetricProducer.h @@ -144,6 +144,10 @@ private: void invalidateCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason); void invalidateCurrentBucketWithoutResetBase(const int64_t dropTimeNs, const BucketDropReason reason); + // Skips the current bucket without notifying StatsdStats of the skipped bucket. + // This should only be called from #flushCurrentBucketLocked. Otherwise, a future event that + // causes the bucket to be invalidated will not notify StatsdStats. + void skipCurrentBucket(const int64_t dropTimeNs, const BucketDropReason reason); const int mWhatMatcherIndex; @@ -250,11 +254,9 @@ private: // diff against. bool mHasGlobalBase; - // Invalid bucket. There was a problem in collecting data in the current bucket so we cannot - // trust any of the data in this bucket. - // - // For instance, one pull failed. - bool mCurrentBucketIsInvalid; + // This is to track whether or not the bucket is skipped for any of the reasons listed in + // BucketDropReason, many of which make the bucket potentially invalid. + bool mCurrentBucketIsSkipped; const int64_t mMaxPullDelayNs; diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp index 361b161c76ac..fd883c29dba0 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.cpp +++ b/cmds/statsd/src/shell/ShellSubscriber.cpp @@ -41,13 +41,8 @@ void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) { { std::unique_lock<std::mutex> lock(mMutex); - if (myToken != mToken) { - // Some other subscription has already come in. Stop. - return; - } mSubscriptionInfo = mySubscriptionInfo; - - spawnHelperThreadsLocked(mySubscriptionInfo, myToken); + spawnHelperThread(myToken); waitForSubscriptionToEndLocked(mySubscriptionInfo, myToken, lock, timeoutSec); if (mSubscriptionInfo == mySubscriptionInfo) { @@ -57,14 +52,9 @@ void ShellSubscriber::startNewSubscription(int in, int out, int timeoutSec) { } } -void ShellSubscriber::spawnHelperThreadsLocked(shared_ptr<SubscriptionInfo> myInfo, int myToken) { - if (!myInfo->mPulledInfo.empty() && myInfo->mPullIntervalMin > 0) { - std::thread puller([this, myToken] { startPull(myToken); }); - puller.detach(); - } - - std::thread heartbeatSender([this, myToken] { sendHeartbeats(myToken); }); - heartbeatSender.detach(); +void ShellSubscriber::spawnHelperThread(int myToken) { + std::thread t([this, myToken] { pullAndSendHeartbeats(myToken); }); + t.detach(); } void ShellSubscriber::waitForSubscriptionToEndLocked(shared_ptr<SubscriptionInfo> myInfo, @@ -114,13 +104,7 @@ bool ShellSubscriber::readConfig(shared_ptr<SubscriptionInfo> subscriptionInfo) subscriptionInfo->mPushedMatchers.push_back(pushed); } - int minInterval = -1; for (const auto& pulled : config.pulled()) { - // All intervals need to be multiples of the min interval. - if (minInterval < 0 || pulled.freq_millis() < minInterval) { - minInterval = pulled.freq_millis(); - } - vector<string> packages; vector<int32_t> uids; for (const string& pkg : pulled.packages()) { @@ -136,18 +120,18 @@ bool ShellSubscriber::readConfig(shared_ptr<SubscriptionInfo> subscriptionInfo) uids); VLOG("adding matcher for pulled atom %d", pulled.matcher().atom_id()); } - subscriptionInfo->mPullIntervalMin = minInterval; return true; } -void ShellSubscriber::startPull(int myToken) { - VLOG("ShellSubscriber: pull thread %d starting", myToken); +void ShellSubscriber::pullAndSendHeartbeats(int myToken) { + VLOG("ShellSubscriber: helper thread %d starting", myToken); while (true) { + int64_t sleepTimeMs = INT_MAX; { std::lock_guard<std::mutex> lock(mMutex); if (!mSubscriptionInfo || mToken != myToken) { - VLOG("ShellSubscriber: pulling thread %d done!", myToken); + VLOG("ShellSubscriber: helper thread %d done!", myToken); return; } @@ -168,11 +152,27 @@ void ShellSubscriber::startPull(int myToken) { pullInfo.mPrevPullElapsedRealtimeMs = nowMillis; } + + // Send a heartbeat, consisting of a data size of 0, if perfd hasn't recently received + // data from statsd. When it receives the data size of 0, perfd will not expect any + // atoms and recheck whether the subscription should end. + if (nowMillis - mLastWriteMs > kMsBetweenHeartbeats) { + attemptWriteToPipeLocked(/*dataSize=*/0); + } + + // Determine how long to sleep before doing more work. + for (PullInfo& pullInfo : mSubscriptionInfo->mPulledInfo) { + int64_t nextPullTime = pullInfo.mPrevPullElapsedRealtimeMs + pullInfo.mInterval; + int64_t timeBeforePull = nextPullTime - nowMillis; // guaranteed to be non-negative + if (timeBeforePull < sleepTimeMs) sleepTimeMs = timeBeforePull; + } + int64_t timeBeforeHeartbeat = (mLastWriteMs + kMsBetweenHeartbeats) - nowMillis; + if (timeBeforeHeartbeat < sleepTimeMs) sleepTimeMs = timeBeforeHeartbeat; } - VLOG("ShellSubscriber: pulling thread %d sleeping for %d ms", myToken, - mSubscriptionInfo->mPullIntervalMin); - std::this_thread::sleep_for(std::chrono::milliseconds(mSubscriptionInfo->mPullIntervalMin)); + VLOG("ShellSubscriber: helper thread %d sleeping for %lld ms", myToken, + (long long)sleepTimeMs); + std::this_thread::sleep_for(std::chrono::milliseconds(sleepTimeMs)); } } @@ -200,7 +200,7 @@ void ShellSubscriber::writePulledAtomsLocked(const vector<std::shared_ptr<LogEve } } - if (count > 0) attemptWriteToSocketLocked(mProto.size()); + if (count > 0) attemptWriteToPipeLocked(mProto.size()); } void ShellSubscriber::onLogEvent(const LogEvent& event) { @@ -214,26 +214,24 @@ void ShellSubscriber::onLogEvent(const LogEvent& event) { util::FIELD_COUNT_REPEATED | FIELD_ID_ATOM); event.ToProto(mProto); mProto.end(atomToken); - attemptWriteToSocketLocked(mProto.size()); + attemptWriteToPipeLocked(mProto.size()); } } } -// Tries to write the atom encoded in mProto to the socket. If the write fails +// Tries to write the atom encoded in mProto to the pipe. If the write fails // because the read end of the pipe has closed, signals to other threads that // the subscription should end. -void ShellSubscriber::attemptWriteToSocketLocked(size_t dataSize) { - // First write the payload size. +void ShellSubscriber::attemptWriteToPipeLocked(size_t dataSize) { + // First, write the payload size. if (!android::base::WriteFully(mSubscriptionInfo->mOutputFd, &dataSize, sizeof(dataSize))) { mSubscriptionInfo->mClientAlive = false; mSubscriptionShouldEnd.notify_one(); return; } - if (dataSize == 0) return; - - // Then, write the payload. - if (!mProto.flush(mSubscriptionInfo->mOutputFd)) { + // Then, write the payload if this is not just a heartbeat. + if (dataSize > 0 && !mProto.flush(mSubscriptionInfo->mOutputFd)) { mSubscriptionInfo->mClientAlive = false; mSubscriptionShouldEnd.notify_one(); return; @@ -242,28 +240,6 @@ void ShellSubscriber::attemptWriteToSocketLocked(size_t dataSize) { mLastWriteMs = getElapsedRealtimeMillis(); } -// Send a heartbeat, consisting solely of a data size of 0, if perfd has not -// recently received any writes from statsd. When it receives the data size of -// 0, perfd will not expect any data and recheck whether the shell command is -// still running. -void ShellSubscriber::sendHeartbeats(int myToken) { - while (true) { - { - std::lock_guard<std::mutex> lock(mMutex); - if (!mSubscriptionInfo || myToken != mToken) { - VLOG("ShellSubscriber: heartbeat thread %d done!", myToken); - return; - } - - if (getElapsedRealtimeMillis() - mLastWriteMs > kMsBetweenHeartbeats) { - VLOG("ShellSubscriber: sending a heartbeat to perfd"); - attemptWriteToSocketLocked(/*dataSize=*/0); - } - } - std::this_thread::sleep_for(std::chrono::milliseconds(kMsBetweenHeartbeats)); - } -} - } // namespace statsd } // namespace os } // namespace android diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h index 26c8a2a0b683..4c05fa7f71c2 100644 --- a/cmds/statsd/src/shell/ShellSubscriber.h +++ b/cmds/statsd/src/shell/ShellSubscriber.h @@ -92,7 +92,6 @@ private: int mOutputFd; std::vector<SimpleAtomMatcher> mPushedMatchers; std::vector<PullInfo> mPulledInfo; - int mPullIntervalMin; bool mClientAlive; }; @@ -100,27 +99,25 @@ private: bool readConfig(std::shared_ptr<SubscriptionInfo> subscriptionInfo); - void spawnHelperThreadsLocked(std::shared_ptr<SubscriptionInfo> myInfo, int myToken); + void spawnHelperThread(int myToken); void waitForSubscriptionToEndLocked(std::shared_ptr<SubscriptionInfo> myInfo, int myToken, std::unique_lock<std::mutex>& lock, int timeoutSec); - void startPull(int myToken); + // Helper thread that pulls atoms at a regular frequency and sends + // heartbeats to perfd if statsd hasn't recently sent any data. Statsd must + // send heartbeats for perfd to escape a blocking read call and recheck if + // the user has terminated the subscription. + void pullAndSendHeartbeats(int myToken); void writePulledAtomsLocked(const vector<std::shared_ptr<LogEvent>>& data, const SimpleAtomMatcher& matcher); void getUidsForPullAtom(vector<int32_t>* uids, const PullInfo& pullInfo); - void attemptWriteToSocketLocked(size_t dataSize); - - // Send ocassional heartbeats for two reasons: (a) for statsd to detect when - // the read end of the pipe has closed and (b) for perfd to escape a - // blocking read call and recheck if the user has terminated the - // subscription. - void sendHeartbeats(int myToken); + void attemptWriteToPipeLocked(size_t dataSize); sp<UidMap> mUidMap; diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index 1121392f1db0..6bfa26761b2f 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -212,6 +212,8 @@ message StatsLogReport { MULTIPLE_BUCKETS_SKIPPED = 7; // Not an invalid bucket case, but the bucket is dropped. BUCKET_TOO_SMALL = 8; + // Not an invalid bucket case, but the bucket is skipped. + NO_DATA = 9; }; message DropEvent { diff --git a/cmds/statsd/statsd_test.xml b/cmds/statsd/statsd_test.xml new file mode 100644 index 000000000000..8f9bb1cb6b2a --- /dev/null +++ b/cmds/statsd/statsd_test.xml @@ -0,0 +1,37 @@ +<?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. +--> +<configuration description="Runs statsd_test."> + <option name="test-suite-tag" value="apct" /> + <option name="test-suite-tag" value="apct-native" /> + <option name="test-suite-tag" value="mts" /> + + <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.FilePusher"> + <option name="cleanup" value="true" /> + <option name="push" value="statsd_test->/data/local/tmp/statsd_test" /> + <option name="append-bitness" value="true" /> + </target_preparer> + + <test class="com.android.tradefed.testtype.GTest" > + <option name="native-test-device-path" value="/data/local/tmp" /> + <option name="module-name" value="statsd_test" /> + </test> + + <object type="module_controller" class="com.android.tradefed.testtype.suite.module.MainlineTestModuleController"> + <option name="mainline-module-package-name" value="com.google.android.os.statsd" /> + </object> +</configuration> diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 474aa2234837..14246cab0d96 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -1115,13 +1115,21 @@ TEST(ValueMetricProducerTest, TestBucketBoundaryNoCondition) { EXPECT_EQ(false, curInterval.hasValue); assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {12}, {bucketSizeNs}, {bucket2StartTimeNs}, {bucket3StartTimeNs}); + // The 1st bucket is dropped because of no data // The 3rd bucket is dropped due to multiple buckets being skipped. - ASSERT_EQ(1, valueProducer->mSkippedBuckets.size()); - EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs); - EXPECT_EQ(bucket4StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs); + ASSERT_EQ(2, valueProducer->mSkippedBuckets.size()); + + EXPECT_EQ(bucketStartTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs); + EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs); ASSERT_EQ(1, valueProducer->mSkippedBuckets[0].dropEvents.size()); - EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason); - EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs); + EXPECT_EQ(NO_DATA, valueProducer->mSkippedBuckets[0].dropEvents[0].reason); + EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].dropEvents[0].dropTimeNs); + + EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[1].bucketStartTimeNs); + EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].bucketEndTimeNs); + ASSERT_EQ(1, valueProducer->mSkippedBuckets[1].dropEvents.size()); + EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[1].dropEvents[0].reason); + EXPECT_EQ(bucket6StartTimeNs, valueProducer->mSkippedBuckets[1].dropEvents[0].dropTimeNs); } /* @@ -2214,7 +2222,7 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenGuardRailHit) { valueProducer->mCondition = ConditionState::kFalse; valueProducer->onConditionChanged(true, bucketStartTimeNs + 2); - EXPECT_EQ(true, valueProducer->mCurrentBucketIsInvalid); + EXPECT_EQ(true, valueProducer->mCurrentBucketIsSkipped); ASSERT_EQ(0UL, valueProducer->mCurrentSlicedBucket.size()); ASSERT_EQ(0UL, valueProducer->mSkippedBuckets.size()); @@ -2629,13 +2637,17 @@ TEST_P(ValueMetricProducerTest_PartialBucket, TestFullBucketResetWhenLastBucketI vector<shared_ptr<LogEvent>> allData; allData.push_back(CreateRepeatedValueLogEvent(tagId, bucket3StartTimeNs + 1, 4)); + // Pull fails and arrives late. valueProducer->onDataPulled(allData, /** fails */ false, bucket3StartTimeNs + 1); assertPastBucketValuesSingleKey(valueProducer->mPastBuckets, {9}, {partialBucketSplitTimeNs - bucketStartTimeNs}, {bucketStartTimeNs}, {partialBucketSplitTimeNs}); ASSERT_EQ(1, valueProducer->mSkippedBuckets.size()); + ASSERT_EQ(2, valueProducer->mSkippedBuckets[0].dropEvents.size()); + EXPECT_EQ(PULL_FAILED, valueProducer->mSkippedBuckets[0].dropEvents[0].reason); + EXPECT_EQ(MULTIPLE_BUCKETS_SKIPPED, valueProducer->mSkippedBuckets[0].dropEvents[1].reason); EXPECT_EQ(partialBucketSplitTimeNs, valueProducer->mSkippedBuckets[0].bucketStartTimeNs); - EXPECT_EQ(bucket2StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs); + EXPECT_EQ(bucket3StartTimeNs, valueProducer->mSkippedBuckets[0].bucketEndTimeNs); ASSERT_EQ(0UL, valueProducer->mCurrentFullBucket.size()); } @@ -3464,26 +3476,41 @@ TEST(ValueMetricProducerTest_BucketDrop, TestInvalidBucketWhenMultipleBucketsSki // Condition change event that skips forward by three buckets. valueProducer->onConditionChanged(false, bucket4StartTimeNs + 10); + int64_t dumpTimeNs = bucket4StartTimeNs + 1000; + // Check dump report. ProtoOutputStream output; std::set<string> strSet; - valueProducer->onDumpReport(bucket4StartTimeNs + 1000, true /* include recent buckets */, true, + valueProducer->onDumpReport(dumpTimeNs, true /* include current buckets */, true, NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output); StatsLogReport report = outputStreamToProto(&output); EXPECT_TRUE(report.has_value_metrics()); ASSERT_EQ(0, report.value_metrics().data_size()); - ASSERT_EQ(1, report.value_metrics().skipped_size()); + ASSERT_EQ(2, report.value_metrics().skipped_size()); EXPECT_EQ(NanoToMillis(bucketStartTimeNs), report.value_metrics().skipped(0).start_bucket_elapsed_millis()); - EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), + EXPECT_EQ(NanoToMillis(bucket4StartTimeNs), report.value_metrics().skipped(0).end_bucket_elapsed_millis()); ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); auto dropEvent = report.value_metrics().skipped(0).drop_event(0); EXPECT_EQ(BucketDropReason::MULTIPLE_BUCKETS_SKIPPED, dropEvent.drop_reason()); EXPECT_EQ(NanoToMillis(bucket4StartTimeNs + 10), dropEvent.drop_time_millis()); + + // This bucket is skipped because a dumpReport with include current buckets is called. + // This creates a new bucket from bucket4StartTimeNs to dumpTimeNs in which we have no data + // since the condition is false for the entire bucket interval. + EXPECT_EQ(NanoToMillis(bucket4StartTimeNs), + report.value_metrics().skipped(1).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(dumpTimeNs), + report.value_metrics().skipped(1).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size()); + + dropEvent = report.value_metrics().skipped(1).drop_event(0); + EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(dumpTimeNs), dropEvent.drop_time_millis()); } /* @@ -3544,6 +3571,89 @@ TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenBucketTooSmall) { } /* + * Test that NO_DATA dump reason is logged when a flushed bucket contains no data. + */ +TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenDataUnavailable) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + + // Check dump report. + ProtoOutputStream output; + std::set<string> strSet; + int64_t dumpReportTimeNs = bucketStartTimeNs + 10000000000; // 10 seconds + valueProducer->onDumpReport(dumpReportTimeNs, true /* include current bucket */, true, + NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_value_metrics()); + ASSERT_EQ(0, report.value_metrics().data_size()); + ASSERT_EQ(1, report.value_metrics().skipped_size()); + + EXPECT_EQ(NanoToMillis(bucketStartTimeNs), + report.value_metrics().skipped(0).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(dumpReportTimeNs), + report.value_metrics().skipped(0).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); + + auto dropEvent = report.value_metrics().skipped(0).drop_event(0); + EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(dumpReportTimeNs), dropEvent.drop_time_millis()); +} + +/* + * Test that a skipped bucket is logged when a forced bucket split occurs when the previous bucket + * was not flushed in time. + */ +TEST(ValueMetricProducerTest_BucketDrop, TestBucketDropWhenForceBucketSplitBeforeBucketFlush) { + ValueMetric metric = ValueMetricProducerTestHelper::createMetricWithCondition(); + + sp<MockStatsPullerManager> pullerManager = new StrictMock<MockStatsPullerManager>(); + + sp<ValueMetricProducer> valueProducer = + ValueMetricProducerTestHelper::createValueProducerWithCondition(pullerManager, metric); + + // App update event. + int64_t appUpdateTimeNs = bucket2StartTimeNs + 1000; + valueProducer->notifyAppUpgrade(appUpdateTimeNs); + + // Check dump report. + ProtoOutputStream output; + std::set<string> strSet; + int64_t dumpReportTimeNs = bucket2StartTimeNs + 10000000000; // 10 seconds + valueProducer->onDumpReport(dumpReportTimeNs, false /* include current buckets */, true, + NO_TIME_CONSTRAINTS /* dumpLatency */, &strSet, &output); + + StatsLogReport report = outputStreamToProto(&output); + EXPECT_TRUE(report.has_value_metrics()); + ASSERT_EQ(0, report.value_metrics().data_size()); + ASSERT_EQ(2, report.value_metrics().skipped_size()); + + EXPECT_EQ(NanoToMillis(bucketStartTimeNs), + report.value_metrics().skipped(0).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), + report.value_metrics().skipped(0).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(0).drop_event_size()); + + auto dropEvent = report.value_metrics().skipped(0).drop_event(0); + EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis()); + + EXPECT_EQ(NanoToMillis(bucket2StartTimeNs), + report.value_metrics().skipped(1).start_bucket_elapsed_millis()); + EXPECT_EQ(NanoToMillis(appUpdateTimeNs), + report.value_metrics().skipped(1).end_bucket_elapsed_millis()); + ASSERT_EQ(1, report.value_metrics().skipped(1).drop_event_size()); + + dropEvent = report.value_metrics().skipped(1).drop_event(0); + EXPECT_EQ(BucketDropReason::NO_DATA, dropEvent.drop_reason()); + EXPECT_EQ(NanoToMillis(appUpdateTimeNs), dropEvent.drop_time_millis()); +} + +/* * Test multiple bucket drop events in the same bucket. */ TEST(ValueMetricProducerTest_BucketDrop, TestMultipleBucketDropEvents) { diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java index af5fafbc93d4..87fc8fe392f0 100644 --- a/core/java/android/app/Activity.java +++ b/core/java/android/app/Activity.java @@ -2838,7 +2838,13 @@ public class Activity extends ContextThemeWrapper throw new IllegalStateException("Activity must be resumed to enter" + " picture-in-picture"); } - return ActivityTaskManager.getService().enterPictureInPictureMode(mToken, params); + // Set mIsInPictureInPictureMode earlier and don't wait for + // onPictureInPictureModeChanged callback here. This is to ensure that + // isInPictureInPictureMode returns true in the following onPause callback. + // See https://developer.android.com/guide/topics/ui/picture-in-picture for guidance. + mIsInPictureInPictureMode = ActivityTaskManager.getService().enterPictureInPictureMode( + mToken, params); + return mIsInPictureInPictureMode; } catch (RemoteException e) { return false; } diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java index 8e43ca3c6739..cffa59c06a53 100644 --- a/core/java/android/app/ActivityThread.java +++ b/core/java/android/app/ActivityThread.java @@ -604,11 +604,8 @@ public final class ActivityThread extends ClientTransactionHandler { throw new IllegalStateException( "Received config update for non-existing activity"); } - // Given alwaysReportChange=false because the configuration is from view root, the - // activity may not be able to handle the changes. In that case the activity will be - // relaunched immediately, then Activity#onConfigurationChanged shouldn't be called. activity.mMainThread.handleActivityConfigurationChanged(token, overrideConfig, - newDisplayId, false /* alwaysReportChange */); + newDisplayId); }; } @@ -4520,8 +4517,7 @@ public final class ActivityThread extends ClientTransactionHandler { // simply finishing, and we are not starting another activity. if (!r.activity.mFinished && willBeVisible && r.activity.mDecor != null && !r.hideForNow) { if (r.newConfig != null) { - performConfigurationChangedForActivity(r, r.newConfig, - false /* alwaysReportChange */); + performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) { Slog.v(TAG, "Resuming activity " + r.activityInfo.name + " with newConfig " + r.activity.mCurrentConfig); @@ -4841,8 +4837,7 @@ public final class ActivityThread extends ClientTransactionHandler { } } if (r.newConfig != null) { - performConfigurationChangedForActivity(r, r.newConfig, - false /* alwaysReportChange */); + performConfigurationChangedForActivity(r, r.newConfig); if (DEBUG_CONFIGURATION) Slog.v(TAG, "Updating activity vis " + r.activityInfo.name + " with new config " + r.activity.mCurrentConfig); @@ -5510,12 +5505,11 @@ public final class ActivityThread extends ClientTransactionHandler { * @param r ActivityClientRecord representing the Activity. * @param newBaseConfig The new configuration to use. This may be augmented with * {@link ActivityClientRecord#overrideConfig}. - * @param alwaysReportChange If the configuration is changed, always report to activity. */ private void performConfigurationChangedForActivity(ActivityClientRecord r, - Configuration newBaseConfig, boolean alwaysReportChange) { + Configuration newBaseConfig) { performConfigurationChangedForActivity(r, newBaseConfig, r.activity.getDisplayId(), - false /* movedToDifferentDisplay */, alwaysReportChange); + false /* movedToDifferentDisplay */); } /** @@ -5528,19 +5522,16 @@ public final class ActivityThread extends ClientTransactionHandler { * {@link ActivityClientRecord#overrideConfig}. * @param displayId The id of the display where the Activity currently resides. * @param movedToDifferentDisplay Indicates if the activity was moved to different display. - * @param alwaysReportChange If the configuration is changed, always report to activity. * @return {@link Configuration} instance sent to client, null if not sent. */ private Configuration performConfigurationChangedForActivity(ActivityClientRecord r, - Configuration newBaseConfig, int displayId, boolean movedToDifferentDisplay, - boolean alwaysReportChange) { + Configuration newBaseConfig, int displayId, boolean movedToDifferentDisplay) { r.tmpConfig.setTo(newBaseConfig); if (r.overrideConfig != null) { r.tmpConfig.updateFrom(r.overrideConfig); } final Configuration reportedConfig = performActivityConfigurationChanged(r.activity, - r.tmpConfig, r.overrideConfig, displayId, movedToDifferentDisplay, - alwaysReportChange); + r.tmpConfig, r.overrideConfig, displayId, movedToDifferentDisplay); freeTextLayoutCachesIfNeeded(r.activity.mCurrentConfig.diff(r.tmpConfig)); return reportedConfig; } @@ -5596,12 +5587,11 @@ public final class ActivityThread extends ClientTransactionHandler { * ActivityManager. * @param displayId Id of the display where activity currently resides. * @param movedToDifferentDisplay Indicates if the activity was moved to different display. - * @param alwaysReportChange If the configuration is changed, always report to activity. * @return Configuration sent to client, null if no changes and not moved to different display. */ private Configuration performActivityConfigurationChanged(Activity activity, Configuration newConfig, Configuration amOverrideConfig, int displayId, - boolean movedToDifferentDisplay, boolean alwaysReportChange) { + boolean movedToDifferentDisplay) { if (activity == null) { throw new IllegalArgumentException("No activity provided."); } @@ -5614,31 +5604,27 @@ public final class ActivityThread extends ClientTransactionHandler { // callback, see also PinnedStackTests#testConfigurationChangeOrderDuringTransition handleWindowingModeChangeIfNeeded(activity, newConfig); - boolean shouldChangeConfig = false; + boolean shouldReportChange = false; if (activity.mCurrentConfig == null) { - shouldChangeConfig = true; + shouldReportChange = true; } else { // If the new config is the same as the config this Activity is already running with and // the override config also didn't change, then don't bother calling // onConfigurationChanged. final int diff = activity.mCurrentConfig.diffPublicOnly(newConfig); - - if (diff != 0 || !mResourcesManager.isSameResourcesOverrideConfig(activityToken, + if (diff == 0 && !movedToDifferentDisplay + && mResourcesManager.isSameResourcesOverrideConfig(activityToken, amOverrideConfig)) { - // Always send the task-level config changes. For system-level configuration, if - // this activity doesn't handle any of the config changes, then don't bother - // calling onConfigurationChanged as we're going to destroy it. - if (alwaysReportChange - || (~activity.mActivityInfo.getRealConfigChanged() & diff) == 0 - || !REPORT_TO_ACTIVITY) { - shouldChangeConfig = true; - } + // Nothing significant, don't proceed with updating and reporting. + return null; + } else if ((~activity.mActivityInfo.getRealConfigChanged() & diff) == 0 + || !REPORT_TO_ACTIVITY) { + // If this activity doesn't handle any of the config changes, then don't bother + // calling onConfigurationChanged. Otherwise, report to the activity for the + // changes. + shouldReportChange = true; } } - if (!shouldChangeConfig && !movedToDifferentDisplay) { - // Nothing significant, don't proceed with updating and reporting. - return null; - } // Propagate the configuration change to ResourcesManager and Activity. @@ -5675,7 +5661,7 @@ public final class ActivityThread extends ClientTransactionHandler { activity.dispatchMovedToDisplay(displayId, configToReport); } - if (shouldChangeConfig) { + if (shouldReportChange) { activity.mCalled = false; activity.onConfigurationChanged(configToReport); if (!activity.mCalled) { @@ -5792,7 +5778,7 @@ public final class ActivityThread extends ClientTransactionHandler { // config and avoid onConfigurationChanged if it hasn't changed. Activity a = (Activity) cb; performConfigurationChangedForActivity(mActivities.get(a.getActivityToken()), - config, false /* alwaysReportChange */); + config); } else if (!equivalent) { performConfigurationChanged(cb, config); } else { @@ -5943,18 +5929,6 @@ public final class ActivityThread extends ClientTransactionHandler { } } - @Override - public void handleActivityConfigurationChanged(IBinder activityToken, - @NonNull Configuration overrideConfig, int displayId) { - handleActivityConfigurationChanged(activityToken, overrideConfig, displayId, - // This is the only place that uses alwaysReportChange=true. The entry point should - // be from ActivityConfigurationChangeItem or MoveToDisplayItem, so the server side - // has confirmed the activity should handle the configuration instead of relaunch. - // If Activity#onConfigurationChanged is called unexpectedly, then we can know it is - // something wrong from server side. - true /* alwaysReportChange */); - } - /** * Handle new activity configuration and/or move to a different display. This method is a noop * if {@link #updatePendingActivityConfiguration(IBinder, Configuration)} has been called with @@ -5964,10 +5938,10 @@ public final class ActivityThread extends ClientTransactionHandler { * @param overrideConfig Activity override config. * @param displayId Id of the display where activity was moved to, -1 if there was no move and * value didn't change. - * @param alwaysReportChange If the configuration is changed, always report to activity. */ - void handleActivityConfigurationChanged(IBinder activityToken, - @NonNull Configuration overrideConfig, int displayId, boolean alwaysReportChange) { + @Override + public void handleActivityConfigurationChanged(IBinder activityToken, + @NonNull Configuration overrideConfig, int displayId) { ActivityClientRecord r = mActivities.get(activityToken); // Check input params. if (r == null || r.activity == null) { @@ -6010,15 +5984,14 @@ public final class ActivityThread extends ClientTransactionHandler { + ", config=" + overrideConfig); final Configuration reportedConfig = performConfigurationChangedForActivity(r, - mCompatConfiguration, displayId, true /* movedToDifferentDisplay */, - alwaysReportChange); + mCompatConfiguration, displayId, true /* movedToDifferentDisplay */); if (viewRoot != null) { viewRoot.onMovedToDisplay(displayId, reportedConfig); } } else { if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handle activity config changed: " + r.activityInfo.name + ", config=" + overrideConfig); - performConfigurationChangedForActivity(r, mCompatConfiguration, alwaysReportChange); + performConfigurationChangedForActivity(r, mCompatConfiguration); } // Notify the ViewRootImpl instance about configuration changes. It may have initiated this // update to make sure that resources are updated before updating itself. diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index 90206b693772..e8ce92db62ad 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -3614,6 +3614,7 @@ public class Notification implements Parcelable * <li>Directional conversations where there is an active speaker and many passive * individuals</li> * <li>Stream / posting updates from other individuals</li> + * <li>Email, document comments, or other conversation types that are not real-time</li> * </ul> * </p> * diff --git a/core/java/android/app/PropertyInvalidatedCache.java b/core/java/android/app/PropertyInvalidatedCache.java index 01cf2b94a842..58068769e63a 100644 --- a/core/java/android/app/PropertyInvalidatedCache.java +++ b/core/java/android/app/PropertyInvalidatedCache.java @@ -188,6 +188,17 @@ public abstract class PropertyInvalidatedCache<Query, Result> { private static final boolean DEBUG = false; private static final boolean VERIFY = false; + // Per-Cache performance counters. As some cache instances are declared static, + @GuardedBy("mLock") + private long mHits = 0; + + @GuardedBy("mLock") + private long mMisses = 0; + + // Most invalidation is done in a static context, so the counters need to be accessible. + @GuardedBy("sCorkLock") + private static final HashMap<String, Long> sInvalidates = new HashMap<>(); + /** * If sEnabled is false then all cache operations are stubbed out. Set * it to false inside test processes. @@ -265,6 +276,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { }; synchronized (sCorkLock) { sCaches.put(this, null); + sInvalidates.put(propertyName, (long) 0); } } @@ -365,6 +377,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { synchronized (mLock) { if (currentNonce == mLastSeenNonce) { cachedResult = mCache.get(query); + + if (cachedResult != null) mHits++; } else { if (DEBUG) { Log.d(TAG, @@ -428,6 +442,7 @@ public abstract class PropertyInvalidatedCache<Query, Result> { if (mLastSeenNonce == currentNonce && result != null) { mCache.put(query, result); } + mMisses++; } return maybeCheckConsistency(query, result); } @@ -531,6 +546,8 @@ public abstract class PropertyInvalidatedCache<Query, Result> { newValueString)); } SystemProperties.set(name, newValueString); + long invalidateCount = sInvalidates.getOrDefault(name, (long) 0); + sInvalidates.put(name, ++invalidateCount); } /** @@ -758,8 +775,16 @@ public abstract class PropertyInvalidatedCache<Query, Result> { } private void dumpContents(PrintWriter pw, String[] args) { + long invalidateCount; + + synchronized (sCorkLock) { + invalidateCount = sInvalidates.getOrDefault(mPropertyName, (long) 0); + } + synchronized (mLock) { pw.println(String.format(" Cache Property Name: %s", cacheName())); + pw.println(String.format(" Hits: %d, Misses: %d, Invalidates: %d", + mHits, mMisses, invalidateCount)); pw.println(String.format(" Last Observed Nonce: %d", mLastSeenNonce)); pw.println(String.format(" Current Size: %d, Max Size: %d", mCache.entrySet().size(), mMaxEntries)); diff --git a/core/java/android/app/TEST_MAPPING b/core/java/android/app/TEST_MAPPING index ab868604dfde..8ad33dbf9f4a 100644 --- a/core/java/android/app/TEST_MAPPING +++ b/core/java/android/app/TEST_MAPPING @@ -50,7 +50,7 @@ "file_patterns": ["INotificationManager\\.aidl"] }, { - "name": "FrameworksInstantAppResolverTests", + "name": "CtsInstantAppTests", "file_patterns": ["(/|^)InstantAppResolve[^/]*"] } ], diff --git a/core/java/android/content/pm/ILauncherApps.aidl b/core/java/android/content/pm/ILauncherApps.aidl index aa290404c001..389458b64fc1 100644 --- a/core/java/android/content/pm/ILauncherApps.aidl +++ b/core/java/android/content/pm/ILauncherApps.aidl @@ -99,9 +99,9 @@ interface ILauncherApps { in IShortcutChangeCallback callback); void cacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, - in UserHandle user); + in UserHandle user, int cacheFlags); void uncacheShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, - in UserHandle user); + in UserHandle user, int cacheFlags); String getShortcutIconUri(String callingPackage, String packageName, String shortcutId, int userId); diff --git a/core/java/android/content/pm/LauncherApps.java b/core/java/android/content/pm/LauncherApps.java index 4299e805264c..bd1ee27ece9e 100644 --- a/core/java/android/content/pm/LauncherApps.java +++ b/core/java/android/content/pm/LauncherApps.java @@ -155,6 +155,26 @@ public class LauncherApps { public static final String EXTRA_PIN_ITEM_REQUEST = "android.content.pm.extra.PIN_ITEM_REQUEST"; + /** + * Cache shortcuts which are used in notifications. + * @hide + */ + public static final int FLAG_CACHE_NOTIFICATION_SHORTCUTS = 0; + + /** + * Cache shortcuts which are used in bubbles. + * @hide + */ + public static final int FLAG_CACHE_BUBBLE_SHORTCUTS = 1; + + /** @hide */ + @IntDef(flag = false, prefix = { "FLAG_CACHE_" }, value = { + FLAG_CACHE_NOTIFICATION_SHORTCUTS, + FLAG_CACHE_BUBBLE_SHORTCUTS, + }) + @Retention(RetentionPolicy.SOURCE) + public @interface ShortcutCacheFlags {} + private final Context mContext; @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private final ILauncherApps mService; @@ -1109,6 +1129,11 @@ public class LauncherApps { * @param packageName The target package name. * @param shortcutIds The IDs of the shortcut to be cached. * @param user The UserHandle of the profile. + * @param cacheFlags One of the values in: + * <ul> + * <li>{@link #FLAG_CACHE_NOTIFICATION_SHORTCUTS} + * <li>{@link #FLAG_CACHE_BUBBLE_SHORTCUTS} + * </ul> * @throws IllegalStateException when the user is locked, or when the {@code user} user * is locked or not running. * @@ -1118,10 +1143,11 @@ public class LauncherApps { */ @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public void cacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, - @NonNull UserHandle user) { + @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags) { logErrorForInvalidProfileAccess(user); try { - mService.cacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); + mService.cacheShortcuts( + mContext.getPackageName(), packageName, shortcutIds, user, cacheFlags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } @@ -1133,6 +1159,11 @@ public class LauncherApps { * @param packageName The target package name. * @param shortcutIds The IDs of the shortcut to be uncached. * @param user The UserHandle of the profile. + * @param cacheFlags One of the values in: + * <ul> + * <li>{@link #FLAG_CACHE_NOTIFICATION_SHORTCUTS} + * <li>{@link #FLAG_CACHE_BUBBLE_SHORTCUTS} + * </ul> * @throws IllegalStateException when the user is locked, or when the {@code user} user * is locked or not running. * @@ -1142,10 +1173,11 @@ public class LauncherApps { */ @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public void uncacheShortcuts(@NonNull String packageName, @NonNull List<String> shortcutIds, - @NonNull UserHandle user) { + @NonNull UserHandle user, @ShortcutCacheFlags int cacheFlags) { logErrorForInvalidProfileAccess(user); try { - mService.uncacheShortcuts(mContext.getPackageName(), packageName, shortcutIds, user); + mService.uncacheShortcuts( + mContext.getPackageName(), packageName, shortcutIds, user, cacheFlags); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java index 2f488cdc3158..c577d0e896b0 100644 --- a/core/java/android/content/pm/PackageManager.java +++ b/core/java/android/content/pm/PackageManager.java @@ -2032,8 +2032,16 @@ public abstract class PackageManager { /** * Feature for {@link #getSystemAvailableFeatures} and * {@link #hasSystemFeature}: The device's main front and back cameras can stream - * concurrently as described in {@link - * android.hardware.camera2.CameraManager#getConcurrentCameraIds()} + * concurrently as described in {@link + * android.hardware.camera2.CameraManager#getConcurrentCameraIds()}. + * </p> + * <p>While {@link android.hardware.camera2.CameraManager#getConcurrentCameraIds()} and + * associated APIs are only available on API level 30 or newer, this feature flag may be + * advertised by devices on API levels below 30. If present on such a device, the same + * guarantees hold: The main front and main back camera can be used at the same time, with + * guaranteed stream configurations as defined in the table for concurrent streaming at + * {@link android.hardware.camera2.CameraDevice#createCaptureSession(android.hardware.camera2.params.SessionConfiguration)}. + * </p> */ @SdkConstant(SdkConstantType.FEATURE) public static final String FEATURE_CAMERA_CONCURRENT = "android.hardware.camera.concurrent"; diff --git a/core/java/android/content/pm/ShortcutInfo.java b/core/java/android/content/pm/ShortcutInfo.java index dcc6cb25c95b..1b3c46f90851 100644 --- a/core/java/android/content/pm/ShortcutInfo.java +++ b/core/java/android/content/pm/ShortcutInfo.java @@ -119,12 +119,27 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public static final int FLAG_LONG_LIVED = 1 << 13; - /** @hide */ - public static final int FLAG_CACHED = 1 << 14; + /** + * TODO(b/155135057): This is a quick and temporary fix for b/155135890. ShortcutService doesn't + * need to be aware of the outside world. Replace this with a more extensible solution. + * @hide + */ + public static final int FLAG_CACHED_NOTIFICATIONS = 1 << 14; /** @hide */ public static final int FLAG_HAS_ICON_URI = 1 << 15; + + /** + * TODO(b/155135057): This is a quick and temporary fix for b/155135890. ShortcutService doesn't + * need to be aware of the outside world. Replace this with a more extensible solution. + * @hide + */ + public static final int FLAG_CACHED_BUBBLES = 1 << 30; + + /** @hide */ + public static final int FLAG_CACHED_ALL = FLAG_CACHED_NOTIFICATIONS | FLAG_CACHED_BUBBLES; + /** @hide */ @IntDef(flag = true, prefix = { "FLAG_" }, value = { FLAG_DYNAMIC, @@ -141,8 +156,9 @@ public final class ShortcutInfo implements Parcelable { FLAG_ICON_FILE_PENDING_SAVE, FLAG_SHADOW, FLAG_LONG_LIVED, - FLAG_CACHED, FLAG_HAS_ICON_URI, + FLAG_CACHED_NOTIFICATIONS, + FLAG_CACHED_BUBBLES, }) @Retention(RetentionPolicy.SOURCE) public @interface ShortcutFlags {} @@ -1707,13 +1723,13 @@ public final class ShortcutInfo implements Parcelable { } /** @hide */ - public void setCached() { - addFlags(FLAG_CACHED); + public void setCached(@ShortcutFlags int cacheFlag) { + addFlags(cacheFlag); } /** Return whether a shortcut is cached. */ public boolean isCached() { - return hasFlags(FLAG_CACHED); + return (getFlags() & FLAG_CACHED_ALL) != 0; } /** Return whether a shortcut is dynamic. */ @@ -1807,7 +1823,7 @@ public final class ShortcutInfo implements Parcelable { /** @hide */ public boolean isAlive() { return hasFlags(FLAG_PINNED) || hasFlags(FLAG_DYNAMIC) || hasFlags(FLAG_MANIFEST) - || hasFlags(FLAG_CACHED); + || isCached(); } /** @hide */ diff --git a/core/java/android/content/pm/ShortcutServiceInternal.java b/core/java/android/content/pm/ShortcutServiceInternal.java index eee91ce173dc..c62767ee031b 100644 --- a/core/java/android/content/pm/ShortcutServiceInternal.java +++ b/core/java/android/content/pm/ShortcutServiceInternal.java @@ -92,10 +92,10 @@ public abstract class ShortcutServiceInternal { public abstract void cacheShortcuts(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, - @NonNull List<String> shortcutIds, int userId); + @NonNull List<String> shortcutIds, int userId, int cacheFlags); public abstract void uncacheShortcuts(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, - @NonNull List<String> shortcutIds, int userId); + @NonNull List<String> shortcutIds, int userId, int cacheFlags); /** * Retrieves all of the direct share targets that match the given IntentFilter for the specified diff --git a/core/java/android/content/pm/TEST_MAPPING b/core/java/android/content/pm/TEST_MAPPING index 6f30ecd9b281..e404feea15b9 100644 --- a/core/java/android/content/pm/TEST_MAPPING +++ b/core/java/android/content/pm/TEST_MAPPING @@ -12,7 +12,7 @@ ], "presubmit": [ { - "name": "FrameworksInstantAppResolverTests", + "name": "CtsInstantAppTests", "file_patterns": ["(/|^)InstantApp[^/]*"] } ], diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java index 6bf754f6935e..0a76a9c6bee3 100644 --- a/core/java/android/hardware/SensorManager.java +++ b/core/java/android/hardware/SensorManager.java @@ -498,7 +498,7 @@ public abstract class SensorManager { || type == Sensor.TYPE_TILT_DETECTOR || type == Sensor.TYPE_WAKE_GESTURE || type == Sensor.TYPE_GLANCE_GESTURE || type == Sensor.TYPE_PICK_UP_GESTURE || type == Sensor.TYPE_WRIST_TILT_GESTURE - || type == Sensor.TYPE_DYNAMIC_SENSOR_META) { + || type == Sensor.TYPE_DYNAMIC_SENSOR_META || type == Sensor.TYPE_HINGE_ANGLE) { wakeUpSensor = true; } diff --git a/core/java/android/hardware/display/DisplayViewport.java b/core/java/android/hardware/display/DisplayViewport.java index 5adf948de348..f2d4c3d75919 100644 --- a/core/java/android/hardware/display/DisplayViewport.java +++ b/core/java/android/hardware/display/DisplayViewport.java @@ -49,6 +49,9 @@ public final class DisplayViewport { // True if this viewport is valid. public boolean valid; + // True if this viewport is active. + public boolean isActive; + // The logical display id. public int displayId; @@ -79,6 +82,7 @@ public final class DisplayViewport { public void copyFrom(DisplayViewport viewport) { valid = viewport.valid; + isActive = viewport.isActive; displayId = viewport.displayId; orientation = viewport.orientation; logicalFrame.set(viewport.logicalFrame); @@ -111,6 +115,7 @@ public final class DisplayViewport { DisplayViewport other = (DisplayViewport) o; return valid == other.valid + && isActive == other.isActive && displayId == other.displayId && orientation == other.orientation && logicalFrame.equals(other.logicalFrame) @@ -127,6 +132,7 @@ public final class DisplayViewport { final int prime = 31; int result = 1; result += prime * result + (valid ? 1 : 0); + result += prime * result + (isActive ? 1 : 0); result += prime * result + displayId; result += prime * result + orientation; result += prime * result + logicalFrame.hashCode(); @@ -147,6 +153,7 @@ public final class DisplayViewport { final Integer port = physicalPort == null ? null : Byte.toUnsignedInt(physicalPort); return "DisplayViewport{type=" + typeToString(type) + ", valid=" + valid + + ", isActive=" + isActive + ", displayId=" + displayId + ", uniqueId='" + uniqueId + "'" + ", physicalPort=" + port diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java index 9086d49231bb..275e38c74451 100644 --- a/core/java/android/net/ConnectivityDiagnosticsManager.java +++ b/core/java/android/net/ConnectivityDiagnosticsManager.java @@ -437,7 +437,7 @@ public class ConnectivityDiagnosticsManager { */ private long mReportTimestamp; - /** The detection method used to identify the suspected data stall */ + /** A bitmask of the detection methods used to identify the suspected data stall */ @DetectionMethod private final int mDetectionMethod; /** LinkProperties available on the Network at the reported timestamp */ @@ -499,9 +499,9 @@ public class ConnectivityDiagnosticsManager { } /** - * Returns the detection method used to identify this suspected data stall. + * Returns the bitmask of detection methods used to identify this suspected data stall. * - * @return The detection method used to identify the suspected data stall + * @return The bitmask of detection methods used to identify the suspected data stall */ public int getDetectionMethod() { return mDetectionMethod; diff --git a/core/java/android/net/Ikev2VpnProfile.java b/core/java/android/net/Ikev2VpnProfile.java index 836624beb3b2..407ff04dc4a3 100644 --- a/core/java/android/net/Ikev2VpnProfile.java +++ b/core/java/android/net/Ikev2VpnProfile.java @@ -101,6 +101,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { private final boolean mIsBypassable; // Defaults in builder private final boolean mIsMetered; // Defaults in builder private final int mMaxMtu; // Defaults in builder + private final boolean mIsRestrictedToTestNetworks; private Ikev2VpnProfile( int type, @@ -116,7 +117,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { @NonNull List<String> allowedAlgorithms, boolean isBypassable, boolean isMetered, - int maxMtu) { + int maxMtu, + boolean restrictToTestNetworks) { super(type); checkNotNull(serverAddr, MISSING_PARAM_MSG_TMPL, "Server address"); @@ -140,6 +142,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mIsBypassable = isBypassable; mIsMetered = isMetered; mMaxMtu = maxMtu; + mIsRestrictedToTestNetworks = restrictToTestNetworks; validate(); } @@ -329,6 +332,15 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { return mMaxMtu; } + /** + * Returns whether or not this VPN profile is restricted to test networks. + * + * @hide + */ + public boolean isRestrictedToTestNetworks() { + return mIsRestrictedToTestNetworks; + } + @Override public int hashCode() { return Objects.hash( @@ -345,7 +357,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mAllowedAlgorithms, mIsBypassable, mIsMetered, - mMaxMtu); + mMaxMtu, + mIsRestrictedToTestNetworks); } @Override @@ -368,7 +381,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { && Objects.equals(mAllowedAlgorithms, other.mAllowedAlgorithms) && mIsBypassable == other.mIsBypassable && mIsMetered == other.mIsMetered - && mMaxMtu == other.mMaxMtu; + && mMaxMtu == other.mMaxMtu + && mIsRestrictedToTestNetworks == other.mIsRestrictedToTestNetworks; } /** @@ -381,7 +395,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { */ @NonNull public VpnProfile toVpnProfile() throws IOException, GeneralSecurityException { - final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */); + final VpnProfile profile = new VpnProfile("" /* Key; value unused by IKEv2VpnProfile(s) */, + mIsRestrictedToTestNetworks); profile.type = mType; profile.server = mServerAddr; profile.ipsecIdentifier = mUserIdentity; @@ -449,6 +464,9 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { builder.setBypassable(profile.isBypassable); builder.setMetered(profile.isMetered); builder.setMaxMtu(profile.maxMtu); + if (profile.isRestrictedToTestNetworks) { + builder.restrictToTestNetworks(); + } switch (profile.type) { case TYPE_IKEV2_IPSEC_USER_PASS: @@ -621,6 +639,7 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { private boolean mIsBypassable = false; private boolean mIsMetered = true; private int mMaxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; + private boolean mIsRestrictedToTestNetworks = false; /** * Creates a new builder with the basic parameters of an IKEv2/IPsec VPN. @@ -842,6 +861,21 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { } /** + * Restricts this profile to use test networks (only). + * + * <p>This method is for testing only, and must not be used by apps. Calling + * provisionVpnProfile() with a profile where test-network usage is enabled will require the + * MANAGE_TEST_NETWORKS permission. + * + * @hide + */ + @NonNull + public Builder restrictToTestNetworks() { + mIsRestrictedToTestNetworks = true; + return this; + } + + /** * Validates, builds and provisions the VpnProfile. * * @throws IllegalArgumentException if any of the required keys or values were invalid @@ -862,7 +896,8 @@ public final class Ikev2VpnProfile extends PlatformVpnProfile { mAllowedAlgorithms, mIsBypassable, mIsMetered, - mMaxMtu); + mMaxMtu, + mIsRestrictedToTestNetworks); } } } diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java index b7fb280efdc4..34e48eb44f32 100644 --- a/core/java/android/net/NetworkStats.java +++ b/core/java/android/net/NetworkStats.java @@ -16,8 +16,6 @@ package android.net; -import static android.os.Process.CLAT_UID; - import android.annotation.IntDef; import android.annotation.NonNull; import android.annotation.Nullable; @@ -1047,73 +1045,54 @@ public final class NetworkStats implements Parcelable { } /** - * Calculate and apply adjustments to captured statistics for 464xlat traffic counted twice. + * Calculate and apply adjustments to captured statistics for 464xlat traffic. * - * <p>This mutates both base and stacked traffic stats, to account respectively for - * double-counted traffic and IPv4/IPv6 header size difference. + * <p>This mutates stacked traffic stats, to account for IPv4/IPv6 header size difference. * - * <p>For 464xlat traffic, xt_qtaguid sees every IPv4 packet twice, once as a native IPv4 - * packet on the stacked interface, and once as translated to an IPv6 packet on the - * base interface. For correct stats accounting on the base interface, if using xt_qtaguid, - * every rx 464xlat packet needs to be subtracted from the root UID on the base interface - * (http://b/12249687, http:/b/33681750), and every tx 464xlat packet which was counted onto - * clat uid should be ignored. + * <p>UID stats, which are only accounted on the stacked interface, need to be increased + * by 20 bytes/packet to account for translation overhead. * - * As for eBPF, the per uid stats is collected by different hook, the rx packets on base - * interface will not be counted. Thus, the adjustment on root uid is not needed. However, the - * tx traffic counted in the same way xt_qtaguid does, so the traffic on clat uid still - * needs to be ignored. + * <p>The potential additional overhead of 8 bytes/packet for ip fragments is ignored. + * + * <p>Interface stats need to sum traffic on both stacked and base interface because: + * - eBPF offloaded packets appear only on the stacked interface + * - Non-offloaded ingress packets appear only on the stacked interface + * (due to iptables raw PREROUTING drop rules) + * - Non-offloaded egress packets appear only on the stacked interface + * (due to ignoring traffic from clat daemon by uid match) + * (and of course the 20 bytes/packet overhead needs to be applied to stacked interface stats) * * <p>This method will behave fine if {@code stackedIfaces} is an non-synchronized but add-only * {@code ConcurrentHashMap} * @param baseTraffic Traffic on the base interfaces. Will be mutated. * @param stackedTraffic Stats with traffic stacked on top of our ifaces. Will also be mutated. * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. - * @param useBpfStats True if eBPF is in use. * @hide */ public static void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, Map<String, String> stackedIfaces, boolean useBpfStats) { - // Total 464xlat traffic to subtract from uid 0 on all base interfaces. - // stackedIfaces may grow afterwards, but NetworkStats will just be resized automatically. - final NetworkStats adjustments = new NetworkStats(0, stackedIfaces.size()); - + NetworkStats stackedTraffic, Map<String, String> stackedIfaces) { // For recycling Entry entry = null; - Entry adjust = new NetworkStats.Entry(IFACE_ALL, 0, 0, 0, 0, 0, 0, 0L, 0L, 0L, 0L, 0L); - for (int i = 0; i < stackedTraffic.size; i++) { entry = stackedTraffic.getValues(i, entry); - if (entry.iface == null || !entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) { - continue; - } - final String baseIface = stackedIfaces.get(entry.iface); - if (baseIface == null) { - continue; - } - // Subtract xt_qtaguid 464lat rx traffic seen for the root UID on the current base - // interface. As for eBPF, the per uid stats is collected by different hook, the rx - // packets on base interface will not be counted. - adjust.iface = baseIface; - if (!useBpfStats) { - adjust.rxBytes = -(entry.rxBytes + entry.rxPackets * IPV4V6_HEADER_DELTA); - adjust.rxPackets = -entry.rxPackets; - } - adjustments.combineValues(adjust); + if (entry == null) continue; + if (entry.iface == null) continue; + if (!entry.iface.startsWith(CLATD_INTERFACE_PREFIX)) continue; // For 464xlat traffic, per uid stats only counts the bytes of the native IPv4 packet // sent on the stacked interface with prefix "v4-" and drops the IPv6 header size after // unwrapping. To account correctly for on-the-wire traffic, add the 20 additional bytes // difference for all packets (http://b/12249687, http:/b/33681750). + // + // Note: this doesn't account for LRO/GRO/GSO/TSO (ie. >mtu) traffic correctly, nor + // does it correctly account for the 8 extra bytes in the IPv6 fragmentation header. + // + // While the ebpf code path does try to simulate proper post segmentation packet + // counts, we have nothing of the sort of xt_qtaguid stats. entry.rxBytes += entry.rxPackets * IPV4V6_HEADER_DELTA; entry.txBytes += entry.txPackets * IPV4V6_HEADER_DELTA; stackedTraffic.setValues(i, entry); } - - // Traffic on clat uid is v6 tx traffic that is already counted with app uid on the stacked - // v4 interface, so it needs to be removed to avoid double-counting. - baseTraffic.removeUids(new int[] {CLAT_UID}); - baseTraffic.combineAllValues(adjustments); } /** @@ -1125,8 +1104,8 @@ public final class NetworkStats implements Parcelable { * @param stackedIfaces Mapping ipv6if -> ipv4if interface where traffic is counted on both. * @hide */ - public void apply464xlatAdjustments(Map<String, String> stackedIfaces, boolean useBpfStats) { - apply464xlatAdjustments(this, this, stackedIfaces, useBpfStats); + public void apply464xlatAdjustments(Map<String, String> stackedIfaces) { + apply464xlatAdjustments(this, this, stackedIfaces); } /** diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java index ebf4cc5c938e..7845200f4bf7 100644 --- a/core/java/android/os/UserManager.java +++ b/core/java/android/os/UserManager.java @@ -230,13 +230,14 @@ public class UserManager { public static final String DISALLOW_MODIFY_ACCOUNTS = "no_modify_accounts"; /** - * Specifies if a user is disallowed from changing Wi-Fi - * access points. The default value is <code>false</code>. - * <p> - * Device owner and profile owner can set this restriction, although the restriction has no - * effect in a managed profile. When it is set by the profile owner of an organization-owned - * managed profile on the parent profile, it will disallow the personal user from changing - * Wi-Fi access points. + * Specifies if a user is disallowed from changing Wi-Fi access points via Settings. + * + * <p>A device owner and a profile owner can set this restriction, although the restriction has + * no effect in a managed profile. When it is set by a device owner, a profile owner on the + * primary user or by a profile owner of an organization-owned managed profile on the parent + * profile, it disallows the primary user from changing Wi-Fi access points. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -285,14 +286,16 @@ public class UserManager { /** * Specifies if a user is disallowed from turning on location sharing. - * The default value is <code>false</code>. - * <p> - * In a managed profile, location sharing always reflects the primary user's setting, but + * + * <p>In a managed profile, location sharing by default reflects the primary user's setting, but * can be overridden and forced off by setting this restriction to true in the managed profile. - * <p> - * Device owner and profile owner can set this restriction. When it is set by the profile - * owner of an organization-owned managed profile on the parent profile, it will prevent the - * user from turning on location sharing in the personal profile. + * + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, a profile owner on the primary user or by a profile owner of an organization-owned + * managed profile on the parent profile, it prevents the primary user from turning on + * location sharing. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -304,12 +307,13 @@ public class UserManager { /** * Specifies if airplane mode is disallowed on the device. - * <p> - * This restriction can only be set by the device owner, the profile owner on the primary user - * or the profile owner of an organization-owned managed profile on the parent profile, and it - * applies globally - i.e. it disables airplane mode on the entire device. - * <p> - * The default value is <code>false</code>. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by any of these owners, it applies globally - i.e., it disables airplane mode + * on the entire device. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -397,17 +401,18 @@ public class UserManager { "no_install_unknown_sources_globally"; /** - * Specifies if a user is disallowed from configuring bluetooth. - * This does <em>not</em> restrict the user from turning bluetooth on or off. - * The default value is <code>false</code>. - * <p> - * This restriction doesn't prevent the user from using bluetooth. For disallowing usage of + * Specifies if a user is disallowed from configuring bluetooth via Settings. This does + * <em>not</em> restrict the user from turning bluetooth on or off. + * + * <p>This restriction doesn't prevent the user from using bluetooth. For disallowing usage of * bluetooth completely on the device, use {@link #DISALLOW_BLUETOOTH}. - * <p> - * Device owner and profile owner can set this restriction, although the restriction has no - * effect in a managed profile. When it is set by the profile owner of an organization-owned - * managed profile on the parent profile, it will disallow the personal user from configuring - * bluetooth. + * + * <p>A device owner and a profile owner can set this restriction, although the restriction has + * no effect in a managed profile. When it is set by a device owner, a profile owner on the + * primary user or by a profile owner of an organization-owned managed profile on the parent + * profile, it disallows the primary user from configuring bluetooth. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -418,13 +423,19 @@ public class UserManager { public static final String DISALLOW_CONFIG_BLUETOOTH = "no_config_bluetooth"; /** - * Specifies if bluetooth is disallowed on the device. + * Specifies if bluetooth is disallowed on the device. If bluetooth is disallowed on the device, + * bluetooth cannot be turned on or configured via Settings. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally - i.e., it disables bluetooth on + * the entire device and all users will be affected. When it is set by a profile owner on the + * primary user or by a profile owner of an organization-owned managed profile on the parent + * profile, it disables the primary user from using bluetooth and configuring bluetooth + * in Settings. * - * <p> This restriction can only be set by the device owner, the profile owner on the - * primary user or the profile owner of an organization-owned managed profile on the - * parent profile and it applies globally - i.e. it disables bluetooth on the entire - * device. * <p>The default value is <code>false</code>. + * * <p>Key for user restrictions. * <p>Type: Boolean * @see DevicePolicyManager#addUserRestriction(ComponentName, String) @@ -434,14 +445,17 @@ public class UserManager { public static final String DISALLOW_BLUETOOTH = "no_bluetooth"; /** - * Specifies if outgoing bluetooth sharing is disallowed on the device. Device owner and profile - * owner can set this restriction. When it is set by device owner or the profile owner of an - * organization-owned managed profile on the parent profile, all users on this device will be - * affected. + * Specifies if outgoing bluetooth sharing is disallowed. + * + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, it applies globally. When it is set by a profile owner on the primary user or by a + * profile owner of an organization-owned managed profile on the parent profile, it disables + * the primary user from any outgoing bluetooth sharing. + * + * <p>Default is <code>true</code> for managed profiles and false otherwise. * - * <p>Default is <code>true</code> for managed profiles and false for otherwise. When a device - * upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it for all existing - * managed profiles. + * <p>When a device upgrades to {@link android.os.Build.VERSION_CODES#O}, the system sets it + * for all existing managed profiles. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -452,10 +466,17 @@ public class UserManager { public static final String DISALLOW_BLUETOOTH_SHARING = "no_bluetooth_sharing"; /** - * Specifies if a user is disallowed from transferring files over - * USB. This can only be set by device owners, profile owners on the primary user or - * profile owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * Specifies if a user is disallowed from transferring files over USB. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from transferring files over USB. No other + * user on the device is able to use file transfer over USB because the UI for file transfer + * is always associated with the primary user. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -512,13 +533,16 @@ public class UserManager { public static final String DISALLOW_REMOVE_MANAGED_PROFILE = "no_remove_managed_profile"; /** - * Specifies if a user is disallowed from enabling or accessing debugging features. When set on - * the primary user or by the profile owner of an organization-owned managed profile on the - * parent profile, disables debugging features altogether, including USB debugging. When set on - * a managed profile or a secondary user, blocks debugging for that user only, including - * starting activities, making service calls, accessing content providers, sending broadcasts, - * installing/uninstalling packages, clearing user data, etc. - * The default value is <code>false</code>. + * Specifies if a user is disallowed from enabling or accessing debugging features. + * + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, a profile owner on the primary user or by a profile owner of an organization-owned + * managed profile on the parent profile, it disables debugging features altogether, including + * USB debugging. When set on a managed profile or a secondary user, it blocks debugging for + * that user only, including starting activities, making service calls, accessing content + * providers, sending broadcasts, installing/uninstalling packages, clearing user data, etc. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -546,19 +570,18 @@ public class UserManager { /** * Specifies if a user is disallowed from enabling or disabling location providers. As a - * result, user is disallowed from turning on or off location. + * result, user is disallowed from turning on or off location via Settings. * - * <p> - * In a managed profile, location sharing is forced off when it is turned off on the primary - * user or by the profile owner of an organization-owned managed profile on the parent profile. - * The user can still turn off location sharing on a managed profile when the restriction is - * set by the profile owner on a managed profile. - * <p> - * This user restriction is different from {@link #DISALLOW_SHARE_LOCATION}, - * as the device owner or profile owner can still enable or disable location mode via + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, a profile owner on the primary user or by a profile owner of an organization-owned + * managed profile on the parent profile, it disallows the primary user from turning location + * on or off. + * + * <p>The default value is <code>false</code>. + * + * <p>This user restriction is different from {@link #DISALLOW_SHARE_LOCATION}, + * as a device owner or a profile owner can still enable or disable location mode via * {@link DevicePolicyManager#setLocationEnabled} when this restriction is on. - * <p> - * The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -570,15 +593,18 @@ public class UserManager { public static final String DISALLOW_CONFIG_LOCATION = "no_config_location"; /** - * Specifies if date, time and timezone configuring is disallowed. + * Specifies configuring date, time and timezone is disallowed via Settings. + * + * <p>A device owner and a profile owner can set this restriction, although the restriction has + * no effect in a managed profile. When it is set by a device owner or by a profile owner of an + * organization-owned managed profile on the parent profile, it applies globally - i.e., + * it disables date, time and timezone setting on the entire device and all users are affected. + * When it is set by a profile owner on the primary user, it disables the primary user + * from configuring date, time and timezone and disables all configuring of date, time and + * timezone in Settings. * - * <p>When restriction is set by device owners or profile owners of organization-owned - * managed profiles on the parent profile, it applies globally - i.e., it disables date, - * time and timezone setting on the entire device and all users will be affected. When it's set - * by profile owners, it's only applied to the managed user. * <p>The default value is <code>false</code>. * - * <p>This user restriction has no effect on managed profiles. * <p>Key for user restrictions. * <p>Type: Boolean * @see DevicePolicyManager#addUserRestriction(ComponentName, String) @@ -588,10 +614,18 @@ public class UserManager { public static final String DISALLOW_CONFIG_DATE_TIME = "no_config_date_time"; /** - * Specifies if a user is disallowed from configuring Tethering - * & portable hotspots. This can only be set by device owners, profile owners on the - * primary user or profile owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * Specifies if a user is disallowed from configuring Tethering and portable hotspots + * via Settings. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from using Tethering and hotspots and + * disables all configuring of Tethering and hotspots in Settings. + * + * <p>The default value is <code>false</code>. + * * <p>In Android 9.0 or higher, if tethering is enabled when this restriction is set, * tethering will be automatically turned off. * @@ -685,10 +719,16 @@ public class UserManager { public static final String ENSURE_VERIFY_APPS = "ensure_verify_apps"; /** - * Specifies if a user is disallowed from configuring cell - * broadcasts. This can only be set by device owners, profile owners on the primary user or - * profile owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * Specifies if a user is disallowed from configuring cell broadcasts. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from configuring cell broadcasts. + * + * <p>The default value is <code>false</code>. + * * <p>This restriction has no effect on secondary users and managed profiles since only the * primary user can configure cell broadcasts. * @@ -701,10 +741,16 @@ public class UserManager { public static final String DISALLOW_CONFIG_CELL_BROADCASTS = "no_config_cell_broadcasts"; /** - * Specifies if a user is disallowed from configuring mobile - * networks. This can only be set by device owners, profile owners on the primary user or - * profile owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * Specifies if a user is disallowed from configuring mobile networks. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from configuring mobile networks. + * + * <p>The default value is <code>false</code>. + * * <p>This restriction has no effect on secondary users and managed profiles since only the * primary user can configure mobile networks. * @@ -747,11 +793,14 @@ public class UserManager { /** * Specifies if a user is disallowed from mounting physical external media. - * <p> - * This restriction can only be set by the device owner, the profile owner on the primary user - * or the profile owner of an organization-owned managed profile on the parent profile. - * <p> - * The default value is <code>false</code>. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from mounting physical external media. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -764,13 +813,14 @@ public class UserManager { /** * Specifies if a user is disallowed from adjusting microphone volume. If set, the microphone * will be muted. - * <p> - * The default value is <code>false</code>. - * <p> - * Device owner and profile owner can set this restriction, although the restriction has no - * effect in a managed profile. When it is set by the profile owner of an organization-owned - * managed profile on the parent profile, it will disallow the personal user from adjusting the - * microphone volume. + * + * <p>A device owner and a profile owner can set this restriction, although the restriction has + * no effect in a managed profile. When it is set by a device owner, it applies globally. When + * it is set by a profile owner on the primary user or by a profile owner of an + * organization-owned managed profile on the parent profile, it will disallow the primary user + * from adjusting the microphone volume. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -800,13 +850,13 @@ public class UserManager { /** * Specifies that the user is not allowed to make outgoing phone calls. Emergency calls are * still permitted. - * <p> - * The default value is <code>false</code>. - * <p> - * Device owner and profile owner can set this restriction, although the restriction has no - * effect in a managed profile. When it is set by the profile owner of an organization-owned - * managed profile on the parent profile, it will disallow the personal user from making - * outgoing phone calls. + * + * <p>A device owner and a profile owner can set this restriction, although the restriction has + * no effect in a managed profile. When it is set by a device owner, a profile owner on the + * primary user or by a profile owner of an organization-owned managed profile on the parent + * profile, it disallows the primary user from making outgoing phone calls. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -817,12 +867,15 @@ public class UserManager { public static final String DISALLOW_OUTGOING_CALLS = "no_outgoing_calls"; /** - * Specifies that the user is not allowed to send or receive - * SMS messages. The default value is <code>false</code>. - * <p> - * Device owner and profile owner can set this restriction. When it is set by the - * profile owner of an organization-owned managed profile on the parent profile, - * it will disable SMS in the personal profile. + * Specifies that the user is not allowed to send or receive SMS messages. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from sending or receiving SMS messages. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -941,9 +994,15 @@ public class UserManager { /** * Specifies if the user is not allowed to reboot the device into safe boot mode. - * This can only be set by device owners, profile owners on the primary user or profile - * owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from rebooting the device into safe + * boot mode. + * + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -981,12 +1040,14 @@ public class UserManager { /** * Specifies if a user is not allowed to use the camera. - * <p> - * Device owner and profile owner can set this restriction. When the restriction is set by - * the device owner or the profile owner of an organization-owned managed profile on the - * parent profile, it is applied globally. - * <p> - * The default value is <code>false</code>. + * + * <p>A device owner and a profile owner can set this restriction. When it is set by a + * device owner, it applies globally - i.e., it disables the use of camera on the entire device + * and all users are affected. When it is set by a profile owner on the primary user or by a + * profile owner of an organization-owned managed profile on the parent profile, it disables + * the primary user from using camera. + * + * <p>The default value is <code>false</code>. * * @see DevicePolicyManager#addUserRestriction(ComponentName, String) * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) @@ -1006,9 +1067,15 @@ public class UserManager { public static final String DISALLOW_UNMUTE_DEVICE = "disallow_unmute_device"; /** - * Specifies if a user is not allowed to use cellular data when roaming. This can only be set by - * device owners or profile owners of organization-owned managed profiles on the parent profile. - * The default value is <code>false</code>. + * Specifies if a user is not allowed to use cellular data when roaming. + * + * <p>This restriction can only be set by a device owner, a profile owner on the primary + * user or a profile owner of an organization-owned managed profile on the parent profile. + * When it is set by a device owner, it applies globally. When it is set by a profile owner + * on the primary user or by a profile owner of an organization-owned managed profile on + * the parent profile, it disables the primary user from using cellular data when roaming. + * + * <p>The default value is <code>false</code>. * * @see DevicePolicyManager#addUserRestriction(ComponentName, String) * @see DevicePolicyManager#clearUserRestriction(ComponentName, String) @@ -1103,9 +1170,10 @@ public class UserManager { * Specifies if the contents of a user's screen is not allowed to be captured for artificial * intelligence purposes. * - * <p>Device owner and profile owner can set this restriction. When it is set by the - * device owner or the profile owner of an organization-owned managed profile on the parent - * profile, only the target user will be affected. + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, a profile owner on the primary user or by a profile owner of an organization-owned + * managed profile on the parent profile, it disables the primary user's screen from being + * captured for artificial intelligence purposes. * * <p>The default value is <code>false</code>. * @@ -1119,9 +1187,10 @@ public class UserManager { * Specifies if the current user is able to receive content suggestions for selections based on * the contents of their screen. * - * <p>Device owner and profile owner can set this restriction. When it is set by the - * device owner or the profile owner of an organization-owned managed profile on the parent - * profile, only the target user will be affected. + * <p>A device owner and a profile owner can set this restriction. When it is set by a device + * owner, a profile owner on the primary user or by a profile owner of an organization-owned + * managed profile on the parent profile, it disables the primary user from receiving content + * suggestions for selections based on the contents of their screen. * * <p>The default value is <code>false</code>. * @@ -1185,10 +1254,11 @@ public class UserManager { /** * Specifies whether the user is allowed to modify private DNS settings. * - * <p>The default value is <code>false</code>. + * <p>This restriction can only be set by a device owner or a profile owner of an + * organization-owned managed profile on the parent profile. When it is set by either of these + * owners, it applies globally. * - * <p>This user restriction can only be applied by the device owner or the profile owner - * of an organization-owned managed profile on the parent profile. + * <p>The default value is <code>false</code>. * * <p>Key for user restrictions. * <p>Type: Boolean @@ -2216,6 +2286,20 @@ public class UserManager { } }; + // Uses IS_USER_UNLOCKED_PROPERTY for invalidation as the APIs have the same dependencies. + private final PropertyInvalidatedCache<Integer, Boolean> mIsUserUnlockingOrUnlockedCache = + new PropertyInvalidatedCache<Integer, Boolean>( + 32, CACHE_KEY_IS_USER_UNLOCKED_PROPERTY) { + @Override + protected Boolean recompute(Integer query) { + try { + return mService.isUserUnlockingOrUnlocked(query); + } catch (RemoteException re) { + throw re.rethrowFromSystemServer(); + } + } + }; + /** {@hide} */ @UnsupportedAppUsage @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, @@ -2227,6 +2311,7 @@ public class UserManager { /** {@hide} */ public void disableIsUserUnlockedCache() { mIsUserUnlockedCache.disableLocal(); + mIsUserUnlockingOrUnlockedCache.disableLocal(); } /** {@hide} */ @@ -2263,11 +2348,7 @@ public class UserManager { @RequiresPermission(anyOf = {Manifest.permission.MANAGE_USERS, Manifest.permission.INTERACT_ACROSS_USERS}, conditional = true) public boolean isUserUnlockingOrUnlocked(@UserIdInt int userId) { - try { - return mService.isUserUnlockingOrUnlocked(userId); - } catch (RemoteException re) { - throw re.rethrowFromSystemServer(); - } + return mIsUserUnlockingOrUnlockedCache.query(userId); } /** @@ -4021,12 +4102,25 @@ public class UserManager { } /** - * Returns true if the user switcher should be shown, this will be if device supports multi-user - * and there are at least 2 users available that are not managed profiles. - * @hide + * Returns true if the user switcher should be shown. + * I.e., returns whether the user switcher is enabled and there is something actionable to show. + * * @return true if user switcher should be shown. + * @hide */ public boolean isUserSwitcherEnabled() { + return isUserSwitcherEnabled(false); + } + + /** + * Returns true if the user switcher should be shown. + * + * @param showEvenIfNotActionable value to return if the feature is enabled but there is nothing + * actionable for the user to do anyway + * @return true if user switcher should be shown. + * @hide + */ + public boolean isUserSwitcherEnabled(boolean showEvenIfNotActionable) { if (!supportsMultipleUsers()) { return false; } @@ -4037,15 +4131,26 @@ public class UserManager { if (isDeviceInDemoMode(mContext)) { return false; } - // If user disabled this feature, don't show switcher - final boolean userSwitcherEnabled = Settings.Global.getInt(mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, 1) != 0; - if (!userSwitcherEnabled) { + // Check the Settings.Global.USER_SWITCHER_ENABLED that the user can toggle on/off. + final boolean userSwitcherSettingOn = Settings.Global.getInt(mContext.getContentResolver(), + Settings.Global.USER_SWITCHER_ENABLED, + Resources.getSystem().getBoolean(R.bool.config_showUserSwitcherByDefault) ? 1 : 0) + != 0; + if (!userSwitcherSettingOn) { return false; } - List<UserInfo> users = getUsers(true); + + // The feature is enabled. But is it worth showing? + return showEvenIfNotActionable + || areThereUsersToWhichToSwitch() // There are switchable users. + || !hasUserRestriction(UserManager.DISALLOW_ADD_USER); // New users can be added. + } + + /** Returns whether there are any users (other than the current user) to which to switch. */ + private boolean areThereUsersToWhichToSwitch() { + final List<UserInfo> users = getUsers(true); if (users == null) { - return false; + return false; } int switchableUserCount = 0; for (UserInfo user : users) { @@ -4053,9 +4158,7 @@ public class UserManager { ++switchableUserCount; } } - final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class) - .getGuestUserDisabled(null); - return switchableUserCount > 1 || guestEnabled; + return switchableUserCount > 1; } /** diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index 25cb0400a38d..220ce22ded5c 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -19,6 +19,8 @@ package android.os.incremental; import android.content.pm.DataLoaderParamsParcel; import android.content.pm.IDataLoaderStatusListener; import android.os.incremental.IncrementalNewFileParams; +import android.os.incremental.IStorageHealthListener; +import android.os.incremental.StorageHealthCheckParams; /** @hide */ interface IIncrementalService { @@ -34,7 +36,10 @@ interface IIncrementalService { * Opens or creates a storage given a target path and data loader params. Returns the storage ID. */ int openStorage(in @utf8InCpp String path); - int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, in IDataLoaderStatusListener listener, int createMode); + int createStorage(in @utf8InCpp String path, in DataLoaderParamsParcel params, int createMode, + in IDataLoaderStatusListener statusListener, + in StorageHealthCheckParams healthCheckParams, + in IStorageHealthListener healthListener); int createLinkedStorage(in @utf8InCpp String path, int otherStorageId, int createMode); /** @@ -106,9 +111,9 @@ interface IIncrementalService { void deleteStorage(int storageId); /** - * Setting up native library directories and extract native libs onto a storage. + * Setting up native library directories and extract native libs onto a storage if needed. */ - boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi); + boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi, boolean extractNativeLibs); /** * Waits until all native library extraction is done for the storage diff --git a/core/java/android/os/incremental/IStorageHealthListener.aidl b/core/java/android/os/incremental/IStorageHealthListener.aidl new file mode 100644 index 000000000000..9f93ede5c9fc --- /dev/null +++ b/core/java/android/os/incremental/IStorageHealthListener.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.os.incremental; + +/** @hide */ +oneway interface IStorageHealthListener { + /** OK status, no pending reads. */ + const int HEALTH_STATUS_OK = 0; + /* Statuses depend on timeouts defined in StorageHealthCheckParams. */ + /** Pending reads detected, waiting for params.blockedTimeoutMs to confirm blocked state. */ + const int HEALTH_STATUS_READS_PENDING = 1; + /** There are reads pending for params.blockedTimeoutMs, waiting till + * params.unhealthyTimeoutMs to confirm unhealthy state. */ + const int HEALTH_STATUS_BLOCKED = 2; + /** There are reads pending for params.unhealthyTimeoutMs>, + * marking storage as unhealthy. */ + const int HEALTH_STATUS_UNHEALTHY = 3; + + /** Health status callback. */ + void onHealthStatus(in int storageId, in int status); +} diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java index 958c7fb4fc8d..863d86ef88c9 100644 --- a/core/java/android/os/incremental/IncrementalFileStorages.java +++ b/core/java/android/os/incremental/IncrementalFileStorages.java @@ -65,7 +65,9 @@ public final class IncrementalFileStorages { public static IncrementalFileStorages initialize(Context context, @NonNull File stageDir, @NonNull DataLoaderParams dataLoaderParams, - @Nullable IDataLoaderStatusListener dataLoaderStatusListener, + @Nullable IDataLoaderStatusListener statusListener, + @Nullable StorageHealthCheckParams healthCheckParams, + @Nullable IStorageHealthListener healthListener, List<InstallationFileParcel> addedFiles) throws IOException { // TODO(b/136132412): sanity check if session should not be incremental IncrementalManager incrementalManager = (IncrementalManager) context.getSystemService( @@ -75,9 +77,9 @@ public final class IncrementalFileStorages { throw new IOException("Failed to obtain incrementalManager."); } - final IncrementalFileStorages result = - new IncrementalFileStorages(stageDir, incrementalManager, dataLoaderParams, - dataLoaderStatusListener); + final IncrementalFileStorages result = new IncrementalFileStorages(stageDir, + incrementalManager, dataLoaderParams, statusListener, healthCheckParams, + healthListener); for (InstallationFileParcel file : addedFiles) { if (file.location == LOCATION_DATA_APP) { try { @@ -100,7 +102,9 @@ public final class IncrementalFileStorages { private IncrementalFileStorages(@NonNull File stageDir, @NonNull IncrementalManager incrementalManager, @NonNull DataLoaderParams dataLoaderParams, - @Nullable IDataLoaderStatusListener dataLoaderStatusListener) throws IOException { + @Nullable IDataLoaderStatusListener statusListener, + @Nullable StorageHealthCheckParams healthCheckParams, + @Nullable IStorageHealthListener healthListener) throws IOException { try { mStageDir = stageDir; mIncrementalManager = incrementalManager; @@ -117,10 +121,9 @@ public final class IncrementalFileStorages { mDefaultStorage.bind(stageDir.getAbsolutePath()); } else { mDefaultStorage = mIncrementalManager.createStorage(stageDir.getAbsolutePath(), - dataLoaderParams, - dataLoaderStatusListener, - IncrementalManager.CREATE_MODE_CREATE - | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false); + dataLoaderParams, IncrementalManager.CREATE_MODE_CREATE + | IncrementalManager.CREATE_MODE_TEMPORARY_BIND, false, + statusListener, healthCheckParams, healthListener); if (mDefaultStorage == null) { throw new IOException( "Couldn't create incremental storage at " + stageDir); diff --git a/core/java/android/os/incremental/IncrementalManager.java b/core/java/android/os/incremental/IncrementalManager.java index 916edfae679f..c7f50c951d70 100644 --- a/core/java/android/os/incremental/IncrementalManager.java +++ b/core/java/android/os/incremental/IncrementalManager.java @@ -110,11 +110,15 @@ public final class IncrementalManager { */ @Nullable public IncrementalStorage createStorage(@NonNull String path, - @NonNull DataLoaderParams params, @Nullable IDataLoaderStatusListener listener, + @NonNull DataLoaderParams params, @CreateMode int createMode, - boolean autoStartDataLoader) { + boolean autoStartDataLoader, + @Nullable IDataLoaderStatusListener statusListener, + @Nullable StorageHealthCheckParams healthCheckParams, + @Nullable IStorageHealthListener healthListener) { try { - final int id = mService.createStorage(path, params.getData(), listener, createMode); + final int id = mService.createStorage(path, params.getData(), createMode, + statusListener, healthCheckParams, healthListener); if (id < 0) { return null; } diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index 70ebbaa326b8..6200a38fe13c 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -469,12 +469,15 @@ public final class IncrementalStorage { * @param apkFullPath Source APK to extract native libs from. * @param libDirRelativePath Target dir to put lib files, e.g., "lib" or "lib/arm". * @param abi Target ABI of the native lib files. Only extract native libs of this ABI. + * @param extractNativeLibs If true, extract native libraries; otherwise just setup directories + * without extracting. * @return Success of not. */ public boolean configureNativeBinaries(String apkFullPath, String libDirRelativePath, - String abi) { + String abi, boolean extractNativeLibs) { try { - return mService.configureNativeBinaries(mId, apkFullPath, libDirRelativePath, abi); + return mService.configureNativeBinaries(mId, apkFullPath, libDirRelativePath, abi, + extractNativeLibs); } catch (RemoteException e) { e.rethrowFromSystemServer(); return false; diff --git a/core/java/android/os/incremental/StorageHealthCheckParams.aidl b/core/java/android/os/incremental/StorageHealthCheckParams.aidl new file mode 100644 index 000000000000..6839317a9ad5 --- /dev/null +++ b/core/java/android/os/incremental/StorageHealthCheckParams.aidl @@ -0,0 +1,35 @@ +/* + * 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 android.os.incremental; + +/** + * @hide + */ +parcelable StorageHealthCheckParams { + /** Timeouts of the oldest pending read. + * Valid values 0ms < blockedTimeoutMs < unhealthyTimeoutMs < storage page read timeout. + * Invalid values will disable health checking. */ + + /** To consider storage "blocked". */ + int blockedTimeoutMs; + /** To consider storage "unhealthy". */ + int unhealthyTimeoutMs; + + /** After storage is marked "unhealthy", how often to check if it recovered. + * Valid value 1000ms < unhealthyMonitoringMs. */ + int unhealthyMonitoringMs; +} diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index e0bc764025a5..1b19e1290121 100755 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -14363,6 +14363,21 @@ public final class Settings { * @hide */ public static final String ADVANCED_BATTERY_USAGE_AMOUNT = "advanced_battery_usage_amount"; + + /** + * For 5G NSA capable devices, determines whether NR tracking indications are on + * when the screen is off. + * + * Values are: + * 0: off - All 5G NSA tracking indications are off when the screen is off. + * 1: extended - All 5G NSA tracking indications are on when the screen is off as long as + * the device is camped on 5G NSA (5G icon is showing in status bar). + * If the device is not camped on 5G NSA, tracking indications are off. + * 2: always on - All 5G NSA tracking indications are on whether the screen is on or off. + * @hide + */ + public static final String NR_NSA_TRACKING_SCREEN_OFF_MODE = + "nr_nsa_tracking_screen_off_mode"; } /** diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java index 05abc6032116..cd56ca9251ab 100644 --- a/core/java/android/view/InsetsAnimationControlImpl.java +++ b/core/java/android/view/InsetsAnimationControlImpl.java @@ -17,6 +17,7 @@ package android.view; import static android.view.InsetsController.AnimationType; +import static android.view.InsetsController.DEBUG; import static android.view.InsetsState.ISIDE_BOTTOM; import static android.view.InsetsState.ISIDE_FLOATING; import static android.view.InsetsState.ISIDE_LEFT; @@ -30,6 +31,7 @@ import android.graphics.Insets; import android.graphics.Matrix; import android.graphics.Rect; import android.util.ArraySet; +import android.util.Log; import android.util.SparseArray; import android.util.SparseIntArray; import android.util.SparseSetArray; @@ -52,6 +54,8 @@ import java.util.ArrayList; public class InsetsAnimationControlImpl implements WindowInsetsAnimationController, InsetsAnimationControlRunner { + private static final String TAG = "InsetsAnimationCtrlImpl"; + private final Rect mTmpFrame = new Rect(); private final WindowInsetsAnimationControlListener mListener; @@ -165,6 +169,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll */ public boolean applyChangeInsets(InsetsState state) { if (mCancelled) { + if (DEBUG) Log.d(TAG, "applyChangeInsets canceled"); return false; } final Insets offset = Insets.subtract(mShownInsets, mPendingInsets); @@ -186,9 +191,13 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll mCurrentAlpha = mPendingAlpha; mAnimation.setAlpha(mPendingAlpha); if (mFinished) { + if (DEBUG) Log.d(TAG, String.format( + "notifyFinished shown: %s, currentAlpha: %f, currentInsets: %s", + mShownOnFinish, mCurrentAlpha, mCurrentInsets)); mController.notifyFinished(this, mShownOnFinish); releaseLeashes(); } + if (DEBUG) Log.d(TAG, "Animation finished abruptly."); return mFinished; } @@ -203,12 +212,15 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll @Override public void finish(boolean shown) { if (mCancelled || mFinished) { + if (DEBUG) Log.d(TAG, "Animation already canceled or finished, not notifying."); return; } mShownOnFinish = shown; mFinished = true; setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */, true /* allowWhenFinished */); + + if (DEBUG) Log.d(TAG, "notify control request finished for types: " + mTypes); mListener.onFinished(this); } @@ -225,6 +237,7 @@ public class InsetsAnimationControlImpl implements WindowInsetsAnimationControll } mCancelled = true; mListener.onCancelled(mReadyDispatched ? this : null); + if (DEBUG) Log.d(TAG, "notify Control request cancelled for types: " + mTypes); releaseLeashes(); } diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java index 3215b7c89b83..0e71b7643b7d 100644 --- a/core/java/android/view/InsetsAnimationThreadControlRunner.java +++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java @@ -16,12 +16,14 @@ package android.view; +import static android.view.InsetsController.DEBUG; import static android.view.SyncRtSurfaceTransactionApplier.applyParams; import android.annotation.UiThread; import android.graphics.Rect; import android.os.Handler; import android.os.Trace; +import android.util.Log; import android.util.SparseArray; import android.view.InsetsController.AnimationType; import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams; @@ -37,6 +39,7 @@ import android.view.animation.Interpolator; */ public class InsetsAnimationThreadControlRunner implements InsetsAnimationControlRunner { + private static final String TAG = "InsetsAnimThreadRunner"; private final InsetsAnimationControlImpl mControl; private final InsetsAnimationControlCallbacks mOuterCallbacks; private final Handler mMainThreadHandler; @@ -71,6 +74,7 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro @Override public void applySurfaceParams(SurfaceParams... params) { + if (DEBUG) Log.d(TAG, "applySurfaceParams"); SurfaceControl.Transaction t = new SurfaceControl.Transaction(); for (int i = params.length - 1; i >= 0; i--) { SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i]; @@ -82,6 +86,7 @@ public class InsetsAnimationThreadControlRunner implements InsetsAnimationContro @Override public void releaseSurfaceControlFromRt(SurfaceControl sc) { + if (DEBUG) Log.d(TAG, "releaseSurfaceControlFromRt"); // Since we don't push the SurfaceParams to the RT we can release directly sc.release(); } diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java index 758062f41428..ef9edc6c0741 100644 --- a/core/java/android/view/InsetsController.java +++ b/core/java/android/view/InsetsController.java @@ -37,6 +37,7 @@ import android.os.CancellationSignal; import android.os.Handler; import android.os.Trace; import android.util.ArraySet; +import android.util.Log; import android.util.Pair; import android.util.SparseArray; import android.view.InsetsSourceConsumer.ShowResult; @@ -69,6 +70,8 @@ import java.util.function.BiFunction; */ public class InsetsController implements WindowInsetsController, InsetsAnimationControlCallbacks { + private int mTypesBeingCancelled; + public interface Host { Handler getHandler(); @@ -152,8 +155,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation * Obtains {@link InputMethodManager} instance from host. */ InputMethodManager getInputMethodManager(); + + /** + * @return title of the rootView, if it has one. + * Note: this method is for debugging purposes only. + */ + @Nullable + String getRootViewTitle(); } + private static final String TAG = "InsetsController"; private static final int ANIMATION_DURATION_SHOW_MS = 275; private static final int ANIMATION_DURATION_HIDE_MS = 340; @@ -171,6 +182,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR = new PathInterpolator(0.4f, 0f, 1f, 1f); + static final boolean DEBUG = false; + static final boolean WARN = false; + /** * Layout mode during insets animation: The views should be laid out as if the changing inset * types are fully shown. Before starting the animation, {@link View#onApplyWindowInsets} will @@ -268,6 +282,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void onReady(WindowInsetsAnimationController controller, int types) { mController = controller; + if (DEBUG) Log.d(TAG, "default animation onReady types: " + types); mAnimator = ValueAnimator.ofFloat(0f, 1f); mAnimator.setDuration(mDurationMs); @@ -290,6 +305,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation sEvaluator.evaluate(insetsFraction, start, end), alphaInterpolator.getInterpolation(alphaFraction), rawFraction); + if (DEBUG) Log.d(TAG, "Default animation setInsetsAndAlpha fraction: " + + insetsFraction); }); mAnimator.addListener(new AnimatorListenerAdapter() { @@ -306,6 +323,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void onFinished(WindowInsetsAnimationController controller) { + if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onFinished types:" + + Type.toString(mRequestedTypes)); } @Override @@ -314,6 +333,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (mAnimator != null) { mAnimator.cancel(); } + if (DEBUG) Log.d(TAG, "InternalAnimationControlListener onCancelled types:" + + mRequestedTypes); } Interpolator getInterpolator() { @@ -348,6 +369,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation protected void onAnimationFinish() { mController.finish(mShow); + if (DEBUG) Log.d(TAG, "onAnimationFinish showOnFinish: " + mShow); } /** @@ -420,8 +442,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation final boolean useInsetsAnimationThread; } - private final String TAG = "InsetsControllerImpl"; - /** The local state */ private final InsetsState mState = new InsetsState(); @@ -494,6 +514,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation InsetsState state = new InsetsState(mState, true /* copySources */); for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { RunningAnimation runningAnimation = mRunningAnimations.get(i); + if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type); InsetsAnimationControlRunner runner = runningAnimation.runner; if (runner instanceof InsetsAnimationControlImpl) { InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner; @@ -516,6 +537,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mLastDisplayCutout, mLastLegacySoftInputMode, mLastLegacySystemUiFlags, null /* typeSideMap */); mHost.dispatchWindowInsetsAnimationProgress(insets, mUnmodifiableTmpRunningAnims); + if (DEBUG) { + for (WindowInsetsAnimation anim : mUnmodifiableTmpRunningAnims) { + Log.d(TAG, String.format("Running animation type: %d, progress: %f", + anim.getTypeMask(), anim.getInterpolatedFraction())); + } + } for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) { dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation()); @@ -553,13 +580,16 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation if (!localStateChanged && mLastDispatchedState.equals(state)) { return false; } + if (DEBUG) Log.d(TAG, "onStateChanged: " + state); updateState(state); mLastDispatchedState.set(state, true /* copySources */); applyLocalVisibilityOverride(); if (localStateChanged) { + if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged"); mHost.notifyInsetsChanged(); } if (!mState.equals(mLastDispatchedState, true /* excludingCaptionInsets */)) { + if (DEBUG) Log.d(TAG, "onStateChanged, send state to WM: " + mState); updateRequestedState(); } return true; @@ -683,7 +713,6 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @VisibleForTesting public void show(@InsetsType int types, boolean fromIme) { - // Handle pending request ready in case there was one set. if (fromIme && mPendingImeControlRequest != null) { PendingControlRequest pendingRequest = mPendingImeControlRequest; @@ -711,10 +740,18 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation || animationType == ANIMATION_TYPE_SHOW) { // no-op: already shown or animating in (because window visibility is // applied before starting animation). + if (DEBUG) Log.d(TAG, String.format( + "show ignored for type: %d animType: %d requestedVisible: %s", + consumer.getType(), animationType, consumer.isRequestedVisible())); + continue; + } + if (fromIme && animationType == ANIMATION_TYPE_USER) { + // App is already controlling the IME, don't cancel it. continue; } typesReady |= InsetsState.toPublicType(consumer.getType()); } + if (DEBUG) Log.d(TAG, "show typesReady: " + typesReady); applyAnimation(typesReady, true /* show */, fromIme); } @@ -778,12 +815,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @AnimationType int animationType, @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation, boolean useInsetsAnimationThread) { + if ((types & mTypesBeingCancelled) != 0) { + throw new IllegalStateException("Cannot start a new insets animation of " + + Type.toString(types) + + " while an existing " + Type.toString(mTypesBeingCancelled) + + " is being cancelled."); + } if (types == 0) { // nothing to animate. listener.onCancelled(null); + if (DEBUG) Log.d(TAG, "no types to animate in controlAnimationUnchecked"); return; } cancelExistingControllers(types); + if (DEBUG) Log.d(TAG, "controlAnimation types: " + types); mLastStartedAnimTypes |= types; final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types); @@ -793,6 +838,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation fromIme, internalTypes, controls, animationType); int typesReady = typesReadyPair.first; boolean imeReady = typesReadyPair.second; + if (DEBUG) Log.d(TAG, String.format( + "controlAnimationUnchecked, typesReady: %s imeReady: %s", typesReady, imeReady)); if (!imeReady) { // IME isn't ready, all requested types will be animated once IME is ready abortPendingImeControlRequest(); @@ -802,9 +849,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation useInsetsAnimationThread); mPendingImeControlRequest = request; mHandler.postDelayed(mPendingControlTimeout, PENDING_CONTROL_TIMEOUT_MS); + if (DEBUG) Log.d(TAG, "Ime not ready. Create pending request"); if (cancellationSignal != null) { cancellationSignal.setOnCancelListener(() -> { if (mPendingImeControlRequest == request) { + if (DEBUG) Log.d(TAG, + "Cancellation signal abortPendingImeControlRequest"); abortPendingImeControlRequest(); } }); @@ -813,6 +863,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } if (typesReady == 0) { + if (DEBUG) Log.d(TAG, "No types ready. onCancelled()"); listener.onCancelled(null); return; } @@ -826,8 +877,12 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation frame, mState, listener, typesReady, this, durationMs, interpolator, animationType); mRunningAnimations.add(new RunningAnimation(runner, animationType)); + if (DEBUG) Log.d(TAG, "Animation added to runner. useInsetsAnimationThread: " + + useInsetsAnimationThread); if (cancellationSignal != null) { - cancellationSignal.setOnCancelListener(runner::cancel); + cancellationSignal.setOnCancelListener(() -> { + cancelAnimation(runner, true /* invokeCallback */); + }); } if (layoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN) { showDirectly(types); @@ -857,8 +912,11 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation break; case ShowResult.IME_SHOW_DELAYED: imeReady = false; + if (DEBUG) Log.d(TAG, "requestShow IME_SHOW_DELAYED"); break; case ShowResult.IME_SHOW_FAILED: + if (WARN) Log.w(TAG, "requestShow IME_SHOW_FAILED. fromIme: " + + fromIme); // IME cannot be shown (since it didn't have focus), proceed // with animation of other types. break; @@ -873,6 +931,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation canRun = true; } if (!canRun) { + if (WARN) Log.w(TAG, String.format( + "collectSourceControls can't continue show for type: %s fromIme: %b", + InsetsState.typeToString(consumer.getType()), fromIme)); continue; } final InsetsSourceControl control = consumer.getControl(); @@ -880,7 +941,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation controls.put(consumer.getType(), new InsetsSourceControl(control)); typesReady |= toPublicType(consumer.getType()); } else if (animationType == ANIMATION_TYPE_SHOW) { - + if (DEBUG) Log.d(TAG, "collectSourceControls no control for show(). fromIme: " + + fromIme); // We don't have a control at the moment. However, we still want to update requested // visibility state such that in case we get control, we can apply show animation. consumer.show(fromIme); @@ -915,14 +977,20 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } private void cancelExistingControllers(@InsetsType int types) { - for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { - InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner; - if ((control.getTypes() & types) != 0) { - cancelAnimation(control, true /* invokeCallback */); + final int originalmTypesBeingCancelled = mTypesBeingCancelled; + mTypesBeingCancelled |= types; + try { + for (int i = mRunningAnimations.size() - 1; i >= 0; i--) { + InsetsAnimationControlRunner control = mRunningAnimations.get(i).runner; + if ((control.getTypes() & types) != 0) { + cancelAnimation(control, true /* invokeCallback */); + } } - } - if ((types & ime()) != 0) { - abortPendingImeControlRequest(); + if ((types & ime()) != 0) { + abortPendingImeControlRequest(); + } + } finally { + mTypesBeingCancelled = originalmTypesBeingCancelled; } } @@ -931,6 +999,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mPendingImeControlRequest.listener.onCancelled(null); mPendingImeControlRequest = null; mHandler.removeCallbacks(mPendingControlTimeout); + if (DEBUG) Log.d(TAG, "abortPendingImeControlRequest"); } } @@ -938,6 +1007,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation @Override public void notifyFinished(InsetsAnimationControlRunner runner, boolean shown) { cancelAnimation(runner, false /* invokeCallback */); + if (DEBUG) Log.d(TAG, "notifyFinished. shown: " + shown); if (shown) { showDirectly(runner.getTypes()); } else { @@ -964,6 +1034,8 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation } private void cancelAnimation(InsetsAnimationControlRunner control, boolean invokeCallback) { + if (DEBUG) Log.d(TAG, String.format("cancelAnimation of types: %d, animType: %d", + control.getTypes(), control.getAnimationType())); if (invokeCallback) { control.cancel(); } @@ -977,6 +1049,9 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mHost.notifyInsetsChanged(); } } + if (invokeCallback && runningAnimation.startDispatched) { + dispatchAnimationEnd(runningAnimation.runner.getAnimation()); + } break; } } @@ -1088,6 +1163,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation public void applyAnimation(@InsetsType final int types, boolean show, boolean fromIme) { if (types == 0) { // nothing to animate. + if (DEBUG) Log.d(TAG, "applyAnimation, nothing to animate"); return; } @@ -1142,6 +1218,7 @@ public class InsetsController implements WindowInsetsController, InsetsAnimation mHost.dispatchWindowInsetsAnimationPrepare(animation); mHost.addOnPreDrawRunnable(() -> { if (controller.isCancelled()) { + if (WARN) Log.w(TAG, "startAnimation canceled before preDraw"); return; } Trace.asyncTraceBegin(Trace.TRACE_TAG_VIEW, diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java index df3ac8787b57..3869484468ae 100644 --- a/core/java/android/view/InsetsSourceConsumer.java +++ b/core/java/android/view/InsetsSourceConsumer.java @@ -19,11 +19,13 @@ package android.view; import static android.view.InsetsController.ANIMATION_TYPE_NONE; import static android.view.InsetsController.AnimationType; import static android.view.InsetsState.getDefaultVisibility; +import static android.view.InsetsController.DEBUG; import static android.view.InsetsState.toPublicType; import android.annotation.IntDef; import android.annotation.Nullable; import android.graphics.Rect; +import android.util.Log; import android.view.InsetsState.InternalInsetsType; import android.view.SurfaceControl.Transaction; import android.view.WindowInsets.Type.InsetsType; @@ -64,6 +66,7 @@ public class InsetsSourceConsumer { protected final InsetsState mState; protected final @InternalInsetsType int mType; + private static final String TAG = "InsetsSourceConsumer"; private final Supplier<Transaction> mTransactionSupplier; private @Nullable InsetsSourceControl mSourceControl; private boolean mHasWindowFocus; @@ -103,7 +106,11 @@ public class InsetsSourceConsumer { final InsetsSourceControl lastControl = mSourceControl; mSourceControl = control; - + if (control != null) { + if (DEBUG) Log.d(TAG, String.format("setControl -> %s on %s", + InsetsState.typeToString(control.getType()), + mController.getHost().getRootViewTitle())); + } // We are loosing control if (mSourceControl == null) { mController.notifyControlRevoked(this); @@ -118,6 +125,8 @@ public class InsetsSourceConsumer { final boolean requestedVisible = isRequestedVisibleAwaitingControl(); final boolean needAnimation = requestedVisible != mState.getSource(mType).isVisible(); if (control.getLeash() != null && (needAnimation || mIsAnimationPending)) { + if (DEBUG) Log.d(TAG, String.format("Gaining control in %s, requestedVisible: %b", + mController.getHost().getRootViewTitle(), requestedVisible)); if (requestedVisible) { showTypes[0] |= toPublicType(getType()); } else { @@ -170,11 +179,15 @@ public class InsetsSourceConsumer { @VisibleForTesting public void show(boolean fromIme) { + if (DEBUG) Log.d(TAG, String.format("Call show() for type: %s fromIme: %b ", + InsetsState.typeToString(mType), fromIme)); setRequestedVisible(true); } @VisibleForTesting public void hide() { + if (DEBUG) Log.d(TAG, String.format("Call hide for %s on %s", + InsetsState.typeToString(mType), mController.getHost().getRootViewTitle())); setRequestedVisible(false); } @@ -212,11 +225,16 @@ public class InsetsSourceConsumer { // If we don't have control, we are not able to change the visibility. if (!hasControl) { + if (DEBUG) Log.d(TAG, "applyLocalVisibilityOverride: No control in " + + mController.getHost().getRootViewTitle() + + " requestedVisible " + mRequestedVisible); return false; } if (isVisible == mRequestedVisible) { return false; } + if (DEBUG) Log.d(TAG, String.format("applyLocalVisibilityOverride: %s requestedVisible: %b", + mController.getHost().getRootViewTitle(), mRequestedVisible)); mState.getSource(mType).setVisible(mRequestedVisible); return true; } @@ -271,6 +289,7 @@ public class InsetsSourceConsumer { newSource.setFrame(source.getFrame()); newSource.setVisibleFrame(source.getVisibleFrame()); mState.addSource(newSource); + if (DEBUG) Log.d(TAG, "updateSource: " + newSource); } boolean notifyAnimationFinished() { @@ -293,6 +312,7 @@ public class InsetsSourceConsumer { if (mRequestedVisible != requestedVisible) { mRequestedVisible = requestedVisible; mIsAnimationPending = false; + if (DEBUG) Log.d(TAG, "setRequestedVisible: " + requestedVisible); } if (applyLocalVisibilityOverride()) { mController.notifyVisibilityChanged(); @@ -305,6 +325,7 @@ public class InsetsSourceConsumer { } final Transaction t = mTransactionSupplier.get(); + if (DEBUG) Log.d(TAG, "applyHiddenToControl: " + mRequestedVisible); if (mRequestedVisible) { t.show(mSourceControl.getLeash()); } else { diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java index e001b668f71a..2c2ecd504519 100644 --- a/core/java/android/view/InsetsSourceControl.java +++ b/core/java/android/view/InsetsSourceControl.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import android.view.InsetsState.InternalInsetsType; +import java.io.PrintWriter; import java.util.function.Consumer; /** @@ -101,6 +102,14 @@ public class InsetsSourceControl implements Parcelable { } } + public void dump(String prefix, PrintWriter pw) { + pw.print(prefix); + pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType)); + pw.print(" mLeash="); pw.print(mLeash); + pw.print(" mSurfacePosition="); pw.print(mSurfacePosition); + pw.println(); + } + public static final @android.annotation.NonNull Creator<InsetsSourceControl> CREATOR = new Creator<InsetsSourceControl>() { public InsetsSourceControl createFromParcel(Parcel in) { diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java index 9896aa4fe214..3822ee59b4aa 100644 --- a/core/java/android/view/InsetsState.java +++ b/core/java/android/view/InsetsState.java @@ -51,6 +51,7 @@ import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.Objects; +import java.util.StringJoiner; /** * Holder for state of system windows that cause window insets for all other windows in the system. @@ -78,7 +79,9 @@ public class InsetsState implements Parcelable { ITYPE_TOP_DISPLAY_CUTOUT, ITYPE_RIGHT_DISPLAY_CUTOUT, ITYPE_BOTTOM_DISPLAY_CUTOUT, - ITYPE_IME + ITYPE_IME, + ITYPE_CLIMATE_BAR, + ITYPE_EXTRA_NAVIGATION_BAR }) public @interface InternalInsetsType {} @@ -109,7 +112,11 @@ public class InsetsState implements Parcelable { /** Input method window. */ public static final int ITYPE_IME = 13; - static final int LAST_TYPE = ITYPE_IME; + /** Additional system decorations inset type. */ + public static final int ITYPE_CLIMATE_BAR = 14; + public static final int ITYPE_EXTRA_NAVIGATION_BAR = 15; + + static final int LAST_TYPE = ITYPE_EXTRA_NAVIGATION_BAR; // Derived types @@ -417,8 +424,10 @@ public class InsetsState implements Parcelable { public static @Type.InsetsType int toPublicType(@InternalInsetsType int type) { switch (type) { case ITYPE_STATUS_BAR: + case ITYPE_CLIMATE_BAR: return Type.STATUS_BARS; case ITYPE_NAVIGATION_BAR: + case ITYPE_EXTRA_NAVIGATION_BAR: return Type.NAVIGATION_BARS; case ITYPE_CAPTION_BAR: return Type.CAPTION_BAR; @@ -497,6 +506,10 @@ public class InsetsState implements Parcelable { return "ITYPE_BOTTOM_DISPLAY_CUTOUT"; case ITYPE_IME: return "ITYPE_IME"; + case ITYPE_CLIMATE_BAR: + return "ITYPE_CLIMATE_BAR"; + case ITYPE_EXTRA_NAVIGATION_BAR: + return "ITYPE_EXTRA_NAVIGATION_BAR"; default: return "ITYPE_UNKNOWN_" + type; } @@ -600,10 +613,16 @@ public class InsetsState implements Parcelable { @Override public String toString() { + StringJoiner joiner = new StringJoiner(", "); + for (InsetsSource source : mSources.values()) { + if (source != null) { + joiner.add(source.toString()); + } + } return "InsetsState: {" + "mDisplayFrame=" + mDisplayFrame - + ", mSources=" + mSources - + "}"; + + ", mSources= { " + joiner + + " }"; } } diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java index 7935eb1ffc39..e3362aafbcd4 100644 --- a/core/java/android/view/ViewGroup.java +++ b/core/java/android/view/ViewGroup.java @@ -7298,7 +7298,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0 || isFrameworkOptionalFitsSystemWindows(); if (isOptionalFitSystemWindows && mAttachInfo != null - && mAttachInfo.mContentOnApplyWindowInsetsListener != null) { + && mAttachInfo.mContentOnApplyWindowInsetsListener != null + && (getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) == 0) { return false; } @@ -7322,7 +7323,8 @@ public abstract class ViewGroup extends View implements ViewParent, ViewManager || isFrameworkOptionalFitsSystemWindows(); if (isOptionalFitSystemWindows && mAttachInfo != null && getListenerInfo().mWindowInsetsAnimationCallback == null - && mAttachInfo.mContentOnApplyWindowInsetsListener != null) { + && mAttachInfo.mContentOnApplyWindowInsetsListener != null + && (getWindowSystemUiVisibility() & SYSTEM_UI_LAYOUT_FLAGS) == 0) { mInsetsAnimationDispatchMode = DISPATCH_MODE_STOP; return; } diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index 511e75541ba7..8b5d033072fb 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -4990,6 +4990,11 @@ public final class ViewRootImpl implements ViewParent, break; } case MSG_SHOW_INSETS: { + if (mView == null) { + Log.e(TAG, + String.format("Calling showInsets(%d,%b) on window that no longer" + + " has views.", msg.arg1, msg.arg2 == 1)); + } mInsetsController.show(msg.arg1, msg.arg2 == 1); break; } diff --git a/core/java/android/view/ViewRootInsetsControllerHost.java b/core/java/android/view/ViewRootInsetsControllerHost.java index 9674a80c8159..686d561a1a5a 100644 --- a/core/java/android/view/ViewRootInsetsControllerHost.java +++ b/core/java/android/view/ViewRootInsetsControllerHost.java @@ -16,6 +16,7 @@ package android.view; +import static android.view.InsetsController.DEBUG; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_APPEARANCE_CONTROLLED; import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_BEHAVIOR_CONTROLLED; @@ -84,6 +85,7 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { if (mViewRoot.mView == null) { return null; } + if (DEBUG) Log.d(TAG, "windowInsetsAnimation started"); return mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds); } @@ -94,11 +96,18 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { // The view has already detached from window. return null; } + if (DEBUG) { + for (WindowInsetsAnimation anim : runningAnimations) { + Log.d(TAG, "windowInsetsAnimation progress: " + + anim.getInterpolatedFraction()); + } + } return mViewRoot.mView.dispatchWindowInsetsAnimationProgress(insets, runningAnimations); } @Override public void dispatchWindowInsetsAnimationEnd(@NonNull WindowInsetsAnimation animation) { + if (DEBUG) Log.d(TAG, "windowInsetsAnimation ended"); mViewRoot.mView.dispatchWindowInsetsAnimationEnd(animation); } @@ -212,4 +221,12 @@ public class ViewRootInsetsControllerHost implements InsetsController.Host { public InputMethodManager getInputMethodManager() { return mViewRoot.mContext.getSystemService(InputMethodManager.class); } + + @Override + public String getRootViewTitle() { + if (mViewRoot == null) { + return null; + } + return mViewRoot.getTitle().toString(); + } } diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index d20ffb3a6ec1..9b5b8824b0e6 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -136,6 +136,7 @@ public class WindowlessWindowManager implements IWindowSession { final SurfaceControl.Builder b = new SurfaceControl.Builder(mSurfaceSession) .setParent(mRootSurface) .setFormat(attrs.format) + .setBufferSize(getSurfaceWidth(attrs), getSurfaceHeight(attrs)) .setName(attrs.getTitle().toString()); final SurfaceControl sc = b.build(); @@ -242,13 +243,8 @@ public class WindowlessWindowManager implements IWindowSession { WindowManager.LayoutParams attrs = state.mParams; if (viewFlags == View.VISIBLE) { - final Rect surfaceInsets = attrs.surfaceInsets; - int width = surfaceInsets != null - ? attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width; - int height = surfaceInsets != null - ? attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height; - - t.setBufferSize(sc, width, height).setOpaque(sc, isOpaque(attrs)).show(sc).apply(); + t.setBufferSize(sc, getSurfaceWidth(attrs), getSurfaceHeight(attrs)) + .setOpaque(sc, isOpaque(attrs)).show(sc).apply(); outSurfaceControl.copyFrom(sc); } else { t.hide(sc).apply(); @@ -444,4 +440,15 @@ public class WindowlessWindowManager implements IWindowSession { public android.os.IBinder asBinder() { return null; } + + private int getSurfaceWidth(WindowManager.LayoutParams attrs) { + final Rect surfaceInsets = attrs.surfaceInsets; + return surfaceInsets != null + ? attrs.width + surfaceInsets.left + surfaceInsets.right : attrs.width; + } + private int getSurfaceHeight(WindowManager.LayoutParams attrs) { + final Rect surfaceInsets = attrs.surfaceInsets; + return surfaceInsets != null + ? attrs.height + surfaceInsets.top + surfaceInsets.bottom : attrs.height; + } } diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java index 0807f4162162..7042f29fc4e4 100644 --- a/core/java/android/webkit/WebChromeClient.java +++ b/core/java/android/webkit/WebChromeClient.java @@ -202,9 +202,9 @@ public class WebChromeClient { * <p>To suppress the dialog and allow JavaScript execution to * continue, call {@code JsResult.confirm()} immediately and then return * {@code true}. - * <p>Note that if the {@link WebChromeClient} is {@code null}, the default - * dialog will be suppressed and Javascript execution will continue - * immediately. + * <p>Note that if the {@link WebChromeClient} is set to be {@code null}, + * or if {@link WebChromeClient} is not set at all, the default dialog will + * be suppressed and Javascript execution will continue immediately. * * @param view The WebView that initiated the callback. * @param url The url of the page requesting the dialog. @@ -236,9 +236,10 @@ public class WebChromeClient { * <p>To suppress the dialog and allow JavaScript execution to continue, * call {@code JsResult.confirm()} or {@code JsResult.cancel()} immediately * and then return {@code true}. - * <p>Note that if the {@link WebChromeClient} is {@code null}, the default - * dialog will be suppressed and the default value of {@code false} will be - * returned to the JavaScript code immediately. + * <p>Note that if the {@link WebChromeClient} is set to be {@code null}, + * or if {@link WebChromeClient} is not set at all, the default dialog will + * be suppressed and the default value of {@code false} will be returned to + * the JavaScript code immediately. * * @param view The WebView that initiated the callback. * @param url The url of the page requesting the dialog. @@ -269,9 +270,10 @@ public class WebChromeClient { * <p>To suppress the dialog and allow JavaScript execution to continue, * call {@code JsPromptResult.confirm(result)} immediately and then * return {@code true}. - * <p>Note that if the {@link WebChromeClient} is {@code null}, the default - * dialog will be suppressed and {@code null} will be returned to the - * JavaScript code immediately. + * <p>Note that if the {@link WebChromeClient} is set to be {@code null}, + * or if {@link WebChromeClient} is not set at all, the default dialog will + * be suppressed and {@code null} will be returned to the JavaScript code + * immediately. * * @param view The WebView that initiated the callback. * @param url The url of the page requesting the dialog. @@ -288,20 +290,32 @@ public class WebChromeClient { } /** - * Tell the client to display a dialog to confirm navigation away from the - * current page. This is the result of the onbeforeunload javascript event. - * If the client returns {@code true}, WebView will assume that the client will - * handle the confirm dialog and call the appropriate JsResult method. If - * the client returns {@code false}, a default value of {@code true} will be returned to - * javascript to accept navigation away from the current page. The default - * behavior is to return {@code false}. Setting the JsResult to {@code true} will navigate - * away from the current page, {@code false} will cancel the navigation. + * Notify the host application that the web page wants to confirm navigation + * from JavaScript {@code onbeforeunload}. + * <p>The default behavior if this method returns {@code false} or is not + * overridden is to show a dialog containing the message and suspend + * JavaScript execution until the dialog is dismissed. The default dialog + * will continue the navigation if the user confirms the navigation, and + * will stop the navigation if the user wants to stay on the current page. + * <p>To show a custom dialog, the app should return {@code true} from this + * method, in which case the default dialog will not be shown and JavaScript + * execution will be suspended. When the custom dialog is dismissed, the + * app should call {@code JsResult.confirm()} to continue the navigation or, + * {@code JsResult.cancel()} to stay on the current page. + * <p>To suppress the dialog and allow JavaScript execution to continue, + * call {@code JsResult.confirm()} or {@code JsResult.cancel()} immediately + * and then return {@code true}. + * <p>Note that if the {@link WebChromeClient} is set to be {@code null}, + * or if {@link WebChromeClient} is not set at all, the default dialog will + * be suppressed and the navigation will be resumed immediately. + * * @param view The WebView that initiated the callback. * @param url The url of the page requesting the dialog. * @param message Message to be displayed in the window. * @param result A JsResult used to send the user's response to * javascript. - * @return boolean Whether the client will handle the confirm dialog. + * @return boolean {@code true} if the request is handled or ignored. + * {@code false} if WebView needs to show the default dialog. */ public boolean onJsBeforeUnload(WebView view, String url, String message, JsResult result) { diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 231e024e835f..9a732455113c 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -141,6 +141,36 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Like {@link #setBoundsChangeTransaction} but instead queues up a setPosition/WindowCrop + * on a container's surface control. This is useful when a boundsChangeTransaction needs to be + * queued up on a Task that won't be organized until the end of this window-container + * transaction. + * + * This requires that, at the end of this transaction, `task` will be organized; otherwise + * the server will throw an IllegalArgumentException. + * + * WARNING: Use this carefully. Whatever is set here should match the expected bounds after + * the transaction completes since it will likely be replaced by it. This call is + * intended to pre-emptively set bounds on a surface in sync with a buffer when + * otherwise the new bounds and the new buffer would update on different frames. + * + * TODO(b/134365562): remove once TaskOrg drives full-screen or BLAST is enabled. + * + * @hide + */ + @NonNull + public WindowContainerTransaction setBoundsChangeTransaction( + @NonNull WindowContainerToken task, @NonNull Rect surfaceBounds) { + Change chg = getOrCreateChange(task.asBinder()); + if (chg.mBoundsChangeSurfaceBounds == null) { + chg.mBoundsChangeSurfaceBounds = new Rect(); + } + chg.mBoundsChangeSurfaceBounds.set(surfaceBounds); + chg.mChangeMask |= Change.CHANGE_BOUNDS_TRANSACTION_RECT; + return this; + } + + /** * Set the windowing mode of children of a given root task, without changing * the windowing mode of the Task itself. This can be used during transitions * for example to make the activity render it's fullscreen configuration @@ -287,6 +317,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int CHANGE_BOUNDS_TRANSACTION = 1 << 1; public static final int CHANGE_PIP_CALLBACK = 1 << 2; public static final int CHANGE_HIDDEN = 1 << 3; + public static final int CHANGE_BOUNDS_TRANSACTION_RECT = 1 << 4; private final Configuration mConfiguration = new Configuration(); private boolean mFocusable = true; @@ -297,6 +328,7 @@ public final class WindowContainerTransaction implements Parcelable { private Rect mPinnedBounds = null; private SurfaceControl.Transaction mBoundsChangeTransaction = null; + private Rect mBoundsChangeSurfaceBounds = null; private int mActivityWindowingMode = -1; private int mWindowingMode = -1; @@ -318,6 +350,10 @@ public final class WindowContainerTransaction implements Parcelable { mBoundsChangeTransaction = SurfaceControl.Transaction.CREATOR.createFromParcel(in); } + if ((mChangeMask & Change.CHANGE_BOUNDS_TRANSACTION_RECT) != 0) { + mBoundsChangeSurfaceBounds = new Rect(); + mBoundsChangeSurfaceBounds.readFromParcel(in); + } mWindowingMode = in.readInt(); mActivityWindowingMode = in.readInt(); @@ -377,6 +413,10 @@ public final class WindowContainerTransaction implements Parcelable { return mBoundsChangeTransaction; } + public Rect getBoundsChangeSurfaceBounds() { + return mBoundsChangeSurfaceBounds; + } + @Override public String toString() { final boolean changesBounds = @@ -408,6 +448,9 @@ public final class WindowContainerTransaction implements Parcelable { if ((mChangeMask & CHANGE_FOCUSABLE) != 0) { sb.append("focusable:" + mFocusable + ","); } + if (mBoundsChangeTransaction != null) { + sb.append("hasBoundsTransaction,"); + } sb.append("}"); return sb.toString(); } @@ -427,6 +470,9 @@ public final class WindowContainerTransaction implements Parcelable { if (mBoundsChangeTransaction != null) { mBoundsChangeTransaction.writeToParcel(dest, flags); } + if (mBoundsChangeSurfaceBounds != null) { + mBoundsChangeSurfaceBounds.writeToParcel(dest, flags); + } dest.writeInt(mWindowingMode); dest.writeInt(mActivityWindowingMode); diff --git a/core/java/com/android/internal/app/AbstractResolverComparator.java b/core/java/com/android/internal/app/AbstractResolverComparator.java index 28c9464fbf66..ea3f1b1fc04c 100644 --- a/core/java/com/android/internal/app/AbstractResolverComparator.java +++ b/core/java/com/android/internal/app/AbstractResolverComparator.java @@ -54,8 +54,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC // True if the current share is a link. private final boolean mHttp; - // can be null if mHttp == false or current user has no default browser package - private final String mDefaultBrowserPackageName; // message types static final int RANKER_SERVICE_RESULT = 0; @@ -102,9 +100,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC getContentAnnotations(intent); mPm = context.getPackageManager(); mUsm = (UsageStatsManager) context.getSystemService(Context.USAGE_STATS_SERVICE); - mDefaultBrowserPackageName = mHttp - ? mPm.getDefaultBrowserPackageNameAsUser(UserHandle.myUserId()) - : null; mAzComparator = new AzInfoComparator(context); } @@ -157,17 +152,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC } if (mHttp) { - // Special case: we want filters that match URI paths/schemes to be - // ordered before others. This is for the case when opening URIs, - // to make native apps go above browsers - except for 1 even more special case - // which is the default browser, as we want that to go above them all. - if (isDefaultBrowser(lhs)) { - return -1; - } - - if (isDefaultBrowser(rhs)) { - return 1; - } final boolean lhsSpecific = ResolverActivity.isSpecificUriMatch(lhs.match); final boolean rhsSpecific = ResolverActivity.isSpecificUriMatch(rhs.match); if (lhsSpecific != rhsSpecific) { @@ -272,21 +256,6 @@ public abstract class AbstractResolverComparator implements Comparator<ResolvedC mAfterCompute = null; } - private boolean isDefaultBrowser(ResolveInfo ri) { - // It makes sense to prefer the default browser - // only if the targeted user is the current user - if (ri.targetUserId != UserHandle.USER_CURRENT) { - return false; - } - - if (ri.activityInfo.packageName != null - && ri.activityInfo.packageName.equals(mDefaultBrowserPackageName)) { - return true; - } - return false; - } - - /** * Sort intents alphabetically based on package name. */ diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java index f041ad91b559..5533e1eda52d 100644 --- a/core/java/com/android/internal/app/ChooserActivity.java +++ b/core/java/com/android/internal/app/ChooserActivity.java @@ -101,6 +101,7 @@ import android.view.View.MeasureSpec; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.ViewGroup.LayoutParams; +import android.view.ViewTreeObserver; import android.view.animation.AccelerateInterpolator; import android.view.animation.DecelerateInterpolator; import android.widget.Button; @@ -170,17 +171,6 @@ public class ChooserActivity extends ResolverActivity implements public static final String EXTRA_PRIVATE_RETAIN_IN_ON_STOP = "com.android.internal.app.ChooserActivity.EXTRA_PRIVATE_RETAIN_IN_ON_STOP"; - /** - * Integer extra to indicate which profile should be automatically selected. - * <p>Can only be used if there is a work profile. - * <p>Possible values can be either {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK}. - */ - static final String EXTRA_SELECTED_PROFILE = - "com.android.internal.app.ChooserActivity.EXTRA_SELECTED_PROFILE"; - - static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; - static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK; - private static final String PREF_NUM_SHEET_EXPANSIONS = "pref_num_sheet_expansions"; private static final String CHIP_LABEL_METADATA_KEY = "android.service.chooser.chip_label"; @@ -885,7 +875,6 @@ public class ChooserActivity extends ResolverActivity implements initialIntents, rList, filterLastUsed, - mUseLayoutForBrowsables, /* userHandle */ UserHandle.of(UserHandle.myUserId())); return new ChooserMultiProfilePagerAdapter( /* context */ this, @@ -906,7 +895,6 @@ public class ChooserActivity extends ResolverActivity implements selectedProfile == PROFILE_PERSONAL ? initialIntents : null, rList, filterLastUsed, - mUseLayoutForBrowsables, /* userHandle */ getPersonalProfileUserHandle()); ChooserGridAdapter workAdapter = createChooserGridAdapter( /* context */ this, @@ -914,7 +902,6 @@ public class ChooserActivity extends ResolverActivity implements selectedProfile == PROFILE_WORK ? initialIntents : null, rList, filterLastUsed, - mUseLayoutForBrowsables, /* userHandle */ getWorkProfileUserHandle()); return new ChooserMultiProfilePagerAdapter( /* context */ this, @@ -927,15 +914,8 @@ public class ChooserActivity extends ResolverActivity implements } private int findSelectedProfile() { - int selectedProfile; - if (getIntent().hasExtra(EXTRA_SELECTED_PROFILE)) { - selectedProfile = getIntent().getIntExtra(EXTRA_SELECTED_PROFILE, /* defValue = */ -1); - if (selectedProfile != PROFILE_PERSONAL && selectedProfile != PROFILE_WORK) { - throw new IllegalArgumentException(EXTRA_SELECTED_PROFILE + " has invalid value " - + selectedProfile + ". Must be either ChooserActivity.PROFILE_PERSONAL or " - + "ChooserActivity.PROFILE_WORK."); - } - } else { + int selectedProfile = getSelectedProfileExtra(); + if (selectedProfile == -1) { selectedProfile = getProfileForUser(getUser()); } return selectedProfile; @@ -1634,7 +1614,7 @@ public class ChooserActivity extends ResolverActivity implements targetList = Collections.singletonList(ti); } - ResolverTargetActionsDialogFragment f = new ResolverTargetActionsDialogFragment( + ChooserTargetActionsDialogFragment f = new ChooserTargetActionsDialogFragment( targetList, mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); @@ -1694,15 +1674,9 @@ public class ChooserActivity extends ResolverActivity implements if (targetInfo instanceof MultiDisplayResolveInfo) { MultiDisplayResolveInfo mti = (MultiDisplayResolveInfo) targetInfo; if (!mti.hasSelected()) { - // Stacked apps get a disambiguation first - CharSequence[] labels = new CharSequence[mti.getTargets().size()]; - int i = 0; - for (TargetInfo ti : mti.getTargets()) { - labels[i++] = ti.getResolveInfo().loadLabel(getPackageManager()); - } ChooserStackedAppDialogFragment f = new ChooserStackedAppDialogFragment( - targetInfo.getDisplayLabel(), - ((MultiDisplayResolveInfo) targetInfo), labels, which); + mti, which, + mChooserMultiProfilePagerAdapter.getCurrentUserHandle()); f.show(getFragmentManager(), TARGET_DETAILS_FRAGMENT_TAG); return; @@ -2503,10 +2477,10 @@ public class ChooserActivity extends ResolverActivity implements @VisibleForTesting public ChooserGridAdapter createChooserGridAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { + boolean filterLastUsed, UserHandle userHandle) { ChooserListAdapter chooserListAdapter = createChooserListAdapter(context, payloadIntents, initialIntents, rList, filterLastUsed, - useLayoutForBrowsables, createListController(userHandle)); + createListController(userHandle)); AppPredictor.Callback appPredictorCallback = createAppPredictorCallback(chooserListAdapter); AppPredictor appPredictor = setupAppPredictorForUser(userHandle, appPredictorCallback); chooserListAdapter.setAppPredictor(appPredictor); @@ -2517,11 +2491,10 @@ public class ChooserActivity extends ResolverActivity implements @VisibleForTesting public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables, - ResolverListController resolverListController) { + boolean filterLastUsed, ResolverListController resolverListController) { return new ChooserListAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, resolverListController, useLayoutForBrowsables, - this, this, context.getPackageManager()); + filterLastUsed, resolverListController, this, + this, context.getPackageManager()); } @VisibleForTesting @@ -2777,6 +2750,7 @@ public class ChooserActivity extends ResolverActivity implements @Override public void onListRebuilt(ResolverListAdapter listAdapter) { setupScrollListener(); + maybeSetupGlobalLayoutListener(); ChooserListAdapter chooserListAdapter = (ChooserListAdapter) listAdapter; if (chooserListAdapter.getUserHandle() @@ -2858,6 +2832,28 @@ public class ChooserActivity extends ResolverActivity implements }); } + private void maybeSetupGlobalLayoutListener() { + if (shouldShowTabs()) { + return; + } + final View recyclerView = mChooserMultiProfilePagerAdapter.getActiveAdapterView(); + recyclerView.getViewTreeObserver() + .addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { + @Override + public void onGlobalLayout() { + // Fixes an issue were the accessibility border disappears on list creation. + recyclerView.getViewTreeObserver().removeOnGlobalLayoutListener(this); + final TextView titleView = findViewById(R.id.title); + if (titleView != null) { + titleView.setFocusable(true); + titleView.setFocusableInTouchMode(true); + titleView.requestFocus(); + titleView.requestAccessibilityFocus(); + } + } + }); + } + @Override // ChooserListCommunicator public boolean isSendAction(Intent targetIntent) { if (targetIntent == null) { @@ -2971,16 +2967,16 @@ public class ChooserActivity extends ResolverActivity implements itemView.setOnClickListener(v -> startSelected(mListPosition, false/* always */, true/* filterd */)); - TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter() - .targetInfoForPosition(mListPosition, /* filtered */ true); + itemView.setOnLongClickListener(v -> { + final TargetInfo ti = mChooserMultiProfilePagerAdapter.getActiveListAdapter() + .targetInfoForPosition(mListPosition, /* filtered */ true); - // This should always be the case for ItemViewHolder, check for sanity - if (ti instanceof DisplayResolveInfo) { - itemView.setOnLongClickListener(v -> { + // This should always be the case for ItemViewHolder, check for sanity + if (ti instanceof DisplayResolveInfo) { showTargetDetails((DisplayResolveInfo) ti); - return true; - }); - } + } + return true; + }); } } } @@ -3308,16 +3304,15 @@ public class ChooserActivity extends ResolverActivity implements // Direct Share targets should not show any menu if (!isDirectShare) { - final TargetInfo ti = mChooserListAdapter.targetInfoForPosition( - holder.getItemIndex(column), true); - - // This should always be the case for non-DS targets, check for sanity - if (ti instanceof DisplayResolveInfo) { - v.setOnLongClickListener(v1 -> { + v.setOnLongClickListener(v1 -> { + final TargetInfo ti = mChooserListAdapter.targetInfoForPosition( + holder.getItemIndex(column), true); + // This should always be the case for non-DS targets, check for sanity + if (ti instanceof DisplayResolveInfo) { showTargetDetails((DisplayResolveInfo) ti); - return true; - }); - } + } + return true; + }); } holder.addView(i, v); diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java index f1b716143787..a87f8477bcf4 100644 --- a/core/java/com/android/internal/app/ChooserListAdapter.java +++ b/core/java/com/android/internal/app/ChooserListAdapter.java @@ -120,15 +120,13 @@ public class ChooserListAdapter extends ResolverListAdapter { public ChooserListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, ResolverListController resolverListController, - boolean useLayoutForBrowsables, ChooserListCommunicator chooserListCommunicator, SelectableTargetInfo.SelectableTargetInfoCommunicator selectableTargetInfoCommunicator, PackageManager packageManager) { // Don't send the initial intents through the shared ResolverActivity path, // we want to separate them into a different section. super(context, payloadIntents, null, rList, filterLastUsed, - resolverListController, useLayoutForBrowsables, - chooserListCommunicator, false); + resolverListController, chooserListCommunicator, false); createPlaceHolders(); mMaxShortcutTargetsPerApp = diff --git a/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java index f4c69a51ece1..fdeba8f67cc1 100644 --- a/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java +++ b/core/java/com/android/internal/app/ChooserStackedAppDialogFragment.java @@ -17,64 +17,50 @@ package com.android.internal.app; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.DialogFragment; import android.content.DialogInterface; -import android.content.res.Configuration; -import android.os.Bundle; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import com.android.internal.app.chooser.DisplayResolveInfo; import com.android.internal.app.chooser.MultiDisplayResolveInfo; /** * Shows individual actions for a "stacked" app target - such as an app with multiple posting * streams represented in the Sharesheet. */ -public class ChooserStackedAppDialogFragment extends DialogFragment +public class ChooserStackedAppDialogFragment extends ChooserTargetActionsDialogFragment implements DialogInterface.OnClickListener { - private static final String TITLE_KEY = "title"; - private static final String PINNED_KEY = "pinned"; - private MultiDisplayResolveInfo mTargetInfos; - private CharSequence[] mLabels; + private MultiDisplayResolveInfo mMultiDisplayResolveInfo; private int mParentWhich; public ChooserStackedAppDialogFragment() { } - public ChooserStackedAppDialogFragment(CharSequence title, - MultiDisplayResolveInfo targets, CharSequence[] labels, int parentWhich) { - Bundle args = new Bundle(); - args.putCharSequence(TITLE_KEY, title); - mTargetInfos = targets; - mLabels = labels; + public ChooserStackedAppDialogFragment(MultiDisplayResolveInfo targets, + int parentWhich, UserHandle userHandle) { + super(targets.getTargets(), userHandle); + mMultiDisplayResolveInfo = targets; mParentWhich = parentWhich; - setArguments(args); } @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - return new Builder(getContext()) - .setCancelable(true) - .setItems(mLabels, this) - .setTitle(args.getCharSequence(TITLE_KEY)) - .create(); + protected CharSequence getItemLabel(DisplayResolveInfo dri) { + final PackageManager pm = getContext().getPackageManager(); + return dri.getResolveInfo().loadLabel(pm); } @Override - public void onClick(DialogInterface dialog, int which) { - final Bundle args = getArguments(); - mTargetInfos.setSelected(which); - ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); - dismiss(); + protected Drawable getItemIcon(DisplayResolveInfo dri) { + // Show no icon for the group disambig dialog, null hides the imageview + return null; } @Override - public void onConfigurationChanged(Configuration newConfig) { - // Dismiss on config changed (eg: rotation) - // TODO: Maintain state on config change - super.onConfigurationChanged(newConfig); + public void onClick(DialogInterface dialog, int which) { + mMultiDisplayResolveInfo.setSelected(which); + ((ChooserActivity) getActivity()).startSelected(mParentWhich, false, true); dismiss(); } } diff --git a/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java new file mode 100644 index 000000000000..3991a7674f38 --- /dev/null +++ b/core/java/com/android/internal/app/ChooserTargetActionsDialogFragment.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2016 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package com.android.internal.app; + +import static android.content.Context.ACTIVITY_SERVICE; + +import static com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; + +import static java.util.stream.Collectors.toList; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.app.ActivityManager; +import android.app.AlertDialog.Builder; +import android.app.Dialog; +import android.app.DialogFragment; +import android.content.ComponentName; +import android.content.DialogInterface; +import android.content.SharedPreferences; +import android.content.pm.PackageManager; +import android.content.res.Configuration; +import android.graphics.drawable.Drawable; +import android.os.Bundle; +import android.os.UserHandle; +import android.util.Pair; +import android.view.View; +import android.view.ViewGroup; +import android.widget.ArrayAdapter; +import android.widget.ImageView; +import android.widget.TextView; + +import com.android.internal.R; +import com.android.internal.app.chooser.DisplayResolveInfo; + +import java.util.ArrayList; +import java.util.List; + +/** + * Shows a dialog with actions to take on a chooser target. + */ +public class ChooserTargetActionsDialogFragment extends DialogFragment + implements DialogInterface.OnClickListener { + + protected List<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); + protected UserHandle mUserHandle; + + public ChooserTargetActionsDialogFragment() { + } + + public ChooserTargetActionsDialogFragment(List<DisplayResolveInfo> targets, + UserHandle userHandle) { + mUserHandle = userHandle; + mTargetInfos = targets; + } + + @Override + public Dialog onCreateDialog(Bundle savedInstanceState) { + + // Fetch UI details from target info + List<Pair<CharSequence, Drawable>> items = mTargetInfos.stream().map(dri -> { + return new Pair<>(getItemLabel(dri), getItemIcon(dri)); + }).collect(toList()); + + final ResolveInfoPresentationGetter pg = getProvidingAppPresentationGetter(); + return new Builder(getContext()) + .setTitle(pg.getLabel()) + .setIcon(pg.getIcon(mUserHandle)) + .setCancelable(true) + .setAdapter(getAdapterForContent(items), this) + .create(); + } + + protected ArrayAdapter<Pair<CharSequence, Drawable>> getAdapterForContent( + List<Pair<CharSequence, Drawable>> items) { + return new ArrayAdapter<Pair<CharSequence, Drawable>>(getContext(), + R.layout.chooser_dialog_item, R.id.text, items) { + @Override + public View getView(int position, View convertView, ViewGroup parent) { + View v = super.getView(position, convertView, parent); // super recycles views + TextView label = v.findViewById(R.id.text); + ImageView icon = v.findViewById(R.id.icon); + + Pair<CharSequence, Drawable> pair = getItem(position); + label.setText(pair.first); + + // Hide icon view if one isn't available + if (pair.second == null) { + icon.setVisibility(View.GONE); + } else { + icon.setImageDrawable(pair.second); + icon.setVisibility(View.VISIBLE); + } + + return v; + } + }; + } + + @Override + public void onClick(DialogInterface dialog, int which) { + pinComponent(mTargetInfos.get(which).getResolvedComponentName()); + ((ChooserActivity) getActivity()).handlePackagesChanged(); + dismiss(); + } + + private void pinComponent(ComponentName name) { + SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); + final String key = name.flattenToString(); + boolean currentVal = sp.getBoolean(name.flattenToString(), false); + if (currentVal) { + sp.edit().remove(key).apply(); + } else { + sp.edit().putBoolean(key, true).apply(); + } + } + + private Drawable getPinIcon(boolean isPinned) { + return isPinned + ? getContext().getDrawable(R.drawable.ic_close) + : getContext().getDrawable(R.drawable.ic_chooser_pin_dialog); + } + + private CharSequence getPinLabel(boolean isPinned, CharSequence targetLabel) { + return isPinned + ? getResources().getString(R.string.unpin_specific_target, targetLabel) + : getResources().getString(R.string.pin_specific_target, targetLabel); + } + + @NonNull + protected CharSequence getItemLabel(DisplayResolveInfo dri) { + final PackageManager pm = getContext().getPackageManager(); + return getPinLabel(dri.isPinned(), dri.getResolveInfo().loadLabel(pm)); + } + + @Nullable + protected Drawable getItemIcon(DisplayResolveInfo dri) { + return getPinIcon(dri.isPinned()); + } + + private ResolveInfoPresentationGetter getProvidingAppPresentationGetter() { + final ActivityManager am = (ActivityManager) getContext() + .getSystemService(ACTIVITY_SERVICE); + final int iconDpi = am.getLauncherLargeIconDensity(); + + // Use the matching application icon and label for the title, any TargetInfo will do + return new ResolveInfoPresentationGetter(getContext(), iconDpi, + mTargetInfos.get(0).getResolveInfo()); + } + + @Override + public void onConfigurationChanged(Configuration newConfig) { + // Dismiss on config changed (eg: rotation) + // TODO: Maintain state on config change + super.onConfigurationChanged(newConfig); + dismiss(); + } + +} diff --git a/core/java/com/android/internal/app/IntentForwarderActivity.java b/core/java/com/android/internal/app/IntentForwarderActivity.java index fca156a97a83..e65d1fe9ce53 100644 --- a/core/java/com/android/internal/app/IntentForwarderActivity.java +++ b/core/java/com/android/internal/app/IntentForwarderActivity.java @@ -18,6 +18,8 @@ package com.android.internal.app; import static android.content.pm.PackageManager.MATCH_DEFAULT_ONLY; +import static com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE; + import android.annotation.Nullable; import android.annotation.StringRes; import android.app.Activity; @@ -26,6 +28,7 @@ import android.app.ActivityThread; import android.app.AppGlobals; import android.app.admin.DevicePolicyManager; import android.compat.annotation.UnsupportedAppUsage; +import android.content.ComponentName; import android.content.ContentResolver; import android.content.Intent; import android.content.pm.ActivityInfo; @@ -74,6 +77,9 @@ public class IntentForwarderActivity extends Activity { private static final String TEL_SCHEME = "tel"; + private static final ComponentName RESOLVER_COMPONENT_NAME = + new ComponentName("android", ResolverActivity.class.getName()); + private Injector mInjector; private MetricsLogger mMetricsLogger; @@ -136,21 +142,50 @@ public class IntentForwarderActivity extends Activity { } newIntent.prepareToLeaveUser(callingUserId); - maybeShowDisclosureAsync(intentReceived, newIntent, targetUserId, userMessageId); - CompletableFuture.runAsync(() -> - startActivityAsCaller(newIntent, targetUserId), mExecutorService) - .thenAcceptAsync(result -> finish(), getApplicationContext().getMainExecutor()); + final CompletableFuture<ResolveInfo> targetResolveInfoFuture = + mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY, targetUserId); + targetResolveInfoFuture + .thenApplyAsync(targetResolveInfo -> { + if (isResolverActivityResolveInfo(targetResolveInfo)) { + launchResolverActivityWithCorrectTab(intentReceived, className, newIntent, + callingUserId, targetUserId); + return targetResolveInfo; + } + startActivityAsCaller(newIntent, targetUserId); + return targetResolveInfo; + }, mExecutorService) + .thenAcceptAsync(result -> { + maybeShowDisclosure(intentReceived, result, userMessageId); + finish(); + }, getApplicationContext().getMainExecutor()); } - private void maybeShowDisclosureAsync( - Intent intentReceived, Intent newIntent, int userId, int messageId) { - final CompletableFuture<ResolveInfo> resolveInfoFuture = - mInjector.resolveActivityAsUser(newIntent, MATCH_DEFAULT_ONLY, userId); - resolveInfoFuture.thenAcceptAsync(ri -> { - if (shouldShowDisclosure(ri, intentReceived)) { - mInjector.showToast(messageId, Toast.LENGTH_LONG); - } - }, getApplicationContext().getMainExecutor()); + private boolean isIntentForwarderResolveInfo(ResolveInfo resolveInfo) { + if (resolveInfo == null) { + return false; + } + ActivityInfo activityInfo = resolveInfo.activityInfo; + if (activityInfo == null) { + return false; + } + if (!"android".equals(activityInfo.packageName)) { + return false; + } + return activityInfo.name.equals(FORWARD_INTENT_TO_PARENT) + || activityInfo.name.equals(FORWARD_INTENT_TO_MANAGED_PROFILE); + } + + private boolean isResolverActivityResolveInfo(@Nullable ResolveInfo resolveInfo) { + return resolveInfo != null + && resolveInfo.activityInfo != null + && RESOLVER_COMPONENT_NAME.equals(resolveInfo.activityInfo.getComponentName()); + } + + private void maybeShowDisclosure( + Intent intentReceived, ResolveInfo resolveInfo, int messageId) { + if (shouldShowDisclosure(resolveInfo, intentReceived)) { + mInjector.showToast(messageId, Toast.LENGTH_LONG); + } } private void startActivityAsCaller(Intent newIntent, int userId) { @@ -185,7 +220,7 @@ public class IntentForwarderActivity extends Activity { // when cross-profile intents are disabled. int selectedProfile = findSelectedProfile(className); sanitizeIntent(intentReceived); - intentReceived.putExtra(ChooserActivity.EXTRA_SELECTED_PROFILE, selectedProfile); + intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile); Intent innerIntent = intentReceived.getParcelableExtra(Intent.EXTRA_INTENT); if (innerIntent == null) { Slog.wtf(TAG, "Cannot start a chooser intent with no extra " + Intent.EXTRA_INTENT); @@ -196,6 +231,25 @@ public class IntentForwarderActivity extends Activity { finish(); } + private void launchResolverActivityWithCorrectTab(Intent intentReceived, String className, + Intent newIntent, int callingUserId, int targetUserId) { + // When showing the intent resolver, instead of forwarding to the other profile, + // we launch it in the current user and select the other tab. This fixes b/155874820. + // + // In the case when there are 0 targets in the current profile and >1 apps in the other + // profile, the package manager launches the intent resolver in the other profile. + // If that's the case, we launch the resolver in the target user instead (other profile). + ResolveInfo callingResolveInfo = mInjector.resolveActivityAsUser( + newIntent, MATCH_DEFAULT_ONLY, callingUserId).join(); + int userId = isIntentForwarderResolveInfo(callingResolveInfo) + ? targetUserId : callingUserId; + int selectedProfile = findSelectedProfile(className); + sanitizeIntent(intentReceived); + intentReceived.putExtra(EXTRA_SELECTED_PROFILE, selectedProfile); + startActivityAsCaller(intentReceived, null, null, false, userId); + finish(); + } + private int findSelectedProfile(String className) { if (className.equals(FORWARD_INTENT_TO_PARENT)) { return ChooserActivity.PROFILE_PERSONAL; diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java index 182c7f272186..ff8fd50f308c 100644 --- a/core/java/com/android/internal/app/ResolverActivity.java +++ b/core/java/com/android/internal/app/ResolverActivity.java @@ -133,9 +133,6 @@ public class ResolverActivity extends Activity implements private CharSequence mTitle; private int mDefaultTitleResId; - @VisibleForTesting - protected boolean mUseLayoutForBrowsables; - // Whether or not this activity supports choosing a default handler for the intent. @VisibleForTesting protected boolean mSupportsAlwaysUseOption; @@ -179,6 +176,17 @@ public class ResolverActivity extends Activity implements // Intent extra for connected audio devices public static final String EXTRA_IS_AUDIO_CAPTURE_DEVICE = "is_audio_capture_device"; + /** + * Integer extra to indicate which profile should be automatically selected. + * <p>Can only be used if there is a work profile. + * <p>Possible values can be either {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK}. + */ + static final String EXTRA_SELECTED_PROFILE = + "com.android.internal.app.ResolverActivity.EXTRA_SELECTED_PROFILE"; + + static final int PROFILE_PERSONAL = AbstractMultiProfilePagerAdapter.PROFILE_PERSONAL; + static final int PROFILE_WORK = AbstractMultiProfilePagerAdapter.PROFILE_WORK; + private BroadcastReceiver mWorkProfileStateReceiver; private UserHandle mHeaderCreatorUser; @@ -353,10 +361,6 @@ public class ResolverActivity extends Activity implements mTitle = title; mDefaultTitleResId = defaultTitleRes; - mUseLayoutForBrowsables = getTargetIntent() == null - ? false - : isHttpSchemeAndViewAction(getTargetIntent()); - mSupportsAlwaysUseOption = supportsAlwaysUseOption; mWorkProfileUserHandle = fetchWorkProfileUserProfile(); @@ -450,7 +454,6 @@ public class ResolverActivity extends Activity implements initialIntents, rList, filterLastUsed, - mUseLayoutForBrowsables, /* userHandle */ UserHandle.of(UserHandle.myUserId())); return new ResolverMultiProfilePagerAdapter( /* context */ this, @@ -475,6 +478,10 @@ public class ResolverActivity extends Activity implements selectedProfile = PROFILE_WORK; } } + int selectedProfileExtra = getSelectedProfileExtra(); + if (selectedProfileExtra != -1) { + selectedProfile = selectedProfileExtra; + } // We only show the default app for the profile of the current user. The filterLastUsed // flag determines whether to show a default app and that app is not shown in the // resolver list. So filterLastUsed should be false for the other profile. @@ -485,7 +492,6 @@ public class ResolverActivity extends Activity implements rList, (filterLastUsed && UserHandle.myUserId() == getPersonalProfileUserHandle().getIdentifier()), - mUseLayoutForBrowsables, /* userHandle */ getPersonalProfileUserHandle()); UserHandle workProfileUserHandle = getWorkProfileUserHandle(); ResolverListAdapter workAdapter = createResolverListAdapter( @@ -495,7 +501,6 @@ public class ResolverActivity extends Activity implements rList, (filterLastUsed && UserHandle.myUserId() == workProfileUserHandle.getIdentifier()), - mUseLayoutForBrowsables, /* userHandle */ workProfileUserHandle); return new ResolverMultiProfilePagerAdapter( /* context */ this, @@ -512,6 +517,25 @@ public class ResolverActivity extends Activity implements } /** + * Returns {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK} if the {@link + * #EXTRA_SELECTED_PROFILE} extra was supplied, or {@code -1} if no extra was supplied. + * @throws IllegalArgumentException if the value passed to the {@link #EXTRA_SELECTED_PROFILE} + * extra is not {@link #PROFILE_PERSONAL} or {@link #PROFILE_WORK} + */ + int getSelectedProfileExtra() { + int selectedProfile = -1; + if (getIntent().hasExtra(EXTRA_SELECTED_PROFILE)) { + selectedProfile = getIntent().getIntExtra(EXTRA_SELECTED_PROFILE, /* defValue = */ -1); + if (selectedProfile != PROFILE_PERSONAL && selectedProfile != PROFILE_WORK) { + throw new IllegalArgumentException(EXTRA_SELECTED_PROFILE + " has invalid value " + + selectedProfile + ". Must be either ResolverActivity.PROFILE_PERSONAL or " + + "ResolverActivity.PROFILE_WORK."); + } + } + return selectedProfile; + } + + /** * Returns the user id of the user that the starting intent originated from. * <p>This is not necessarily equal to {@link #getUserId()} or {@link UserHandle#myUserId()}, * as there are edge cases when the intent resolver is launched in the other profile. @@ -741,26 +765,6 @@ public class ResolverActivity extends Activity implements mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredPosition() >= 0; if (title == ActionTitle.DEFAULT && defaultTitleRes != 0) { return getString(defaultTitleRes); - } else if (isHttpSchemeAndViewAction(intent)) { - // If the Intent's scheme is http(s) then we need to warn the user that - // they're giving access for the activity to open URLs from this specific host - String dialogTitle = null; - if (named && !mUseLayoutForBrowsables) { - dialogTitle = getString(ActionTitle.BROWSABLE_APP_TITLE_RES, - mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredItem() - .getDisplayLabel()); - } else if (named && mUseLayoutForBrowsables) { - dialogTitle = getString(ActionTitle.BROWSABLE_HOST_APP_TITLE_RES, - intent.getData().getHost(), - mMultiProfilePagerAdapter.getActiveListAdapter().getFilteredItem() - .getDisplayLabel()); - } else if (mMultiProfilePagerAdapter.getActiveListAdapter().areAllTargetsBrowsers()) { - dialogTitle = getString(ActionTitle.BROWSABLE_TITLE_RES); - } else { - dialogTitle = getString(ActionTitle.BROWSABLE_HOST_TITLE_RES, - intent.getData().getHost()); - } - return dialogTitle; } else { return named ? getString(title.namedTitleRes, mMultiProfilePagerAdapter @@ -873,12 +877,6 @@ public class ResolverActivity extends Activity implements mMultiProfilePagerAdapter.clearInactiveProfileCache(); } - private boolean isHttpSchemeAndViewAction(Intent intent) { - return (IntentFilter.SCHEME_HTTP.equals(intent.getScheme()) - || IntentFilter.SCHEME_HTTPS.equals(intent.getScheme())) - && Intent.ACTION_VIEW.equals(intent.getAction()); - } - private boolean hasManagedProfile() { UserManager userManager = (UserManager) getSystemService(Context.USER_SERVICE); if (userManager == null) { @@ -929,13 +927,9 @@ public class ResolverActivity extends Activity implements } else { enabled = true; } - if (mUseLayoutForBrowsables && !ri.handleAllWebDataURI) { - mAlwaysButton.setText(getResources() - .getString(R.string.activity_resolver_set_always)); - } else { - mAlwaysButton.setText(getResources() - .getString(R.string.activity_resolver_use_always)); - } + + mAlwaysButton.setText(getResources() + .getString(R.string.activity_resolver_use_always)); } if (ri != null) { @@ -965,31 +959,7 @@ public class ResolverActivity extends Activity implements ? currentListAdapter.getFilteredPosition() : listView.getCheckedItemPosition(); boolean hasIndexBeenFiltered = !currentListAdapter.hasFilteredItem(); - ResolveInfo ri = currentListAdapter.resolveInfoForPosition(which, hasIndexBeenFiltered); - if (mUseLayoutForBrowsables - && !ri.handleAllWebDataURI && id == R.id.button_always) { - showSettingsForSelected(ri); - } else { - startSelected(which, id == R.id.button_always, hasIndexBeenFiltered); - } - } - - private void showSettingsForSelected(ResolveInfo ri) { - Intent intent = new Intent(); - - final String packageName = ri.activityInfo.packageName; - Bundle showFragmentArgs = new Bundle(); - showFragmentArgs.putString(EXTRA_FRAGMENT_ARG_KEY, OPEN_LINKS_COMPONENT_KEY); - showFragmentArgs.putString("package", packageName); - - // For regular apps, we open the Open by Default page - intent.setAction(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS) - .setData(Uri.fromParts("package", packageName, null)) - .addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT) - .putExtra(EXTRA_FRAGMENT_ARG_KEY, OPEN_LINKS_COMPONENT_KEY) - .putExtra(EXTRA_SHOW_FRAGMENT_ARGS, showFragmentArgs); - - startActivity(intent); + startSelected(which, id == R.id.button_always, hasIndexBeenFiltered); } public void startSelected(int which, boolean always, boolean hasIndexBeenFiltered) { @@ -1381,12 +1351,12 @@ public class ResolverActivity extends Activity implements @VisibleForTesting protected ResolverListAdapter createResolverListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { + boolean filterLastUsed, UserHandle userHandle) { Intent startIntent = getIntent(); boolean isAudioCaptureDevice = startIntent.getBooleanExtra(EXTRA_IS_AUDIO_CAPTURE_DEVICE, false); return new ResolverListAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this, + filterLastUsed, createListController(userHandle), this, isAudioCaptureDevice); } @@ -1760,7 +1730,7 @@ public class ResolverActivity extends Activity implements listView.setOnItemClickListener(listener); listView.setOnItemLongClickListener(listener); - if (mSupportsAlwaysUseOption || mUseLayoutForBrowsables) { + if (mSupportsAlwaysUseOption) { listView.setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); } } @@ -1801,7 +1771,7 @@ public class ResolverActivity extends Activity implements } protected void resetButtonBar() { - if (!mSupportsAlwaysUseOption && !mUseLayoutForBrowsables) { + if (!mSupportsAlwaysUseOption) { return; } final ViewGroup buttonLayout = findViewById(R.id.button_bar); diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java index d942e859ccd0..97f43d27a9ce 100644 --- a/core/java/com/android/internal/app/ResolverListAdapter.java +++ b/core/java/com/android/internal/app/ResolverListAdapter.java @@ -69,13 +69,11 @@ public class ResolverListAdapter extends BaseAdapter { private final PackageManager mPm; protected final Context mContext; private final ColorMatrixColorFilter mSuspendedMatrixColorFilter; - private final boolean mUseLayoutForBrowsables; private final int mIconDpi; protected ResolveInfo mLastChosen; private DisplayResolveInfo mOtherProfile; ResolverListController mResolverListController; private int mPlaceholderCount; - private boolean mAllTargetsAreBrowsers = false; protected final LayoutInflater mInflater; @@ -94,7 +92,6 @@ public class ResolverListAdapter extends BaseAdapter { Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, ResolverListController resolverListController, - boolean useLayoutForBrowsables, ResolverListCommunicator resolverListCommunicator, boolean isAudioCaptureDevice) { mContext = context; @@ -107,7 +104,6 @@ public class ResolverListAdapter extends BaseAdapter { mFilterLastUsed = filterLastUsed; mResolverListController = resolverListController; mSuspendedMatrixColorFilter = createSuspendedColorMatrix(); - mUseLayoutForBrowsables = useLayoutForBrowsables; mResolverListCommunicator = resolverListCommunicator; mIsAudioCaptureDevice = isAudioCaptureDevice; final ActivityManager am = (ActivityManager) mContext.getSystemService(ACTIVITY_SERVICE); @@ -183,14 +179,6 @@ public class ResolverListAdapter extends BaseAdapter { } /** - * @return true if all items in the display list are defined as browsers by - * ResolveInfo.handleAllWebDataURI - */ - public boolean areAllTargetsBrowsers() { - return mAllTargetsAreBrowsers; - } - - /** * Rebuild the list of resolvers. In some cases some parts will need some asynchronous work * to complete. * @@ -207,7 +195,6 @@ public class ResolverListAdapter extends BaseAdapter { mOtherProfile = null; mLastChosen = null; mLastChosenPosition = -1; - mAllTargetsAreBrowsers = false; mDisplayList.clear(); mIsTabLoaded = false; @@ -322,8 +309,6 @@ public class ResolverListAdapter extends BaseAdapter { boolean doPostProcessing) { int n; if (sortedComponents != null && (n = sortedComponents.size()) != 0) { - mAllTargetsAreBrowsers = mUseLayoutForBrowsables; - // First put the initial items at the top. if (mInitialIntents != null) { for (int i = 0; i < mInitialIntents.length; i++) { @@ -353,7 +338,6 @@ public class ResolverListAdapter extends BaseAdapter { ri.noResourceId = true; ri.icon = 0; } - mAllTargetsAreBrowsers &= ri.handleAllWebDataURI; addResolveInfo(new DisplayResolveInfo(ii, ri, ri.loadLabel(mPm), null, ii, makePresentationGetter(ri))); @@ -364,7 +348,6 @@ public class ResolverListAdapter extends BaseAdapter { for (ResolvedComponentInfo rci : sortedComponents) { final ResolveInfo ri = rci.getResolveInfoAt(0); if (ri != null) { - mAllTargetsAreBrowsers &= ri.handleAllWebDataURI; addResolveInfoWithAlternates(rci); } } diff --git a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java b/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java deleted file mode 100644 index cdc600c51451..000000000000 --- a/core/java/com/android/internal/app/ResolverTargetActionsDialogFragment.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - - -package com.android.internal.app; - -import static android.content.Context.ACTIVITY_SERVICE; - -import static com.android.internal.app.ResolverListAdapter.ResolveInfoPresentationGetter; - -import android.app.ActivityManager; -import android.app.AlertDialog.Builder; -import android.app.Dialog; -import android.app.DialogFragment; -import android.content.ComponentName; -import android.content.DialogInterface; -import android.content.SharedPreferences; -import android.content.pm.PackageManager; -import android.content.res.Configuration; -import android.os.Bundle; -import android.os.UserHandle; - -import com.android.internal.R; -import com.android.internal.app.chooser.DisplayResolveInfo; -import com.android.internal.app.chooser.TargetInfo; - -import java.util.ArrayList; -import java.util.List; - -/** - * Shows a dialog with actions to take on a chooser target. - */ -public class ResolverTargetActionsDialogFragment extends DialogFragment - implements DialogInterface.OnClickListener { - - private List<DisplayResolveInfo> mTargetInfos = new ArrayList<>(); - private UserHandle mUserHandle; - - public ResolverTargetActionsDialogFragment() { - } - - public ResolverTargetActionsDialogFragment(List<DisplayResolveInfo> targets, - UserHandle userHandle) { - mUserHandle = userHandle; - mTargetInfos = targets; - } - - @Override - public Dialog onCreateDialog(Bundle savedInstanceState) { - final Bundle args = getArguments(); - final PackageManager pm = getContext().getPackageManager(); - - // Pin item for each sub-item - CharSequence[] items = new CharSequence[mTargetInfos.size()]; - for (int i = 0; i < mTargetInfos.size(); i++) { - final TargetInfo ti = mTargetInfos.get(i); - final CharSequence label = ti.getResolveInfo().loadLabel(pm); - items[i] = ti.isPinned() - ? getResources().getString(R.string.unpin_specific_target, label) - : getResources().getString(R.string.pin_specific_target, label); - } - - // Use the matching application icon and label for the title, any TargetInfo will do - final ActivityManager am = (ActivityManager) getContext() - .getSystemService(ACTIVITY_SERVICE); - final int iconDpi = am.getLauncherLargeIconDensity(); - final ResolveInfoPresentationGetter pg = new ResolveInfoPresentationGetter(getContext(), - iconDpi, mTargetInfos.get(0).getResolveInfo()); - - return new Builder(getContext()) - .setTitle(pg.getLabel()) - .setIcon(pg.getIcon(mUserHandle)) - .setCancelable(true) - .setItems(items, this) - .create(); - } - - @Override - public void onClick(DialogInterface dialog, int which) { - pinComponent(mTargetInfos.get(which).getResolvedComponentName()); - ((ChooserActivity) getActivity()).handlePackagesChanged(); - dismiss(); - } - - private void pinComponent(ComponentName name) { - SharedPreferences sp = ChooserActivity.getPinnedSharedPrefs(getContext()); - final String key = name.flattenToString(); - boolean currentVal = sp.getBoolean(name.flattenToString(), false); - if (currentVal) { - sp.edit().remove(key).apply(); - } else { - sp.edit().putBoolean(key, true).apply(); - } - } - - @Override - public void onConfigurationChanged(Configuration newConfig) { - // Dismiss on config changed (eg: rotation) - // TODO: Maintain state on config change - super.onConfigurationChanged(newConfig); - dismiss(); - } - -} diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 02cf25a7c3d2..476198b5311a 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -506,7 +506,8 @@ public class NativeLibraryHelper { } for (int i = 0; i < apkPaths.length; i++) { - if (!incrementalStorage.configureNativeBinaries(apkPaths[i], libRelativeDir, abi)) { + if (!incrementalStorage.configureNativeBinaries(apkPaths[i], libRelativeDir, abi, + handle.extractNativeLibs)) { return PackageManager.INSTALL_FAILED_INTERNAL_ERROR; } } diff --git a/core/java/com/android/internal/net/VpnProfile.java b/core/java/com/android/internal/net/VpnProfile.java index 829bd8a5a2a7..8ea5aa815a1c 100644 --- a/core/java/com/android/internal/net/VpnProfile.java +++ b/core/java/com/android/internal/net/VpnProfile.java @@ -136,13 +136,19 @@ public final class VpnProfile implements Cloneable, Parcelable { public boolean isMetered = false; // 21 public int maxMtu = PlatformVpnProfile.MAX_MTU_DEFAULT; // 22 public boolean areAuthParamsInline = false; // 23 + public final boolean isRestrictedToTestNetworks; // 24 // Helper fields. @UnsupportedAppUsage public transient boolean saveLogin = false; public VpnProfile(String key) { + this(key, false); + } + + public VpnProfile(String key, boolean isRestrictedToTestNetworks) { this.key = key; + this.isRestrictedToTestNetworks = isRestrictedToTestNetworks; } @UnsupportedAppUsage @@ -171,6 +177,7 @@ public final class VpnProfile implements Cloneable, Parcelable { isMetered = in.readBoolean(); maxMtu = in.readInt(); areAuthParamsInline = in.readBoolean(); + isRestrictedToTestNetworks = in.readBoolean(); } /** @@ -220,6 +227,7 @@ public final class VpnProfile implements Cloneable, Parcelable { out.writeBoolean(isMetered); out.writeInt(maxMtu); out.writeBoolean(areAuthParamsInline); + out.writeBoolean(isRestrictedToTestNetworks); } /** @@ -237,12 +245,21 @@ public final class VpnProfile implements Cloneable, Parcelable { String[] values = new String(value, StandardCharsets.UTF_8).split(VALUE_DELIMITER, -1); // Acceptable numbers of values are: // 14-19: Standard profile, with option for serverCert, proxy - // 24: Standard profile with serverCert, proxy and platform-VPN parameters. - if ((values.length < 14 || values.length > 19) && values.length != 24) { + // 24: Standard profile with serverCert, proxy and platform-VPN parameters + // 25: Standard profile with platform-VPN parameters and isRestrictedToTestNetworks + if ((values.length < 14 || values.length > 19) + && values.length != 24 && values.length != 25) { return null; } - VpnProfile profile = new VpnProfile(key); + final boolean isRestrictedToTestNetworks; + if (values.length >= 25) { + isRestrictedToTestNetworks = Boolean.parseBoolean(values[24]); + } else { + isRestrictedToTestNetworks = false; + } + + VpnProfile profile = new VpnProfile(key, isRestrictedToTestNetworks); profile.name = values[0]; profile.type = Integer.parseInt(values[1]); if (profile.type < 0 || profile.type > TYPE_MAX) { @@ -283,6 +300,8 @@ public final class VpnProfile implements Cloneable, Parcelable { profile.areAuthParamsInline = Boolean.parseBoolean(values[23]); } + // isRestrictedToTestNetworks (values[24]) assigned as part of the constructor + profile.saveLogin = !profile.username.isEmpty() || !profile.password.isEmpty(); return profile; } catch (Exception e) { @@ -330,6 +349,7 @@ public final class VpnProfile implements Cloneable, Parcelable { builder.append(VALUE_DELIMITER).append(isMetered); builder.append(VALUE_DELIMITER).append(maxMtu); builder.append(VALUE_DELIMITER).append(areAuthParamsInline); + builder.append(VALUE_DELIMITER).append(isRestrictedToTestNetworks); return builder.toString().getBytes(StandardCharsets.UTF_8); } @@ -421,7 +441,8 @@ public final class VpnProfile implements Cloneable, Parcelable { return Objects.hash( key, type, server, username, password, dnsServers, searchDomains, routes, mppe, l2tpSecret, ipsecIdentifier, ipsecSecret, ipsecUserCert, ipsecCaCert, ipsecServerCert, - proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline); + proxy, mAllowedAlgorithms, isBypassable, isMetered, maxMtu, areAuthParamsInline, + isRestrictedToTestNetworks); } /** Checks VPN profiles for interior equality. */ @@ -453,7 +474,8 @@ public final class VpnProfile implements Cloneable, Parcelable { && isBypassable == other.isBypassable && isMetered == other.isMetered && maxMtu == other.maxMtu - && areAuthParamsInline == other.areAuthParamsInline; + && areAuthParamsInline == other.areAuthParamsInline + && isRestrictedToTestNetworks == other.isRestrictedToTestNetworks; } @NonNull diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java index 415e21062aa5..5a1af84eccac 100644 --- a/core/java/com/android/internal/os/BatteryStatsImpl.java +++ b/core/java/com/android/internal/os/BatteryStatsImpl.java @@ -9875,6 +9875,10 @@ public class BatteryStatsImpl extends BatteryStats { mPlatformIdleStateCallback = cb; mRailEnergyDataCallback = railStatsCb; mUserInfoProvider = userInfoProvider; + + // Notify statsd that the system is initially not in doze. + mDeviceIdleMode = DEVICE_IDLE_MODE_OFF; + FrameworkStatsLog.write(FrameworkStatsLog.DEVICE_IDLE_MODE_STATE_CHANGED, mDeviceIdleMode); } @UnsupportedAppUsage diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java index c2b13c971020..2e32730a6ecb 100644 --- a/core/java/com/android/internal/os/ZygoteInit.java +++ b/core/java/com/android/internal/os/ZygoteInit.java @@ -376,11 +376,17 @@ public class ZygoteInit { null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); hidlManager.addDependency(hidlBase); + SharedLibraryInfo androidTestBase = new SharedLibraryInfo( + "/system/framework/android.test.base.jar", null /*packageName*/, + null /*codePaths*/, null /*name*/, 0 /*version*/, SharedLibraryInfo.TYPE_BUILTIN, + null /*declaringPackage*/, null /*dependentPackages*/, null /*dependencies*/); + ApplicationLoaders.getDefault().createAndCacheNonBootclasspathSystemClassLoaders( new SharedLibraryInfo[]{ // ordered dependencies first hidlBase, hidlManager, + androidTestBase, }); } diff --git a/core/jni/android_hardware_display_DisplayViewport.cpp b/core/jni/android_hardware_display_DisplayViewport.cpp index e74aafe61e00..c25da0fcad62 100644 --- a/core/jni/android_hardware_display_DisplayViewport.cpp +++ b/core/jni/android_hardware_display_DisplayViewport.cpp @@ -34,6 +34,7 @@ static struct { jclass clazz; jfieldID displayId; + jfieldID isActive; jfieldID orientation; jfieldID logicalFrame; jfieldID physicalFrame; @@ -59,6 +60,7 @@ status_t android_hardware_display_DisplayViewport_toNative(JNIEnv* env, jobject static const jmethodID byteValue = env->GetMethodID(byteClass, "byteValue", "()B"); viewport->displayId = env->GetIntField(viewportObj, gDisplayViewportClassInfo.displayId); + viewport->isActive = env->GetBooleanField(viewportObj, gDisplayViewportClassInfo.isActive); viewport->orientation = env->GetIntField(viewportObj, gDisplayViewportClassInfo.orientation); viewport->deviceWidth = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceWidth); viewport->deviceHeight = env->GetIntField(viewportObj, gDisplayViewportClassInfo.deviceHeight); @@ -104,6 +106,9 @@ int register_android_hardware_display_DisplayViewport(JNIEnv* env) { gDisplayViewportClassInfo.displayId = GetFieldIDOrDie(env, gDisplayViewportClassInfo.clazz, "displayId", "I"); + gDisplayViewportClassInfo.isActive = + GetFieldIDOrDie(env, gDisplayViewportClassInfo.clazz, "isActive", "Z"); + gDisplayViewportClassInfo.orientation = GetFieldIDOrDie(env, gDisplayViewportClassInfo.clazz, "orientation", "I"); diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto index 762895b6320f..023197baef12 100644 --- a/core/proto/android/providers/settings/global.proto +++ b/core/proto/android/providers/settings/global.proto @@ -695,6 +695,8 @@ message GlobalSettingsProto { } optional Notification notification = 82; + optional SettingProto nr_nsa_tracking_screen_off_mode = 153 [ (android.privacy).dest = DEST_AUTOMATIC ]; + optional SettingProto nsd_on = 83 [ (android.privacy).dest = DEST_AUTOMATIC ]; message Ntp { @@ -1060,5 +1062,5 @@ message GlobalSettingsProto { // Please insert fields in alphabetical order and group them into messages // if possible (to avoid reaching the method limit). - // Next tag = 153; + // Next tag = 154; } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index f285d9504822..c661fd4f4478 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -5001,7 +5001,8 @@ <permission android:name="android.permission.ASSOCIATE_INPUT_DEVICE_TO_DISPLAY_BY_PORT" android:protectionLevel="signature" /> - <!-- Allows query of any normal app on the device, regardless of manifest declarations. --> + <!-- Allows query of any normal app on the device, regardless of manifest declarations. + <p>Protection level: normal --> <permission android:name="android.permission.QUERY_ALL_PACKAGES" android:protectionLevel="normal" /> <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> diff --git a/packages/SystemUI/res/drawable/stat_sys_media.xml b/core/res/res/drawable/ic_chooser_pin_dialog.xml index d48db7bd0d28..2ac01c79e316 100644 --- a/packages/SystemUI/res/drawable/stat_sys_media.xml +++ b/core/res/res/drawable/ic_chooser_pin_dialog.xml @@ -15,17 +15,11 @@ --> <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="M5,7.81l0,8.38l6,-4.19z" - android:fillColor="#000000"/> - <path - android:pathData="M13,8h2v8h-2z" - android:fillColor="#000000"/> - <path - android:pathData="M17,8h2v8h-2z" - android:fillColor="#000000"/> + android:width="24dp" + android:height="24dp" + android:viewportWidth="24" + android:viewportHeight="24"> + <path + android:pathData="M14,4v5c0,1.12 0.37,2.16 1,3H9c0.65,-0.86 1,-1.9 1,-3V4H14M17,2H7C6.45,2 6,2.45 6,3c0,0.55 0.45,1 1,1c0,0 0,0 0,0l1,0v5c0,1.66 -1.34,3 -3,3v2h5.97v7l1,1l1,-1v-7H19v-2c0,0 0,0 0,0c-1.66,0 -3,-1.34 -3,-3V4l1,0c0,0 0,0 0,0c0.55,0 1,-0.45 1,-1C18,2.45 17.55,2 17,2L17,2z" + android:fillColor="#FF000000"/> </vector> diff --git a/core/res/res/layout/chooser_dialog_item.xml b/core/res/res/layout/chooser_dialog_item.xml new file mode 100644 index 000000000000..1d6369793bfb --- /dev/null +++ b/core/res/res/layout/chooser_dialog_item.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" + android:orientation="horizontal" + android:gravity="start|center_vertical" + android:paddingStart="?attr/dialogPreferredPadding" + android:paddingEnd="?attr/dialogPreferredPadding" + android:minHeight="48dp" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <!-- Icon and text aligns with aligns with alert_dialog_title_material --> + <ImageView android:id="@+id/icon" + android:tint="?android:attr/textColorAlertDialogListItem" + android:padding="4dp" + android:layout_marginEnd="8dp" + android:layout_width="32dp" + android:layout_height="32dp"/> + + <!-- Using text style from select_dialog_item_material --> + <TextView android:id="@+id/text" + android:textAppearance="?android:attr/textAppearanceListItemSmall" + android:textColor="?android:attr/textColorAlertDialogListItem" + android:lines="1" + android:ellipsize="end" + android:layout_width="wrap_content" + android:layout_height="wrap_content"/> + +</LinearLayout>
\ No newline at end of file diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index cb65f7c39005..1379ea71f9da 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -1091,7 +1091,7 @@ <string name="elapsed_time_short_format_h_mm_ss" msgid="2302144714803345056">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string> <string name="selectAll" msgid="1532369154488982046">"အားလုံးရွေးရန်"</string> <string name="cut" msgid="2561199725874745819">"ဖြတ်ခြင်း"</string> - <string name="copy" msgid="5472512047143665218">"ကူးခြင်း"</string> + <string name="copy" msgid="5472512047143665218">"ကူးရန်"</string> <string name="failed_to_copy_to_clipboard" msgid="725919885138539875">"ကလစ်ဘုတ်သို့ မိတ္တူကူးခြင်း မအောင်မြင်ပါ"</string> <string name="paste" msgid="461843306215520225">"Paste"</string> <string name="paste_as_plain_text" msgid="7664800665823182587">"စာသားအတိုင်း ကူးထည့်ပါ"</string> diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml index 368e307f9ff5..34b6a54be493 100644 --- a/core/res/res/values-sw600dp/config.xml +++ b/core/res/res/values-sw600dp/config.xml @@ -48,5 +48,8 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">true</bool> + + <!-- If true, show multiuser switcher by default unless the user specifically disables it. --> + <bool name="config_showUserSwitcherByDefault">true</bool> </resources> diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml index a205fcf9520b..2cad9e6888a6 100644 --- a/core/res/res/values/config.xml +++ b/core/res/res/values/config.xml @@ -42,7 +42,6 @@ <item><xliff:g id="id">@string/status_bar_phone_evdo_signal</xliff:g></item> <item><xliff:g id="id">@string/status_bar_phone_signal</xliff:g></item> <item><xliff:g id="id">@string/status_bar_secure</xliff:g></item> - <item><xliff:g id="id">@string/status_bar_media</xliff:g></item> <item><xliff:g id="id">@string/status_bar_managed_profile</xliff:g></item> <item><xliff:g id="id">@string/status_bar_cast</xliff:g></item> <item><xliff:g id="id">@string/status_bar_screen_record</xliff:g></item> @@ -97,7 +96,6 @@ <string translatable="false" name="status_bar_airplane">airplane</string> <string translatable="false" name="status_bar_sensors_off">sensors_off</string> <string translatable="false" name="status_bar_screen_record">screen_record</string> - <string translatable="false" name="status_bar_media">media</string> <!-- Flag indicating whether the surface flinger has limited alpha compositing functionality in hardware. If set, the window @@ -4311,6 +4309,10 @@ (default 2MB) --> <integer name="config_notificationStripRemoteViewSizeBytes">5000000</integer> + <!-- List of packages that can use the Conversation space for their category messages + notifications until they target R --> + <string-array name="config_notificationMsgPkgsAllowedAsConvos" translatable="false"/> + <!-- Contains a blacklist of apps that should not get pre-installed carrier app permission grants, even if the UICC claims that the app should be privileged. See b/138150105 --> <string-array name="config_restrictedPreinstalledCarrierApps" translatable="false"/> @@ -4444,6 +4446,9 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <bool name="config_keyguardUserSwitcher">false</bool> + <!-- If true, show multiuser switcher by default unless the user specifically disables it. --> + <bool name="config_showUserSwitcherByDefault">false</bool> + <!-- Set to true to make assistant show in front of the dream/screensaver. --> <bool name="config_assistantOnTopOfDream">false</bool> @@ -4451,4 +4456,11 @@ <bool name="config_pdp_reject_enable_retry">false</bool> <!-- pdp data reject retry delay in ms --> <integer name="config_pdp_reject_retry_delay_ms">-1</integer> + + <!-- Package name that is recognized as an actor for the packages listed in + @array/config_overlayableConfiguratorTargets. If an overlay targeting one of the listed + targets is signed with the same signature as the configurator, the overlay will be granted + the "actor" policy. --> + <string name="config_overlayableConfigurator" translatable="false" /> + <string-array name="config_overlayableConfiguratorTargets" translatable="false" /> </resources> diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml index 233f72eaae1f..dc21e878d132 100644 --- a/core/res/res/values/strings.xml +++ b/core/res/res/values/strings.xml @@ -456,12 +456,12 @@ days the profile is allowed to be off and this number is at least 3. [CHAR LIMIT=NONE] --> <string name="personal_apps_suspension_soon_text"> Personal apps will be blocked on <xliff:g id="date" example="May 29">%1$s</xliff:g> at - <xliff:g id="time" example="5:20 PM">%2$s</xliff:g>. Your work profile can\u2019t stay off - for more than <xliff:g id="number" example="3">%3$d</xliff:g> days. + <xliff:g id="time" example="5:20 PM">%2$s</xliff:g>. Your IT admin doesn\u2019t allow your + work profile to stay off for more than <xliff:g id="number" example="3">%3$d</xliff:g> days. </string> <!-- Title for the button that turns work profile on. To be used in a notification [CHAR LIMIT=NONE] --> - <string name="personal_apps_suspended_turn_profile_on">Turn on work profile</string> + <string name="personal_apps_suspended_turn_profile_on">Turn on</string> <!-- Display name for any time a piece of data refers to the owner of the phone. For example, this could be used in place of the phone's phone number. --> <string name="me">Me</string> @@ -4138,17 +4138,9 @@ <string name="activity_resolver_use_always">Always</string> <!-- Title for a button to choose the currently selected activity - as the default in the activity resolver. [CHAR LIMIT=50] --> - <string name="activity_resolver_set_always">Set to always open</string> - - <!-- Title for a button to choose the currently selected activity from the activity resolver to use just this once. [CHAR LIMIT=25] --> <string name="activity_resolver_use_once">Just once</string> - <!-- Title for a button to choose to go to - 'Open by Default' app settings. [CHAR LIMIT=25] --> - <string name="activity_resolver_app_settings">Settings</string> - <!-- Text for the toast that is shown when the user clicks on a launcher that doesn't support the work profile. [CHAR LIMIT=100] --> <string name="activity_resolver_work_profiles_support">%1$s doesn\'t support work profile</string> diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml index 758a4f7baffc..878b8db3f1e8 100644 --- a/core/res/res/values/symbols.xml +++ b/core/res/res/values/symbols.xml @@ -2552,7 +2552,6 @@ <java-symbol type="bool" name="config_allow_ussd_over_ims" /> <java-symbol type="attr" name="touchscreenBlocksFocus" /> <java-symbol type="layout" name="resolver_list_with_default" /> - <java-symbol type="string" name="activity_resolver_set_always" /> <java-symbol type="string" name="activity_resolver_use_always" /> <java-symbol type="string" name="whichApplicationNamed" /> <java-symbol type="string" name="whichApplicationLabel" /> @@ -2748,6 +2747,7 @@ <java-symbol type="drawable" name="ic_chooser_group_arrow"/> <java-symbol type="drawable" name="chooser_group_background"/> <java-symbol type="drawable" name="ic_chooser_pin"/> + <java-symbol type="drawable" name="ic_chooser_pin_dialog"/> <java-symbol type="drawable" name="chooser_pinned_background"/> <java-symbol type="integer" name="config_maxShortcutTargetsPerApp" /> <java-symbol type="layout" name="resolve_grid_item" /> @@ -2916,7 +2916,6 @@ <java-symbol type="string" name="status_bar_camera" /> <java-symbol type="string" name="status_bar_sensors_off" /> <java-symbol type="string" name="status_bar_screen_record" /> - <java-symbol type="string" name="status_bar_media" /> <!-- Locale picker --> <java-symbol type="id" name="locale_search_menu" /> @@ -3835,10 +3834,12 @@ <java-symbol type="string" name="config_factoryResetPackage" /> <java-symbol type="array" name="config_highRefreshRateBlacklist" /> + <java-symbol type="layout" name="chooser_dialog_item" /> <java-symbol type="id" name="chooser_copy_button" /> <java-symbol type="layout" name="chooser_action_button" /> <java-symbol type="dimen" name="chooser_action_button_icon_size" /> <java-symbol type="string" name="config_defaultNearbySharingComponent" /> + <java-symbol type="drawable" name="ic_close" /> <java-symbol type="bool" name="config_automotiveHideNavBarForKeyboard" /> @@ -4006,6 +4007,9 @@ <!-- Set to true to enable the user switcher on the keyguard. --> <java-symbol type="bool" name="config_keyguardUserSwitcher" /> + <!-- If true, show multiuser switcher by default unless the user specifically disables it. --> + <java-symbol type="bool" name="config_showUserSwitcherByDefault" /> + <!-- Set to true to make assistant show in front of the dream/screensaver. --> <java-symbol type="bool" name="config_assistantOnTopOfDream"/> @@ -4025,4 +4029,8 @@ <java-symbol type="string" name="config_pdp_reject_service_not_subscribed" /> <java-symbol type="string" name="config_pdp_reject_multi_conn_to_same_pdn_not_allowed" /> + <java-symbol type="string" name="config_overlayableConfigurator" /> + <java-symbol type="array" name="config_overlayableConfiguratorTargets" /> + + <java-symbol type="array" name="config_notificationMsgPkgsAllowedAsConvos" /> </resources> diff --git a/core/tests/InstantAppResolverTests/Android.bp b/core/tests/InstantAppResolverTests/Android.bp deleted file mode 100644 index 7b01010ebb2b..000000000000 --- a/core/tests/InstantAppResolverTests/Android.bp +++ /dev/null @@ -1,32 +0,0 @@ -// -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -android_test { - name: "FrameworksInstantAppResolverTests", - srcs: [ "src/**/*.kt" ], - libs: [ - "android.test.runner", - "android.test.base", - ], - platform_apis: true, - static_libs: [ - "androidx.test.ext.junit", - "androidx.test.rules", - "mockito-target-minus-junit4", - "truth-prebuilt", - ], - test_suites: ["device-tests"], -} diff --git a/core/tests/InstantAppResolverTests/AndroidManifest.xml b/core/tests/InstantAppResolverTests/AndroidManifest.xml deleted file mode 100644 index f95978b5a63e..000000000000 --- a/core/tests/InstantAppResolverTests/AndroidManifest.xml +++ /dev/null @@ -1,33 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<manifest - xmlns:android="http://schemas.android.com/apk/res/android" - package="android.app.instantapp.resolver.test" - > - - <application> - <uses-library android:name="android.test.runner"/> - </application> - - <instrumentation - android:name="androidx.test.runner.AndroidJUnitRunner" - android:label="InstantAppResolverTests" - android:targetPackage="android.app.instantapp.resolver.test" - /> - -</manifest> diff --git a/core/tests/InstantAppResolverTests/AndroidTest.xml b/core/tests/InstantAppResolverTests/AndroidTest.xml deleted file mode 100644 index fcc6344efd83..000000000000 --- a/core/tests/InstantAppResolverTests/AndroidTest.xml +++ /dev/null @@ -1,29 +0,0 @@ -<?xml version="1.0" encoding="utf-8"?> -<!-- - ~ Copyright (C) 2019 The Android Open Source Project - ~ - ~ Licensed under the Apache License, Version 2.0 (the "License"); - ~ you may not use this file except in compliance with the License. - ~ You may obtain a copy of the License at - ~ - ~ http://www.apache.org/licenses/LICENSE-2.0 - ~ - ~ Unless required by applicable law or agreed to in writing, software - ~ distributed under the License is distributed on an "AS IS" BASIS, - ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - ~ See the License for the specific language governing permissions and - ~ limitations under the License. - --> - -<configuration description="Test module config for InstantAppResolverTests"> - <option name="test-tag" value="InstantAppResolverTests" /> - - <target_preparer class="com.android.tradefed.targetprep.TestAppInstallSetup"> - <option name="cleanup-apks" value="true" /> - <option name="test-file-name" value="FrameworksInstantAppResolverTests.apk" /> - </target_preparer> - - <test class="com.android.tradefed.testtype.AndroidJUnitTest"> - <option name="package" value="android.app.instantapp.resolver.test" /> - </test> -</configuration> diff --git a/core/tests/InstantAppResolverTests/src/android/app/instantapp/resolver/test/ResolverServiceMethodFallbackTest.kt b/core/tests/InstantAppResolverTests/src/android/app/instantapp/resolver/test/ResolverServiceMethodFallbackTest.kt deleted file mode 100644 index 2a17ef210d36..000000000000 --- a/core/tests/InstantAppResolverTests/src/android/app/instantapp/resolver/test/ResolverServiceMethodFallbackTest.kt +++ /dev/null @@ -1,174 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.app.instantapp.resolver.test - -import android.app.InstantAppResolverService -import android.app.InstantAppResolverService.InstantAppResolutionCallback -import android.content.Intent -import android.content.pm.InstantAppRequestInfo -import android.net.Uri -import android.os.Bundle -import android.os.IRemoteCallback -import android.os.UserHandle -import com.google.common.truth.Truth.assertThat -import org.junit.Before -import org.junit.Rule -import org.junit.Test -import org.junit.rules.ExpectedException -import org.junit.runner.RunWith -import org.junit.runners.Parameterized -import org.mockito.Answers -import org.mockito.Mock -import org.mockito.Mockito.doNothing -import org.mockito.Mockito.never -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.MockitoAnnotations -import java.util.UUID -import kotlin.random.Random - -private typealias Method = InstantAppResolverService.(InstantAppRequestInfo) -> Unit - -@Suppress("max-line-length") -@RunWith(Parameterized::class) -class ResolverServiceMethodFallbackTest @Suppress("UNUSED_PARAMETER") constructor( - private val version: Int, - private val methodList: List<Method>, - private val info: InstantAppRequestInfo, - // Remaining only used to print human-readable test name - name: String, - isWebIntent: Boolean -) { - - companion object { - // Since the resolution callback class is final, mock the IRemoteCallback and have it throw - // a unique exception to indicate it was called. - class TestRemoteCallbackException : Exception() - - private val testIntentWeb = Intent(Intent.ACTION_VIEW, - Uri.parse("https://${this::class.java.canonicalName}.com")) - private val testIntentNotWeb = Intent(Intent.ACTION_VIEW, - Uri.parse("content://${this::class.java.canonicalName}")) - - private val testRemoteCallback = object : IRemoteCallback { - override fun sendResult(data: Bundle?) = throw TestRemoteCallbackException() - override fun asBinder() = throw UnsupportedOperationException() - } - private val testResolutionCallback = InstantAppResolutionCallback(0, testRemoteCallback) - private val testArray = IntArray(10) { Random.nextInt() } - private val testToken = UUID.randomUUID().toString() - private val testUser = UserHandle(Integer.MAX_VALUE) - private val testInfoWeb = InstantAppRequestInfo(testIntentWeb, testArray, testUser, - false, testToken) - private val testInfoNotWeb = InstantAppRequestInfo(testIntentNotWeb, testArray, testUser, - false, testToken) - - // Each section defines methods versions with later definitions falling back to - // earlier definitions. Each block receives an [InstantAppResolverService] and invokes - // the appropriate version with the test data defined above. - private val infoOne: Method = { onGetInstantAppResolveInfo(testArray, testToken, - testResolutionCallback) } - private val infoTwo: Method = { onGetInstantAppResolveInfo(it.intent, testArray, testToken, - testResolutionCallback) } - private val infoThree: Method = { onGetInstantAppResolveInfo(it.intent, testArray, testUser, - testToken, testResolutionCallback) } - private val infoFour: Method = { onGetInstantAppResolveInfo(it, testResolutionCallback) } - - private val filterOne: Method = { onGetInstantAppIntentFilter(testArray, testToken, - testResolutionCallback) } - private val filterTwo: Method = { onGetInstantAppIntentFilter(it.intent, testArray, - testToken, testResolutionCallback) } - private val filterThree: Method = { onGetInstantAppIntentFilter(it.intent, testArray, - testUser, testToken, testResolutionCallback) } - private val filterFour: Method = { onGetInstantAppIntentFilter(it, testResolutionCallback) } - - private val infoList = listOf(infoOne, infoTwo, infoThree, infoFour) - private val filterList = listOf(filterOne, filterTwo, filterThree, filterFour) - - @JvmStatic - @Parameterized.Parameters(name = "{3} version {0}, isWeb = {4}") - fun parameters(): Array<Array<*>> { - // Sanity check that web intent logic hasn't changed - assertThat(testInfoWeb.intent.isWebIntent).isTrue() - assertThat(testInfoNotWeb.intent.isWebIntent).isFalse() - - // Declare all the possible params - val versions = Array(5) { it } - val methods = arrayOf("ResolveInfo" to infoList, "IntentFilter" to filterList) - val infos = arrayOf(testInfoWeb, testInfoNotWeb) - - // FlatMap params into every possible combination - return infos.flatMap { info -> - methods.flatMap { (name, methods) -> - versions.map { version -> - arrayOf(version, methods, info, name, info.intent.isWebIntent) - } - } - }.toTypedArray() - } - } - - @field:Mock(answer = Answers.CALLS_REAL_METHODS) - lateinit var mockService: InstantAppResolverService - - @get:Rule - val expectedException = ExpectedException.none() - - @Before - fun setUpMocks() { - MockitoAnnotations.initMocks(this) - } - - @Test - fun onGetInstantApp() { - if (version == 0) { - // No version of the API was implemented, so expect terminal case - if (info.intent.isWebIntent) { - // If web intent, terminal is total failure - expectedException.expect(IllegalStateException::class.java) - } else { - // Otherwise, terminal is a fail safe by calling [testRemoteCallback] - expectedException.expect(TestRemoteCallbackException::class.java) - } - } else if (version < 2 && !info.intent.isWebIntent) { - // Starting from v2, if resolving a non-web intent and a v2+ method isn't implemented, - // it fails safely by calling [testRemoteCallback] - expectedException.expect(TestRemoteCallbackException::class.java) - } - - // Version 1 is the first method (index 0) - val methodIndex = version - 1 - - // Implement a method if necessary - methodList.getOrNull(methodIndex)?.invoke(doNothing().`when`(mockService), info) - - // Call the latest API - methodList.last().invoke(mockService, info) - - // Check all methods before implemented method are never called - (0 until methodIndex).forEach { - methodList[it].invoke(verify(mockService, never()), info) - } - - // Check all methods from implemented method are called - (methodIndex until methodList.size).forEach { - methodList[it].invoke(verify(mockService), info) - } - - verifyNoMoreInteractions(mockService) - } -} diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java index 2884777fc997..daaf31a6bb65 100644 --- a/core/tests/coretests/src/android/view/InsetsStateTest.java +++ b/core/tests/coretests/src/android/view/InsetsStateTest.java @@ -20,6 +20,8 @@ import static android.view.InsetsState.ISIDE_BOTTOM; import static android.view.InsetsState.ISIDE_TOP; import static android.view.InsetsState.ITYPE_BOTTOM_GESTURES; import static android.view.InsetsState.ITYPE_CAPTION_BAR; +import static android.view.InsetsState.ITYPE_CLIMATE_BAR; +import static android.view.InsetsState.ITYPE_EXTRA_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_IME; import static android.view.InsetsState.ITYPE_NAVIGATION_BAR; import static android.view.InsetsState.ITYPE_STATUS_BAR; @@ -183,6 +185,38 @@ public class InsetsStateTest { } @Test + public void testCalculateInsets_extraNavRightStatusTop() throws Exception { + try (InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(ITYPE_STATUS_BAR).setVisible(true); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(ITYPE_EXTRA_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, 0, 0, null); + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); + } + } + + @Test + public void testCalculateInsets_navigationRightClimateTop() throws Exception { + try (InsetsModeSession session = + new InsetsModeSession(ViewRootImpl.NEW_INSETS_MODE_FULL)) { + mState.getSource(ITYPE_CLIMATE_BAR).setFrame(new Rect(0, 0, 100, 100)); + mState.getSource(ITYPE_CLIMATE_BAR).setVisible(true); + mState.getSource(ITYPE_NAVIGATION_BAR).setFrame(new Rect(80, 0, 100, 300)); + mState.getSource(ITYPE_NAVIGATION_BAR).setVisible(true); + WindowInsets insets = mState.calculateInsets(new Rect(0, 0, 100, 300), null, false, + false, DisplayCutout.NO_CUTOUT, 0, 0, null); + assertEquals(Insets.of(0, 100, 20, 0), insets.getSystemWindowInsets()); + assertEquals(Insets.of(0, 100, 0, 0), insets.getInsets(Type.statusBars())); + assertEquals(Insets.of(0, 0, 20, 0), insets.getInsets(Type.navigationBars())); + } + } + + @Test public void testStripForDispatch() { mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100)); mState.getSource(ITYPE_STATUS_BAR).setVisible(true); diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java index 071b2259e1f0..749b0e54b880 100644 --- a/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ChooserWrapperActivity.java @@ -61,12 +61,12 @@ public class ChooserWrapperActivity extends ChooserActivity { @Override public ChooserListAdapter createChooserListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, - boolean useLayoutForBrowsables, ResolverListController resolverListController) { + ResolverListController resolverListController) { PackageManager packageManager = sOverrides.packageManager == null ? context.getPackageManager() : sOverrides.packageManager; return new ChooserListAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, resolverListController, useLayoutForBrowsables, + filterLastUsed, resolverListController, this, this, packageManager); } diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java index 208710498e1c..0c009a055e2b 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperActivity.java @@ -42,9 +42,9 @@ public class ResolverWrapperActivity extends ResolverActivity { @Override public ResolverListAdapter createResolverListAdapter(Context context, List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, - boolean filterLastUsed, boolean useLayoutForBrowsables, UserHandle userHandle) { + boolean filterLastUsed, UserHandle userHandle) { return new ResolverWrapperAdapter(context, payloadIntents, initialIntents, rList, - filterLastUsed, createListController(userHandle), useLayoutForBrowsables, this); + filterLastUsed, createListController(userHandle), this); } @Override @@ -166,4 +166,4 @@ public class ResolverWrapperActivity extends ResolverActivity { }; } } -}
\ No newline at end of file +} diff --git a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java index a2191b5fac80..56a70708b6df 100644 --- a/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java +++ b/core/tests/coretests/src/com/android/internal/app/ResolverWrapperAdapter.java @@ -35,11 +35,10 @@ public class ResolverWrapperAdapter extends ResolverListAdapter { List<Intent> payloadIntents, Intent[] initialIntents, List<ResolveInfo> rList, boolean filterLastUsed, - ResolverListController resolverListController, boolean useLayoutForBrowsables, + ResolverListController resolverListController, ResolverListCommunicator resolverListCommunicator) { super(context, payloadIntents, initialIntents, rList, filterLastUsed, - resolverListController, - useLayoutForBrowsables, resolverListCommunicator, false); + resolverListController, resolverListCommunicator, false); } public CountingIdlingResource getLabelIdlingResource() { diff --git a/data/etc/platform.xml b/data/etc/platform.xml index 9cd7cc6aedcf..cf312165dd9a 100644 --- a/data/etc/platform.xml +++ b/data/etc/platform.xml @@ -249,6 +249,7 @@ <allow-in-data-usage-save package="com.android.providers.downloads" /> <!-- This is a core platform component that needs to freely run in the background --> + <allow-in-power-save package="com.android.cellbroadcastreceiver.module" /> <allow-in-power-save package="com.android.cellbroadcastreceiver" /> <allow-in-power-save package="com.android.shell" /> diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml index bdb6bcc1f19f..04fead8d4b32 100644 --- a/data/etc/privapp-permissions-platform.xml +++ b/data/etc/privapp-permissions-platform.xml @@ -40,7 +40,7 @@ applications that come with the platform <permission name="android.permission.CRYPT_KEEPER"/> </privapp-permissions> - <privapp-permissions package="com.android.cellbroadcastreceiver"> + <privapp-permissions package="com.android.cellbroadcastreceiver.module"> <permission name="android.permission.INTERACT_ACROSS_USERS"/> <permission name="android.permission.MANAGE_USERS"/> <permission name="android.permission.MODIFY_PHONE_STATE"/> @@ -409,6 +409,10 @@ applications that come with the platform <permission name="android.permission.ACCESS_TV_DESCRAMBLER" /> <permission name="android.permission.ACCESS_TV_TUNER" /> <permission name="android.permission.TUNER_RESOURCE_ACCESS" /> + <!-- Permissions required for CTS test - TVInputManagerTest --> + <permission name="android.permission.TV_INPUT_HARDWARE" /> + <!-- Permission required for CTS test - PrivilegedLocationPermissionTest --> + <permission name="android.permission.LOCATION_HARDWARE" /> </privapp-permissions> <privapp-permissions package="com.android.statementservice"> diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index b5c19a895413..bfc623faeaef 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -253,6 +253,12 @@ "group": "WM_DEBUG_ORIENTATION", "at": "com\/android\/server\/wm\/DisplayRotation.java" }, + "-1554521902": { + "message": "showInsets(ime) was requested by different window: %s ", + "level": "WARN", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "-1545962566": { "message": "View server did not start", "level": "WARN", @@ -367,6 +373,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "-1312861660": { + "message": "notifyInsetsControlChanged for %s ", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/WindowState.java" + }, "-1292329638": { "message": "Added starting %s: startingWindow=%s startingView=%s", "level": "VERBOSE", @@ -817,6 +829,12 @@ "group": "WM_DEBUG_STARTING_WINDOW", "at": "com\/android\/server\/wm\/TaskSnapshotSurface.java" }, + "-395922585": { + "message": "InsetsSource setWin %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, "-393505149": { "message": "unable to update pointer icon", "level": "WARN", @@ -859,6 +877,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "-322743468": { + "message": "setInputMethodInputTarget %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "-322035974": { "message": "App freeze timeout expired.", "level": "WARN", @@ -925,6 +949,12 @@ "group": "WM_DEBUG_SCREEN_ON", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "-112805366": { + "message": "InsetsSource updateVisibility serverVisible: %s clientVisible: %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, "-106400104": { "message": "Preload recents with %s", "level": "DEBUG", @@ -1003,6 +1033,12 @@ "group": "WM_DEBUG_RECENTS_ANIMATIONS", "at": "com\/android\/server\/wm\/RecentsAnimationController.java" }, + "29780972": { + "message": "InsetsSource Control %s for target %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, "38267433": { "message": "Attempted to reset replacing window on non-existing app token %s", "level": "WARN", @@ -1027,6 +1063,18 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, + "73987756": { + "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, + "75707221": { + "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsSourceProvider.java" + }, "83950285": { "message": "removeAnimation(%d)", "level": "DEBUG", @@ -1285,12 +1333,6 @@ "group": "WM_ERROR", "at": "com\/android\/server\/wm\/WindowManagerService.java" }, - "438102669": { - "message": "call showInsets(ime) on %s", - "level": "DEBUG", - "group": "WM_DEBUG_IME", - "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" - }, "457951957": { "message": "\tNot visible=%s", "level": "DEBUG", @@ -1369,6 +1411,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "585839596": { + "message": "call showInsets(ime) on %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java" + }, "594260577": { "message": "createWallpaperAnimations()", "level": "DEBUG", @@ -1873,6 +1921,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1533154777": { + "message": "notifyInsetsChanged for %s ", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/WindowState.java" + }, "1563755163": { "message": "Permission Denial: %s from pid=%d, uid=%d requires %s", "level": "WARN", @@ -1897,6 +1951,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS_ANIM", "at": "com\/android\/server\/wm\/AppTransition.java" }, + "1591969812": { + "message": "updateImeControlTarget %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "1628345525": { "message": "Now opening app %s", "level": "VERBOSE", @@ -1927,6 +1987,12 @@ "group": "WM_DEBUG_APP_TRANSITIONS", "at": "com\/android\/server\/wm\/ActivityRecord.java" }, + "1658605381": { + "message": "onImeControlTargetChanged %s", + "level": "DEBUG", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/InsetsStateController.java" + }, "1671994402": { "message": "Nulling last startingData", "level": "VERBOSE", @@ -2173,6 +2239,12 @@ "group": "WM_DEBUG_ADD_REMOVE", "at": "com\/android\/server\/wm\/WindowState.java" }, + "2119122320": { + "message": "setInputMethodTarget %s", + "level": "INFO", + "group": "WM_DEBUG_IME", + "at": "com\/android\/server\/wm\/DisplayContent.java" + }, "2128604122": { "message": "findFocusedWindow: No focusable windows.", "level": "VERBOSE", diff --git a/data/sounds/AudioTv.mk b/data/sounds/AudioTv.mk index 2a31e4c2d55a..fd53aff73a50 100644 --- a/data/sounds/AudioTv.mk +++ b/data/sounds/AudioTv.mk @@ -16,6 +16,7 @@ LOCAL_PATH := frameworks/base/data/sounds PRODUCT_COPY_FILES += \ $(LOCAL_PATH)/Alarm_Beep_01.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/alarms/Alarm_Beep_02.ogg \ + $(LOCAL_PATH)/effects/ogg/Effect_Tick_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/Effect_Tick.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressDelete_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressDelete.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressInvalid_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressInvalid.ogg \ $(LOCAL_PATH)/effects/ogg/KeypressReturn_120_48k.ogg:$(TARGET_COPY_OUT_PRODUCT)/media/audio/ui/KeypressReturn.ogg \ diff --git a/graphics/java/android/graphics/pdf/PdfDocument.java b/graphics/java/android/graphics/pdf/PdfDocument.java index 1b8336f54637..58421ab5ccd9 100644 --- a/graphics/java/android/graphics/pdf/PdfDocument.java +++ b/graphics/java/android/graphics/pdf/PdfDocument.java @@ -46,8 +46,8 @@ import java.util.List; * // create a new document * PdfDocument document = new PdfDocument(); * - * // crate a page description - * PageInfo pageInfo = new PageInfo.Builder(new Rect(0, 0, 100, 100), 1).create(); + * // create a page description + * PageInfo pageInfo = new PageInfo.Builder(100, 100, 1).create(); * * // start a page * Page page = document.startPage(pageInfo); diff --git a/libs/hwui/jni/android_graphics_Canvas.cpp b/libs/hwui/jni/android_graphics_Canvas.cpp index 4aff3e544efa..b6c6cd0b5c1c 100644 --- a/libs/hwui/jni/android_graphics_Canvas.cpp +++ b/libs/hwui/jni/android_graphics_Canvas.cpp @@ -113,7 +113,7 @@ static void restoreUnclippedLayer(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle, get_canvas(canvasHandle)->restoreUnclippedLayer(saveCount, *paint); } -static bool restore(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) { +static jboolean restore(CRITICAL_JNI_PARAMS_COMMA jlong canvasHandle) { Canvas* canvas = get_canvas(canvasHandle); if (canvas->getSaveCount() <= 1) { return false; // cannot restore anymore diff --git a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp index 8a262969614e..9cffceb308c8 100644 --- a/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp +++ b/libs/hwui/jni/android_graphics_drawable_VectorDrawable.cpp @@ -102,7 +102,7 @@ static void setAntiAlias(JNIEnv*, jobject, jlong treePtr, jboolean aa) { /** * Draw */ -static int draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr, +static jint draw(JNIEnv* env, jobject, jlong treePtr, jlong canvasPtr, jlong colorFilterPtr, jobject jrect, jboolean needsMirroring, jboolean canReuseCache) { VectorDrawable::Tree* tree = reinterpret_cast<VectorDrawable::Tree*>(treePtr); Canvas* canvas = reinterpret_cast<Canvas*>(canvasPtr); diff --git a/libs/hwui/jni/android_util_PathParser.cpp b/libs/hwui/jni/android_util_PathParser.cpp index df5e9cd44ed0..72995efb1c21 100644 --- a/libs/hwui/jni/android_util_PathParser.cpp +++ b/libs/hwui/jni/android_util_PathParser.cpp @@ -39,18 +39,18 @@ static void parseStringForPath(JNIEnv* env, jobject, jlong skPathHandle, jstring } } -static long createEmptyPathData(JNIEnv*, jobject) { +static jlong createEmptyPathData(JNIEnv*, jobject) { PathData* pathData = new PathData(); return reinterpret_cast<jlong>(pathData); } -static long createPathData(JNIEnv*, jobject, jlong pathDataPtr) { +static jlong createPathData(JNIEnv*, jobject, jlong pathDataPtr) { PathData* pathData = reinterpret_cast<PathData*>(pathDataPtr); PathData* newPathData = new PathData(*pathData); return reinterpret_cast<jlong>(newPathData); } -static long createPathDataFromStringPath(JNIEnv* env, jobject, jstring inputStr, jint strLength) { +static jlong createPathDataFromStringPath(JNIEnv* env, jobject, jstring inputStr, jint strLength) { const char* pathString = env->GetStringUTFChars(inputStr, NULL); PathData* pathData = new PathData(); PathParser::ParseResult result; @@ -65,7 +65,7 @@ static long createPathDataFromStringPath(JNIEnv* env, jobject, jstring inputStr, } } -static bool interpolatePathData(JNIEnv*, jobject, jlong outPathDataPtr, jlong fromPathDataPtr, +static jboolean interpolatePathData(JNIEnv*, jobject, jlong outPathDataPtr, jlong fromPathDataPtr, jlong toPathDataPtr, jfloat fraction) { PathData* outPathData = reinterpret_cast<PathData*>(outPathDataPtr); PathData* fromPathData = reinterpret_cast<PathData*>(fromPathDataPtr); @@ -79,7 +79,7 @@ static void deletePathData(JNIEnv*, jobject, jlong pathDataHandle) { delete pathData; } -static bool canMorphPathData(JNIEnv*, jobject, jlong fromPathDataPtr, jlong toPathDataPtr) { +static jboolean canMorphPathData(JNIEnv*, jobject, jlong fromPathDataPtr, jlong toPathDataPtr) { PathData* fromPathData = reinterpret_cast<PathData*>(fromPathDataPtr); PathData* toPathData = reinterpret_cast<PathData*>(toPathDataPtr); return VectorDrawableUtils::canMorph(*fromPathData, *toPathData); diff --git a/media/java/android/media/MediaCodec.java b/media/java/android/media/MediaCodec.java index d6496c0b3e02..62d76c0d2d58 100644 --- a/media/java/android/media/MediaCodec.java +++ b/media/java/android/media/MediaCodec.java @@ -2742,6 +2742,9 @@ final public class MediaCodec { * See {@link MediaCodec.CryptoInfo.Pattern}. */ public void setPattern(Pattern newPattern) { + if (newPattern == null) { + newPattern = zeroPattern; + } pattern = newPattern; } @@ -2767,6 +2770,11 @@ final public class MediaCodec { builder.append(Arrays.toString(numBytesOfClearData)); builder.append(", encrypted "); builder.append(Arrays.toString(numBytesOfEncryptedData)); + builder.append(", pattern (encrypt: "); + builder.append(pattern.mEncryptBlocks); + builder.append(", skip: "); + builder.append(pattern.mSkipBlocks); + builder.append(")"); return builder.toString(); } }; diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl index 508a46f492dd..1fbb67260895 100644 --- a/media/java/android/media/tv/ITvInputManager.aidl +++ b/media/java/android/media/tv/ITvInputManager.aidl @@ -111,4 +111,8 @@ interface ITvInputManager { // For preview channels and programs void sendTvInputNotifyIntent(in Intent intent, int userId); void requestChannelBrowsable(in Uri channelUri, int userId); + + // For CTS purpose only. Add/remove a TvInputHardware device + void addHardwareDevice(in int deviceId); + void removeHardwareDevice(in int deviceId); } diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java index e701055c2894..98a01a4cb449 100644 --- a/media/java/android/media/tv/TvInputManager.java +++ b/media/java/android/media/tv/TvInputManager.java @@ -23,6 +23,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; +import android.annotation.TestApi; import android.content.Context; import android.content.Intent; import android.graphics.Rect; @@ -1801,6 +1802,40 @@ public final class TvInputManager { executor, callback); } + /** + * API to add a hardware device in the TvInputHardwareManager for CTS testing + * purpose. + * + * @param deviceId Id of the adding hardware device. + * + * @hide + */ + @TestApi + public void addHardwareDevice(int deviceId) { + try { + mService.addHardwareDevice(deviceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + + /** + * API to remove a hardware device in the TvInputHardwareManager for CTS testing + * purpose. + * + * @param deviceId Id of the removing hardware device. + * + * @hide + */ + @TestApi + public void removeHardwareDevice(int deviceId) { + try { + mService.removeHardwareDevice(deviceId); + } catch (RemoteException e) { + throw e.rethrowFromSystemServer(); + } + } + private Hardware acquireTvInputHardwareInternal(int deviceId, TvInputInfo info, String tvInputSessionId, int priorityHint, Executor executor, final HardwareCallback callback) { diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index a458b16c551a..8bf688dba10b 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -447,7 +447,7 @@ public class Tuner implements AutoCloseable { private native DvrRecorder nativeOpenDvrRecorder(long bufferSize); private native DvrPlayback nativeOpenDvrPlayback(long bufferSize); - private static native DemuxCapabilities nativeGetDemuxCapabilities(); + private native DemuxCapabilities nativeGetDemuxCapabilities(); private native int nativeCloseDemux(int handle); private native int nativeCloseFrontend(int handle); @@ -939,8 +939,7 @@ public class Tuner implements AutoCloseable { Filter filter = nativeOpenFilter( mainType, TunerUtils.getFilterSubtype(mainType, subType), bufferSize); if (filter != null) { - filter.setMainType(mainType); - filter.setSubtype(subType); + filter.setType(mainType, subType); filter.setCallback(cb, executor); if (mHandler == null) { mHandler = createEventHandler(); @@ -1147,8 +1146,11 @@ public class Tuner implements AutoCloseable { } /* package */ void releaseLnb() { - mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); - mLnbHandle = null; + if (mLnbHandle != null) { + // LNB handle can be null if it's opened by name. + mTunerResourceManager.releaseLnb(mLnbHandle, mClientId); + mLnbHandle = null; + } mLnb = null; } } diff --git a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java index 9971c847dd54..68071b0b0fe3 100644 --- a/media/java/android/media/tv/tuner/dvr/DvrPlayback.java +++ b/media/java/android/media/tv/tuner/dvr/DvrPlayback.java @@ -105,28 +105,33 @@ public class DvrPlayback implements AutoCloseable { /** - * Attaches a filter to DVR interface for recording. + * Attaches a filter to DVR interface for playback. * - * <p>There can be multiple filters attached. Attached filters are independent, so the order - * doesn't matter. + * <p>This method will be deprecated. Now it's a no-op. + * <p>Filters opened by {@link Tuner#openFilter} are used for DVR playback. * * @param filter the filter to be attached. * @return result status of the operation. */ @Result public int attachFilter(@NonNull Filter filter) { - return nativeAttachFilter(filter); + // no-op + return Tuner.RESULT_UNAVAILABLE; } /** * Detaches a filter from DVR interface. * + * <p>This method will be deprecated. Now it's a no-op. + * <p>Filters opened by {@link Tuner#openFilter} are used for DVR playback. + * * @param filter the filter to be detached. * @return result status of the operation. */ @Result public int detachFilter(@NonNull Filter filter) { - return nativeDetachFilter(filter); + // no-op + return Tuner.RESULT_UNAVAILABLE; } /** diff --git a/media/java/android/media/tv/tuner/filter/Filter.java b/media/java/android/media/tv/tuner/filter/Filter.java index cc932da4a9f6..f0015b723edb 100644 --- a/media/java/android/media/tv/tuner/filter/Filter.java +++ b/media/java/android/media/tv/tuner/filter/Filter.java @@ -221,12 +221,9 @@ public class Filter implements AutoCloseable { } /** @hide */ - public void setMainType(@Type int mainType) { + public void setType(@Type int mainType, @Subtype int subtype) { mMainType = mainType; - } - /** @hide */ - public void setSubtype(@Subtype int subtype) { - mSubtype = subtype; + mSubtype = TunerUtils.getFilterSubtype(mainType, subtype); } /** @hide */ diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index fb8c276ecc8d..7e721406a300 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -2975,7 +2975,7 @@ static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyt jbyte *dst = env->GetByteArrayElements(buffer, &isCopy); ALOGD("copyData, isCopy=%d", isCopy); if (dst == nullptr) { - ALOGD("Failed to GetByteArrayElements"); + jniThrowRuntimeException(env, "Failed to GetByteArrayElements"); return 0; } @@ -2983,7 +2983,7 @@ static jint copyData(JNIEnv *env, std::unique_ptr<MQ>& mq, EventFlag* flag, jbyt env->ReleaseByteArrayElements(buffer, dst, 0); flag->wake(static_cast<uint32_t>(DemuxQueueNotifyBits::DATA_CONSUMED)); } else { - ALOGD("Failed to read FMQ"); + jniThrowRuntimeException(env, "Failed to read FMQ"); env->ReleaseByteArrayElements(buffer, dst, 0); return 0; } diff --git a/media/jni/soundpool/Android.bp b/media/jni/soundpool/Android.bp index aa3279321e90..6141308a8fdb 100644 --- a/media/jni/soundpool/Android.bp +++ b/media/jni/soundpool/Android.bp @@ -1,5 +1,92 @@ +tidy_errors = [ + // https://clang.llvm.org/extra/clang-tidy/checks/list.html + // For many categories, the checks are too many to specify individually. + // Feel free to disable as needed - as warnings are generally ignored, + // we treat warnings as errors. + "android-*", + "bugprone-*", + "cert-*", + "clang-analyzer-security*", + "google-*", + "misc-*", + //"modernize-*", // explicitly list the modernize as they can be subjective. + "modernize-avoid-bind", + //"modernize-avoid-c-arrays", // std::array<> can be verbose + "modernize-concat-nested-namespaces", + //"modernize-deprecated-headers", // C headers still ok even if there is C++ equivalent. + "modernize-deprecated-ios-base-aliases", + "modernize-loop-convert", + "modernize-make-shared", + "modernize-make-unique", + "modernize-pass-by-value", + "modernize-raw-string-literal", + "modernize-redundant-void-arg", + "modernize-replace-auto-ptr", + "modernize-replace-random-shuffle", + "modernize-return-braced-init-list", + "modernize-shrink-to-fit", + "modernize-unary-static-assert", + "modernize-use-auto", // debatable - auto can obscure type + "modernize-use-bool-literals", + "modernize-use-default-member-init", + "modernize-use-emplace", + "modernize-use-equals-default", + "modernize-use-equals-delete", + "modernize-use-nodiscard", + "modernize-use-noexcept", + "modernize-use-nullptr", + "modernize-use-override", + //"modernize-use-trailing-return-type", // not necessarily more readable + "modernize-use-transparent-functors", + "modernize-use-uncaught-exceptions", + "modernize-use-using", + "performance-*", + + // Remove some pedantic stylistic requirements. + "-google-readability-casting", // C++ casts not always necessary and may be verbose + "-google-readability-todo", // do not require TODO(info) + "-google-build-using-namespace", // Reenable and fix later. +] + +cc_defaults { + name: "soundpool_flags_defaults", + // https://clang.llvm.org/docs/UsersManual.html#command-line-options + // https://clang.llvm.org/docs/DiagnosticsReference.html + cflags: [ + "-Wall", + "-Wdeprecated", + "-Werror", + "-Werror=implicit-fallthrough", + "-Werror=sometimes-uninitialized", + //"-Werror=conditional-uninitialized", + "-Wextra", + "-Wredundant-decls", + "-Wshadow", + "-Wstrict-aliasing", + "-fstrict-aliasing", + "-Wthread-safety", + //"-Wthread-safety-negative", // experimental - looks broken in R. + "-Wunreachable-code", + "-Wunreachable-code-break", + "-Wunreachable-code-return", + "-Wunused", + "-Wused-but-marked-unused", + ], + // https://clang.llvm.org/extra/clang-tidy/ + tidy: true, + tidy_checks: tidy_errors, + tidy_checks_as_errors: tidy_errors, + tidy_flags: [ + "-format-style='file'", + "--header-filter='frameworks/base/media/jni/soundpool'", + ], +} + cc_library_shared { name: "libsoundpool", + defaults: [ + "soundpool_flags_defaults", + ], srcs: [ "android_media_SoundPool.cpp", diff --git a/media/jni/soundpool/Sound.cpp b/media/jni/soundpool/Sound.cpp index 0bbc3e46b044..c3abdc22b19d 100644 --- a/media/jni/soundpool/Sound.cpp +++ b/media/jni/soundpool/Sound.cpp @@ -31,7 +31,7 @@ constexpr size_t kDefaultHeapSize = 1024 * 1024; // 1MB (compatible with low m Sound::Sound(int32_t soundID, int fd, int64_t offset, int64_t length) : mSoundID(soundID) - , mFd(dup(fd)) + , mFd(fcntl(fd, F_DUPFD_CLOEXEC)) // like dup(fd) but closes on exec to prevent leaks. , mOffset(offset) , mLength(length) { @@ -47,7 +47,7 @@ Sound::~Sound() static status_t decode(int fd, int64_t offset, int64_t length, uint32_t *rate, int32_t *channelCount, audio_format_t *audioFormat, - audio_channel_mask_t *channelMask, sp<MemoryHeapBase> heap, + audio_channel_mask_t *channelMask, const sp<MemoryHeapBase>& heap, size_t *sizeInBytes) { ALOGV("%s(fd=%d, offset=%lld, length=%lld, ...)", __func__, fd, (long long)offset, (long long)length); @@ -81,7 +81,7 @@ static status_t decode(int fd, int64_t offset, int64_t length, bool sawInputEOS = false; bool sawOutputEOS = false; - uint8_t* writePos = static_cast<uint8_t*>(heap->getBase()); + auto writePos = static_cast<uint8_t*>(heap->getBase()); size_t available = heap->getSize(); size_t written = 0; format.reset(AMediaCodec_getOutputFormat(codec.get())); // update format. @@ -204,7 +204,7 @@ status_t Sound::doLoad() int32_t channelCount; audio_format_t format; audio_channel_mask_t channelMask; - status_t status = decode(mFd.get(), mOffset, mLength, &sampleRate, &channelCount, &format, + status = decode(mFd.get(), mOffset, mLength, &sampleRate, &channelCount, &format, &channelMask, mHeap, &mSizeInBytes); ALOGV("%s: close(%d)", __func__, mFd.get()); mFd.reset(); // close diff --git a/media/jni/soundpool/SoundDecoder.cpp b/media/jni/soundpool/SoundDecoder.cpp index 12200ef03aad..6614fdb5af53 100644 --- a/media/jni/soundpool/SoundDecoder.cpp +++ b/media/jni/soundpool/SoundDecoder.cpp @@ -57,7 +57,7 @@ void SoundDecoder::quit() mThreadPool->quit(); } -void SoundDecoder::run(int32_t id __unused /* ALOGV only */) +void SoundDecoder::run(int32_t id) { ALOGV("%s(%d): entering", __func__, id); std::unique_lock lock(mLock); diff --git a/media/jni/soundpool/SoundDecoder.h b/media/jni/soundpool/SoundDecoder.h index 1288943e86e3..7b62114483cf 100644 --- a/media/jni/soundpool/SoundDecoder.h +++ b/media/jni/soundpool/SoundDecoder.h @@ -30,21 +30,22 @@ class SoundDecoder { public: SoundDecoder(SoundManager* soundManager, size_t threads); ~SoundDecoder(); - void loadSound(int32_t soundID); + void loadSound(int32_t soundID) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock void quit(); private: - void run(int32_t id); // The decode thread function. + // The decode thread function. + void run(int32_t id) NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock SoundManager* const mSoundManager; // set in constructor, has own lock std::unique_ptr<ThreadPool> mThreadPool; // set in constructor, has own lock std::mutex mLock; - std::condition_variable mQueueSpaceAvailable; - std::condition_variable mQueueDataAvailable; + std::condition_variable mQueueSpaceAvailable GUARDED_BY(mLock); + std::condition_variable mQueueDataAvailable GUARDED_BY(mLock); - std::deque<int32_t> mSoundIDs; // GUARDED_BY(mLock); - bool mQuit = false; // GUARDED_BY(mLock); + std::deque<int32_t> mSoundIDs GUARDED_BY(mLock); + bool mQuit GUARDED_BY(mLock) = false; }; } // end namespace android::soundpool diff --git a/media/jni/soundpool/SoundManager.cpp b/media/jni/soundpool/SoundManager.cpp index 3c625bf3bb7f..5b16174eef2b 100644 --- a/media/jni/soundpool/SoundManager.cpp +++ b/media/jni/soundpool/SoundManager.cpp @@ -43,7 +43,7 @@ SoundManager::~SoundManager() mSounds.clear(); } -int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority __unused) +int32_t SoundManager::load(int fd, int64_t offset, int64_t length, int32_t priority) { ALOGV("%s(fd=%d, offset=%lld, length=%lld, priority=%d)", __func__, fd, (long long)offset, (long long)length, priority); diff --git a/media/jni/soundpool/SoundManager.h b/media/jni/soundpool/SoundManager.h index 9201e78132f4..4a4e3b87be26 100644 --- a/media/jni/soundpool/SoundManager.h +++ b/media/jni/soundpool/SoundManager.h @@ -21,6 +21,8 @@ #include <mutex> #include <unordered_map> +#include <android-base/thread_annotations.h> + namespace android { class SoundPool; @@ -91,20 +93,21 @@ private: } private: mutable std::recursive_mutex mCallbackLock; // allow mCallback to setCallback(). + // No thread-safety checks in R for recursive_mutex. SoundPool* mSoundPool = nullptr; // GUARDED_BY(mCallbackLock) SoundPoolCallback* mCallback = nullptr; // GUARDED_BY(mCallbackLock) void* mUserData = nullptr; // GUARDED_BY(mCallbackLock) }; - std::shared_ptr<Sound> findSound_l(int32_t soundID) const; + std::shared_ptr<Sound> findSound_l(int32_t soundID) const REQUIRES(mSoundManagerLock); // The following variables are initialized in constructor and can be accessed anytime. - CallbackHandler mCallbackHandler; // has its own lock - const std::unique_ptr<SoundDecoder> mDecoder; // has its own lock + CallbackHandler mCallbackHandler; // has its own lock + const std::unique_ptr<SoundDecoder> mDecoder; // has its own lock - mutable std::mutex mSoundManagerLock; - std::unordered_map<int, std::shared_ptr<Sound>> mSounds; // GUARDED_BY(mSoundManagerLock) - int32_t mNextSoundID = 0; // GUARDED_BY(mSoundManagerLock) + mutable std::mutex mSoundManagerLock; + std::unordered_map<int, std::shared_ptr<Sound>> mSounds GUARDED_BY(mSoundManagerLock); + int32_t mNextSoundID GUARDED_BY(mSoundManagerLock) = 0; }; } // namespace android::soundpool diff --git a/media/jni/soundpool/Stream.cpp b/media/jni/soundpool/Stream.cpp index e3152d6349aa..a6d975851619 100644 --- a/media/jni/soundpool/Stream.cpp +++ b/media/jni/soundpool/Stream.cpp @@ -105,7 +105,7 @@ void Stream::setRate(int32_t streamID, float rate) if (streamID == mStreamID) { mRate = rate; if (mAudioTrack != nullptr && mSound != nullptr) { - const uint32_t sampleRate = uint32_t(float(mSound->getSampleRate()) * rate + 0.5); + const auto sampleRate = (uint32_t)lround(double(mSound->getSampleRate()) * rate); mAudioTrack->setSampleRate(sampleRate); } } @@ -214,8 +214,11 @@ void Stream::stop_l() void Stream::clearAudioTrack() { + sp<AudioTrack> release; // release outside of lock. + std::lock_guard lock(mLock); // This will invoke the destructor which waits for the AudioTrack thread to join, // and is currently the only safe way to ensure there are no callbacks afterwards. + release = mAudioTrack; // or std::swap if we had move semantics. mAudioTrack.clear(); } @@ -288,7 +291,7 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, const audio_stream_type_t streamType = AudioSystem::attributesToStreamType(*mStreamManager->getAttributes()); const int32_t channelCount = sound->getChannelCount(); - const uint32_t sampleRate = uint32_t(float(sound->getSampleRate()) * rate + 0.5); + const auto sampleRate = (uint32_t)lround(double(sound->getSampleRate()) * rate); size_t frameCount = 0; if (loop) { @@ -307,7 +310,7 @@ void Stream::play_l(const std::shared_ptr<Sound>& sound, int32_t nextStreamID, __func__, mAudioTrack.get(), sound->getSoundID()); } } - if (newTrack == 0) { + if (newTrack == nullptr) { // mToggle toggles each time a track is started on a given stream. // The toggle is concatenated with the Stream address and passed to AudioTrack // as callback user data. This enables the detection of callbacks received from the old @@ -380,9 +383,9 @@ exit: /* static */ void Stream::staticCallback(int event, void* user, void* info) { - const uintptr_t userAsInt = (uintptr_t)user; - Stream* stream = reinterpret_cast<Stream*>(userAsInt & ~1); - stream->callback(event, info, userAsInt & 1, 0 /* tries */); + const auto userAsInt = (uintptr_t)user; + auto stream = reinterpret_cast<Stream*>(userAsInt & ~1); + stream->callback(event, info, int(userAsInt & 1), 0 /* tries */); } void Stream::callback(int event, void* info, int toggle, int tries) diff --git a/media/jni/soundpool/Stream.h b/media/jni/soundpool/Stream.h index 82d2690e2965..fd929210eb46 100644 --- a/media/jni/soundpool/Stream.h +++ b/media/jni/soundpool/Stream.h @@ -18,6 +18,7 @@ #include "Sound.h" +#include <android-base/thread_annotations.h> #include <audio_utils/clock.h> #include <media/AudioTrack.h> @@ -104,47 +105,55 @@ public: // The following getters are not locked and have weak consistency. // These are considered advisory only - being stale is of nuisance. - int32_t getPriority() const { return mPriority; } - int32_t getPairPriority() const { return getPairStream()->getPriority(); } - int64_t getStopTimeNs() const { return mStopTimeNs; } + int32_t getPriority() const NO_THREAD_SAFETY_ANALYSIS { return mPriority; } + int32_t getPairPriority() const NO_THREAD_SAFETY_ANALYSIS { + return getPairStream()->getPriority(); + } + int64_t getStopTimeNs() const NO_THREAD_SAFETY_ANALYSIS { return mStopTimeNs; } + + // Can change with setPlay() + int32_t getStreamID() const NO_THREAD_SAFETY_ANALYSIS { return mStreamID; } + + // Can change with play_l() + int32_t getSoundID() const NO_THREAD_SAFETY_ANALYSIS { return mSoundID; } - int32_t getStreamID() const { return mStreamID; } // Can change with setPlay() - int32_t getSoundID() const { return mSoundID; } // Can change with play_l() - bool hasSound() const { return mSound.get() != nullptr; } + bool hasSound() const NO_THREAD_SAFETY_ANALYSIS { return mSound.get() != nullptr; } - Stream* getPairStream() const; // this never changes. See top of header. + // This never changes. See top of header. + Stream* getPairStream() const; private: void play_l(const std::shared_ptr<Sound>& sound, int streamID, float leftVolume, float rightVolume, int priority, int loop, float rate, - sp<AudioTrack> releaseTracks[2]); - void stop_l(); - void setVolume_l(float leftVolume, float rightVolume); + sp<AudioTrack> releaseTracks[2]) REQUIRES(mLock); + void stop_l() REQUIRES(mLock); + void setVolume_l(float leftVolume, float rightVolume) REQUIRES(mLock); // For use with AudioTrack callback. static void staticCallback(int event, void* user, void* info); - void callback(int event, void* info, int toggle, int tries); + void callback(int event, void* info, int toggle, int tries) + NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock // StreamManager should be set on construction and not changed. // release mLock before calling into StreamManager StreamManager* mStreamManager = nullptr; mutable std::mutex mLock; - std::atomic_int32_t mStreamID = 0; // Note: valid streamIDs are always positive. - int mState = IDLE; - std::shared_ptr<Sound> mSound; // Non-null if playing. - int32_t mSoundID = 0; // The sound ID associated with the AudioTrack. - float mLeftVolume = 0.f; - float mRightVolume = 0.f; - int32_t mPriority = INT32_MIN; - int32_t mLoop = 0; - float mRate = 0.f; - bool mAutoPaused = false; - bool mMuted = false; - - sp<AudioTrack> mAudioTrack; - int mToggle = 0; - int64_t mStopTimeNs = 0; // if nonzero, time to wait for stop. + std::atomic_int32_t mStreamID GUARDED_BY(mLock) = 0; // Valid streamIDs are always positive. + int mState GUARDED_BY(mLock) = IDLE; + std::shared_ptr<Sound> mSound GUARDED_BY(mLock); // Non-null if playing. + int32_t mSoundID GUARDED_BY(mLock) = 0; // SoundID associated with AudioTrack. + float mLeftVolume GUARDED_BY(mLock) = 0.f; + float mRightVolume GUARDED_BY(mLock) = 0.f; + int32_t mPriority GUARDED_BY(mLock) = INT32_MIN; + int32_t mLoop GUARDED_BY(mLock) = 0; + float mRate GUARDED_BY(mLock) = 0.f; + bool mAutoPaused GUARDED_BY(mLock) = false; + bool mMuted GUARDED_BY(mLock) = false; + + sp<AudioTrack> mAudioTrack GUARDED_BY(mLock); + int mToggle GUARDED_BY(mLock) = 0; + int64_t mStopTimeNs GUARDED_BY(mLock) = 0; // if nonzero, time to wait for stop. }; } // namespace android::soundpool diff --git a/media/jni/soundpool/StreamManager.cpp b/media/jni/soundpool/StreamManager.cpp index c61221892c28..9ff4254284dc 100644 --- a/media/jni/soundpool/StreamManager.cpp +++ b/media/jni/soundpool/StreamManager.cpp @@ -55,7 +55,7 @@ StreamMap::StreamMap(int32_t streams) { streams = 1; } mStreamPoolSize = streams * 2; - mStreamPool.reset(new Stream[mStreamPoolSize]); + mStreamPool = std::make_unique<Stream[]>(mStreamPoolSize); // create array of streams. // we use a perfect hash table with 2x size to map StreamIDs to Stream pointers. mPerfectHash = std::make_unique<PerfectHash<int32_t, Stream *>>(roundup(mStreamPoolSize * 2)); } @@ -69,7 +69,7 @@ Stream* StreamMap::findStream(int32_t streamID) const size_t StreamMap::streamPosition(const Stream* stream) const { ptrdiff_t index = stream - mStreamPool.get(); - LOG_ALWAYS_FATAL_IF(index < 0 || index >= mStreamPoolSize, + LOG_ALWAYS_FATAL_IF(index < 0 || (size_t)index >= mStreamPoolSize, "%s: stream position out of range: %td", __func__, index); return (size_t)index; } @@ -92,6 +92,11 @@ int32_t StreamMap::getNextIdForStream(Stream* stream) const { //////////// +// Thread safety analysis is supposed to be disabled for constructors and destructors +// but clang in R seems to have a bug. We use pragma to disable. +#pragma clang diagnostic push +#pragma clang diagnostic ignored "-Wthread-safety-analysis" + StreamManager::StreamManager( int32_t streams, size_t threads, const audio_attributes_t* attributes) : StreamMap(streams) @@ -110,6 +115,8 @@ StreamManager::StreamManager( "SoundPool_"); } +#pragma clang diagnostic pop + StreamManager::~StreamManager() { ALOGV("%s", __func__); diff --git a/media/jni/soundpool/StreamManager.h b/media/jni/soundpool/StreamManager.h index 30ad220db05b..59ae2f9d108b 100644 --- a/media/jni/soundpool/StreamManager.h +++ b/media/jni/soundpool/StreamManager.h @@ -183,9 +183,9 @@ private: std::atomic_size_t mActiveThreadCount = 0; std::mutex mThreadLock; - bool mQuit = false; // GUARDED_BY(mThreadLock) - int32_t mNextThreadId = 0; // GUARDED_BY(mThreadLock) - std::list<std::unique_ptr<JavaThread>> mThreads; // GUARDED_BY(mThreadLock) + bool mQuit GUARDED_BY(mThreadLock) = false; + int32_t mNextThreadId GUARDED_BY(mThreadLock) = 0; + std::list<std::unique_ptr<JavaThread>> mThreads GUARDED_BY(mThreadLock); }; /** @@ -263,7 +263,7 @@ private: mutable std::mutex mHashLock; const size_t mHashCapacity; // size of mK2V no lock needed. std::unique_ptr<std::atomic<V>[]> mK2V; // no lock needed for read access. - K mNextKey{}; // GUARDED_BY(mHashLock) + K mNextKey GUARDED_BY(mHashLock) {}; }; /** @@ -392,7 +392,8 @@ public: // Returns positive streamID on success, 0 on failure. This is locked. int32_t queueForPlay(const std::shared_ptr<Sound> &sound, int32_t soundID, float leftVolume, float rightVolume, - int32_t priority, int32_t loop, float rate); + int32_t priority, int32_t loop, float rate) + NO_THREAD_SAFETY_ANALYSIS; // uses unique_lock /////////////////////////////////////////////////////////////////////// // Called from soundpool::Stream @@ -407,11 +408,11 @@ public: private: - void run(int32_t id); // worker thread, takes lock internally. + void run(int32_t id) NO_THREAD_SAFETY_ANALYSIS; // worker thread, takes unique_lock. void dump() const; // no lock needed // returns true if more worker threads are needed. - bool needMoreThreads_l() { + bool needMoreThreads_l() REQUIRES(mStreamManagerLock) { return mRestartStreams.size() > 0 && (mThreadPool->getActiveThreadCount() == 0 || std::distance(mRestartStreams.begin(), @@ -420,14 +421,16 @@ private: } // returns true if the stream was added. - bool moveToRestartQueue_l(Stream* stream, int32_t activeStreamIDToMatch = 0); + bool moveToRestartQueue_l( + Stream* stream, int32_t activeStreamIDToMatch = 0) REQUIRES(mStreamManagerLock); // returns number of queues the stream was removed from (should be 0 or 1); // a special code of -1 is returned if activeStreamIDToMatch is > 0 and // the stream wasn't found on the active queue. - ssize_t removeFromQueues_l(Stream* stream, int32_t activeStreamIDToMatch = 0); - void addToRestartQueue_l(Stream *stream); - void addToActiveQueue_l(Stream *stream); - void sanityCheckQueue_l() const; + ssize_t removeFromQueues_l( + Stream* stream, int32_t activeStreamIDToMatch = 0) REQUIRES(mStreamManagerLock); + void addToRestartQueue_l(Stream *stream) REQUIRES(mStreamManagerLock); + void addToActiveQueue_l(Stream *stream) REQUIRES(mStreamManagerLock); + void sanityCheckQueue_l() const REQUIRES(mStreamManagerLock); const audio_attributes_t mAttributes; std::unique_ptr<ThreadPool> mThreadPool; // locked internally @@ -436,9 +439,9 @@ private: // 4 stream queues by the Manager Thread or by the user initiated play(). // A stream pair has exactly one stream on exactly one of the queues. std::mutex mStreamManagerLock; - std::condition_variable mStreamManagerCondition; + std::condition_variable mStreamManagerCondition GUARDED_BY(mStreamManagerLock); - bool mQuit = false; // GUARDED_BY(mStreamManagerLock) + bool mQuit GUARDED_BY(mStreamManagerLock) = false; // There are constructor arg "streams" pairs of streams, only one of each // pair on the 4 stream queues below. The other stream in the pair serves as @@ -452,24 +455,24 @@ private: // The paired stream may be active (but with no AudioTrack), and will be restarted // with an active AudioTrack when the current stream is stopped. std::multimap<int64_t /* stopTimeNs */, Stream*> - mRestartStreams; // GUARDED_BY(mStreamManagerLock) + mRestartStreams GUARDED_BY(mStreamManagerLock); // 2) mActiveStreams: Streams that are active. // The paired stream will be inactive. // This is in order of specified by kStealActiveStream_OldestFirst - std::list<Stream*> mActiveStreams; // GUARDED_BY(mStreamManagerLock) + std::list<Stream*> mActiveStreams GUARDED_BY(mStreamManagerLock); // 3) mAvailableStreams: Streams that are inactive. // The paired stream will also be inactive. // No particular order. - std::unordered_set<Stream*> mAvailableStreams; // GUARDED_BY(mStreamManagerLock) + std::unordered_set<Stream*> mAvailableStreams GUARDED_BY(mStreamManagerLock); // 4) mProcessingStreams: Streams that are being processed by the ManagerThreads // When on this queue, the stream and its pair are not available for stealing. // Each ManagerThread will have at most one stream on the mProcessingStreams queue. // The paired stream may be active or restarting. // No particular order. - std::unordered_set<Stream*> mProcessingStreams; // GUARDED_BY(mStreamManagerLock) + std::unordered_set<Stream*> mProcessingStreams GUARDED_BY(mStreamManagerLock); }; } // namespace android::soundpool diff --git a/media/jni/soundpool/android_media_SoundPool.cpp b/media/jni/soundpool/android_media_SoundPool.cpp index f6706369f379..8f6df3db718b 100644 --- a/media/jni/soundpool/android_media_SoundPool.cpp +++ b/media/jni/soundpool/android_media_SoundPool.cpp @@ -52,7 +52,7 @@ android_media_SoundPool_load_FD(JNIEnv *env, jobject thiz, jobject fileDescripto { ALOGV("android_media_SoundPool_load_FD"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; + if (ap == nullptr) return 0; return (jint) ap->load(jniGetFDFromFileDescriptor(env, fileDescriptor), int64_t(offset), int64_t(length), int(priority)); } @@ -61,7 +61,7 @@ static jboolean android_media_SoundPool_unload(JNIEnv *env, jobject thiz, jint sampleID) { ALOGV("android_media_SoundPool_unload\n"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return JNI_FALSE; + if (ap == nullptr) return JNI_FALSE; return ap->unload(sampleID) ? JNI_TRUE : JNI_FALSE; } @@ -72,7 +72,7 @@ android_media_SoundPool_play(JNIEnv *env, jobject thiz, jint sampleID, { ALOGV("android_media_SoundPool_play\n"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return 0; + if (ap == nullptr) return 0; return (jint) ap->play(sampleID, leftVolume, rightVolume, priority, loop, rate); } @@ -81,7 +81,7 @@ android_media_SoundPool_pause(JNIEnv *env, jobject thiz, jint channelID) { ALOGV("android_media_SoundPool_pause"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->pause(channelID); } @@ -90,7 +90,7 @@ android_media_SoundPool_resume(JNIEnv *env, jobject thiz, jint channelID) { ALOGV("android_media_SoundPool_resume"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->resume(channelID); } @@ -99,7 +99,7 @@ android_media_SoundPool_autoPause(JNIEnv *env, jobject thiz) { ALOGV("android_media_SoundPool_autoPause"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->autoPause(); } @@ -108,7 +108,7 @@ android_media_SoundPool_autoResume(JNIEnv *env, jobject thiz) { ALOGV("android_media_SoundPool_autoResume"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->autoResume(); } @@ -117,7 +117,7 @@ android_media_SoundPool_stop(JNIEnv *env, jobject thiz, jint channelID) { ALOGV("android_media_SoundPool_stop"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->stop(channelID); } @@ -127,7 +127,7 @@ android_media_SoundPool_setVolume(JNIEnv *env, jobject thiz, jint channelID, { ALOGV("android_media_SoundPool_setVolume"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->setVolume(channelID, (float) leftVolume, (float) rightVolume); } @@ -136,7 +136,7 @@ android_media_SoundPool_mute(JNIEnv *env, jobject thiz, jboolean muting) { ALOGV("android_media_SoundPool_mute(%d)", muting); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->mute(muting == JNI_TRUE); } @@ -146,7 +146,7 @@ android_media_SoundPool_setPriority(JNIEnv *env, jobject thiz, jint channelID, { ALOGV("android_media_SoundPool_setPriority"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->setPriority(channelID, (int) priority); } @@ -156,7 +156,7 @@ android_media_SoundPool_setLoop(JNIEnv *env, jobject thiz, jint channelID, { ALOGV("android_media_SoundPool_setLoop"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->setLoop(channelID, loop); } @@ -166,7 +166,7 @@ android_media_SoundPool_setRate(JNIEnv *env, jobject thiz, jint channelID, { ALOGV("android_media_SoundPool_setRate"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap == NULL) return; + if (ap == nullptr) return; ap->setRate(channelID, (float) rate); } @@ -174,24 +174,26 @@ static void android_media_callback(SoundPoolEvent event, SoundPool* soundPool, v { ALOGV("callback: (%d, %d, %d, %p, %p)", event.mMsg, event.mArg1, event.mArg2, soundPool, user); JNIEnv *env = AndroidRuntime::getJNIEnv(); - env->CallStaticVoidMethod(fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, NULL); + env->CallStaticVoidMethod( + fields.mSoundPoolClass, fields.mPostEvent, user, event.mMsg, event.mArg1, event.mArg2, + nullptr /* object */); } static jint android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, jint maxChannels, jobject jaa) { - if (jaa == 0) { + if (jaa == nullptr) { ALOGE("Error creating SoundPool: invalid audio attributes"); return -1; } - audio_attributes_t *paa = NULL; + audio_attributes_t *paa = nullptr; // read the AudioAttributes values paa = (audio_attributes_t *) calloc(1, sizeof(audio_attributes_t)); - const jstring jtags = + const auto jtags = (jstring) env->GetObjectField(jaa, javaAudioAttrFields.fieldFormattedTags); - const char* tags = env->GetStringUTFChars(jtags, NULL); + const char* tags = env->GetStringUTFChars(jtags, nullptr); // copying array size -1, char array for tags was calloc'd, no need to NULL-terminate it strncpy(paa->tags, tags, AUDIO_ATTRIBUTES_TAGS_MAX_SIZE - 1); env->ReleaseStringUTFChars(jtags, tags); @@ -201,8 +203,8 @@ android_media_SoundPool_native_setup(JNIEnv *env, jobject thiz, jobject weakRef, paa->flags = env->GetIntField(jaa, javaAudioAttrFields.fieldFlags); ALOGV("android_media_SoundPool_native_setup"); - SoundPool *ap = new SoundPool(maxChannels, paa); - if (ap == NULL) { + auto *ap = new SoundPool(maxChannels, paa); + if (ap == nullptr) { return -1; } @@ -224,12 +226,12 @@ android_media_SoundPool_release(JNIEnv *env, jobject thiz) { ALOGV("android_media_SoundPool_release"); SoundPool *ap = MusterSoundPool(env, thiz); - if (ap != NULL) { + if (ap != nullptr) { // release weak reference and clear callback - jobject weakRef = (jobject) ap->getUserData(); - ap->setCallback(NULL, NULL); - if (weakRef != NULL) { + auto weakRef = (jobject) ap->getUserData(); + ap->setCallback(nullptr /* callback */, nullptr /* user */); + if (weakRef != nullptr) { env->DeleteGlobalRef(weakRef); } @@ -309,7 +311,7 @@ static const char* const kClassPathName = "android/media/SoundPool"; jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) { - JNIEnv* env = NULL; + JNIEnv* env = nullptr; jint result = -1; jclass clazz; @@ -317,23 +319,23 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) ALOGE("ERROR: GetEnv failed\n"); return result; } - assert(env != NULL); + assert(env != nullptr); clazz = env->FindClass(kClassPathName); - if (clazz == NULL) { + if (clazz == nullptr) { ALOGE("Can't find %s", kClassPathName); return result; } fields.mNativeContext = env->GetFieldID(clazz, "mNativeContext", "J"); - if (fields.mNativeContext == NULL) { + if (fields.mNativeContext == nullptr) { ALOGE("Can't find SoundPool.mNativeContext"); return result; } fields.mPostEvent = env->GetStaticMethodID(clazz, "postEventFromNative", "(Ljava/lang/Object;IIILjava/lang/Object;)V"); - if (fields.mPostEvent == NULL) { + if (fields.mPostEvent == nullptr) { ALOGE("Can't find android/media/SoundPool.postEventFromNative"); return result; } @@ -342,16 +344,18 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) // since it's a static object. fields.mSoundPoolClass = (jclass) env->NewGlobalRef(clazz); - if (AndroidRuntime::registerNativeMethods(env, kClassPathName, gMethods, NELEM(gMethods)) < 0) + if (AndroidRuntime::registerNativeMethods( + env, kClassPathName, gMethods, NELEM(gMethods)) < 0) { return result; + } // Get the AudioAttributes class and fields jclass audioAttrClass = env->FindClass(kAudioAttributesClassPathName); - if (audioAttrClass == NULL) { + if (audioAttrClass == nullptr) { ALOGE("Can't find %s", kAudioAttributesClassPathName); return result; } - jclass audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); + auto audioAttributesClassRef = (jclass)env->NewGlobalRef(audioAttrClass); javaAudioAttrFields.fieldUsage = env->GetFieldID(audioAttributesClassRef, "mUsage", "I"); javaAudioAttrFields.fieldContentType = env->GetFieldID(audioAttributesClassRef, "mContentType", "I"); @@ -359,9 +363,10 @@ jint JNI_OnLoad(JavaVM* vm, void* /* reserved */) javaAudioAttrFields.fieldFormattedTags = env->GetFieldID(audioAttributesClassRef, "mFormattedTags", "Ljava/lang/String;"); env->DeleteGlobalRef(audioAttributesClassRef); - if (javaAudioAttrFields.fieldUsage == NULL || javaAudioAttrFields.fieldContentType == NULL - || javaAudioAttrFields.fieldFlags == NULL - || javaAudioAttrFields.fieldFormattedTags == NULL) { + if (javaAudioAttrFields.fieldUsage == nullptr + || javaAudioAttrFields.fieldContentType == nullptr + || javaAudioAttrFields.fieldFlags == nullptr + || javaAudioAttrFields.fieldFormattedTags == nullptr) { ALOGE("Can't initialize AudioAttributes fields"); return result; } diff --git a/packages/CarSystemUI/AndroidManifest.xml b/packages/CarSystemUI/AndroidManifest.xml index 1dd02919a093..c0482e1b3e04 100644 --- a/packages/CarSystemUI/AndroidManifest.xml +++ b/packages/CarSystemUI/AndroidManifest.xml @@ -25,6 +25,11 @@ <uses-permission android:name="android.car.permission.CAR_ENROLL_TRUST"/> <!-- This permission is required to get bluetooth broadcast. --> <uses-permission android:name="android.permission.BLUETOOTH" /> + <!-- These permissions are required to implement icons based on role holders. --> + <uses-permission android:name="android.permission.OBSERVE_ROLE_HOLDERS"/> + <uses-permission android:name="android.permission.MANAGE_ROLE_HOLDERS"/> + <!-- This permission is required to access app information from other users. --> + <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS"/> <!-- This permission is required to check the foreground user id. --> <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" /> </manifest> diff --git a/packages/CarSystemUI/res/layout/car_navigation_bar.xml b/packages/CarSystemUI/res/layout/car_navigation_bar.xml index 1418bf8604bf..2a715d0c3494 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_bar.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_bar.xml @@ -125,6 +125,7 @@ android:id="@+id/assist" style="@style/NavigationBarButton" systemui:icon="@drawable/ic_mic_white" + systemui:useDefaultAppIconForRole="true" /> </LinearLayout> diff --git a/packages/CarSystemUI/res/layout/car_navigation_button.xml b/packages/CarSystemUI/res/layout/car_navigation_button.xml index 837252b6d716..ca4e76ee104b 100644 --- a/packages/CarSystemUI/res/layout/car_navigation_button.xml +++ b/packages/CarSystemUI/res/layout/car_navigation_button.xml @@ -29,12 +29,14 @@ <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/car_nav_button_icon_image" - android:layout_height="wrap_content" + android:layout_height="@dimen/car_navigation_button_icon_height" android:layout_width="match_parent" android:layout_gravity="center" android:animateLayoutChanges="true" android:background="@android:color/transparent" android:scaleType="fitCenter" + android:tintMode="src_in" + android:tint="@color/car_nav_icon_fill_color" android:clickable="false" /> @@ -48,6 +50,7 @@ android:background="@android:color/transparent" android:scaleType="fitCenter" android:clickable="false" + android:visibility="gone" /> <ImageView diff --git a/packages/CarSystemUI/res/values/attrs.xml b/packages/CarSystemUI/res/values/attrs.xml index a5867638b183..788376494032 100644 --- a/packages/CarSystemUI/res/values/attrs.xml +++ b/packages/CarSystemUI/res/values/attrs.xml @@ -65,6 +65,10 @@ <attr name="showMoreWhenSelected" format="boolean" /> <!-- whether to highlight the button when selected. Defaults false --> <attr name="highlightWhenSelected" format="boolean" /> + <!-- whether to show the icon of the app currently associated this button's role. Only + relevant for buttons associated to specific roles (e.g.: AssistantButton). + Defaults false --> + <attr name="useDefaultAppIconForRole" format="boolean"/> </declare-styleable> <!-- Custom attributes to configure hvac values --> diff --git a/packages/CarSystemUI/res/values/colors.xml b/packages/CarSystemUI/res/values/colors.xml index 0e84d517759a..d20ab49a22e6 100644 --- a/packages/CarSystemUI/res/values/colors.xml +++ b/packages/CarSystemUI/res/values/colors.xml @@ -21,7 +21,7 @@ <color name="car_user_switcher_name_text_color">@*android:color/car_body1_light</color> <color name="car_user_switcher_add_user_background_color">#131313</color> <color name="car_user_switcher_add_user_add_sign_color">@*android:color/car_body1_light</color> - <color name="car_nav_icon_fill_color">#8Fffffff</color> + <color name="car_nav_icon_fill_color">#8F8F8F</color> <color name="car_nav_icon_fill_color_selected">#ffffff</color> <!-- colors for seekbar --> <color name="car_seekbar_track_background">#131315</color> diff --git a/packages/CarSystemUI/res/values/dimens.xml b/packages/CarSystemUI/res/values/dimens.xml index ed0b4853994d..cb321cdc6c4d 100644 --- a/packages/CarSystemUI/res/values/dimens.xml +++ b/packages/CarSystemUI/res/values/dimens.xml @@ -175,6 +175,7 @@ <dimen name="car_user_switcher_margin_top">@*android:dimen/car_padding_4</dimen> <dimen name="car_navigation_button_width">64dp</dimen> + <dimen name="car_navigation_button_icon_height">44dp</dimen> <dimen name="car_navigation_bar_width">760dp</dimen> <dimen name="car_left_navigation_bar_width">96dp</dimen> <dimen name="car_right_navigation_bar_width">96dp</dimen> diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java index 69ec78eab593..ede4696a96c3 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/AssitantButton.java @@ -18,6 +18,7 @@ package com.android.systemui.car.navigationbar; import static android.service.voice.VoiceInteractionSession.SHOW_SOURCE_ASSIST_GESTURE; +import android.app.role.RoleManager; import android.content.Context; import android.content.res.TypedArray; import android.os.Bundle; @@ -31,7 +32,6 @@ import com.android.internal.app.IVoiceInteractionSessionShowCallback; * AssitantButton is a ui component that will trigger the Voice Interaction Service. */ public class AssitantButton extends CarNavigationButton { - private static final String TAG = "AssistantButton"; private final AssistUtils mAssistUtils; private IVoiceInteractionSessionShowCallback mShowCallback = @@ -50,9 +50,7 @@ public class AssitantButton extends CarNavigationButton { public AssitantButton(Context context, AttributeSet attrs) { super(context, attrs); mAssistUtils = new AssistUtils(context); - setOnClickListener(v -> { - showAssistant(); - }); + setOnClickListener(v -> showAssistant()); } private void showAssistant() { @@ -65,4 +63,9 @@ public class AssitantButton extends CarNavigationButton { protected void setUpIntents(TypedArray typedArray) { // left blank because for the assistant button Intent will not be passed from the layout. } + + @Override + protected String getRoleName() { + return RoleManager.ROLE_ASSISTANT; + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java new file mode 100644 index 000000000000..5c83c025bc20 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/ButtonRoleHolderController.java @@ -0,0 +1,142 @@ +/* + * 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.car.navigationbar; + +import android.annotation.Nullable; +import android.app.role.OnRoleHoldersChangedListener; +import android.app.role.RoleManager; +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.systemui.car.CarDeviceProvisionedController; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Some CarNavigationButtons can be associated to a {@link RoleManager} role. When they are, it is + * possible to have them display the icon of the default application (role holder) for the given + * role. + * + * This class monitors the current role holders for each role type and updates the button icon for + * this buttons with have this feature enabled. + */ +@Singleton +public class ButtonRoleHolderController { + private static final String TAG = "ButtonRoleHolderController"; + + private final Context mContext; + private final PackageManager mPackageManager; + private final RoleManager mRoleManager; + private final CarDeviceProvisionedController mDeviceController; + private final Map<String, CarNavigationButton> mButtonMap = new HashMap<>(); + private final OnRoleHoldersChangedListener mListener = this::onRoleChanged; + private boolean mRegistered; + + @Inject + public ButtonRoleHolderController(Context context, PackageManager packageManager, + RoleManager roleManager, CarDeviceProvisionedController deviceController) { + mContext = context; + mPackageManager = packageManager; + mRoleManager = roleManager; + mDeviceController = deviceController; + } + + /** + * Iterate through a view looking for CarNavigationButton and add it to this controller if it + * opted to be associated with a {@link RoleManager} role type. + * + * @param v the View that may contain CarFacetButtons + */ + void addAllButtonsWithRoleName(View v) { + if (v instanceof CarNavigationButton) { + CarNavigationButton button = (CarNavigationButton) v; + String roleName = button.getRoleName(); + if (roleName != null && button.isDefaultAppIconForRoleEnabled()) { + addButtonWithRoleName(button, roleName); + } + } else if (v instanceof ViewGroup) { + ViewGroup viewGroup = (ViewGroup) v; + for (int i = 0; i < viewGroup.getChildCount(); i++) { + addAllButtonsWithRoleName(viewGroup.getChildAt(i)); + } + } + } + + private void addButtonWithRoleName(CarNavigationButton button, String roleName) { + mButtonMap.put(roleName, button); + updateIcon(roleName); + if (!mRegistered) { + mRoleManager.addOnRoleHoldersChangedListenerAsUser(mContext.getMainExecutor(), + mListener, UserHandle.ALL); + mRegistered = true; + } + } + + void removeAll() { + mButtonMap.clear(); + if (mRegistered) { + mRoleManager.removeOnRoleHoldersChangedListenerAsUser(mListener, UserHandle.ALL); + mRegistered = false; + } + } + + @VisibleForTesting + void onRoleChanged(String roleName, UserHandle user) { + if (RoleManager.ROLE_ASSISTANT.equals(roleName) + && user.getIdentifier() == mDeviceController.getCurrentUser()) { + updateIcon(roleName); + } + } + + private void updateIcon(String roleName) { + CarNavigationButton button = mButtonMap.get(roleName); + if (button == null) { + return; + } + List<String> holders = mRoleManager.getRoleHoldersAsUser(button.getRoleName(), + UserHandle.of(mDeviceController.getCurrentUser())); + if (holders == null || holders.isEmpty()) { + button.setAppIcon(null); + } else { + button.setAppIcon(loadIcon(holders.get(0))); + } + } + + @Nullable + private Drawable loadIcon(String packageName) { + try { + ApplicationInfo appInfo = mPackageManager.getApplicationInfo(packageName, + PackageManager.MATCH_ANY_USER); + return appInfo.loadIcon(mPackageManager); + } catch (PackageManager.NameNotFoundException e) { + Log.e(ButtonRoleHolderController.TAG, "Package not found: " + packageName, e); + return null; + } + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java index 5c6472ecb4ef..4c720abb4c74 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBar.java @@ -87,7 +87,6 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks private final Executor mUiBgExecutor; private final IStatusBarService mBarService; private final Lazy<KeyguardStateController> mKeyguardStateControllerLazy; - private final ButtonSelectionStateController mButtonSelectionStateController; private final Lazy<PhoneStatusBarPolicy> mIconPolicyLazy; private final Lazy<StatusBarIconController> mIconControllerLazy; @@ -139,7 +138,6 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks @UiBackground Executor uiBgExecutor, IStatusBarService barService, Lazy<KeyguardStateController> keyguardStateControllerLazy, - ButtonSelectionStateController buttonSelectionStateController, Lazy<PhoneStatusBarPolicy> iconPolicyLazy, Lazy<StatusBarIconController> iconControllerLazy ) { @@ -156,7 +154,6 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks mUiBgExecutor = uiBgExecutor; mBarService = barService; mKeyguardStateControllerLazy = keyguardStateControllerLazy; - mButtonSelectionStateController = buttonSelectionStateController; mIconPolicyLazy = iconPolicyLazy; mIconControllerLazy = iconControllerLazy; @@ -280,10 +277,9 @@ public class CarNavigationBar extends SystemUI implements CommandQueue.Callbacks * before and after the device is provisioned. . Also for change of density and font size. */ private void restartNavBars() { - // remove and reattach all hvac components such that we don't keep a reference to unused - // ui elements - mCarNavigationBarController.removeAllFromHvac(); - mButtonSelectionStateController.removeAll(); + // remove and reattach all components such that we don't keep a reference to unused ui + // elements + mCarNavigationBarController.removeAll(); if (mTopNavigationBarWindow != null) { mTopNavigationBarWindow.removeAllViews(); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java index 288e5cf13c2e..ca780ae645c9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java @@ -37,6 +37,7 @@ public class CarNavigationBarController { private final Context mContext; private final NavigationBarViewFactory mNavigationBarViewFactory; private final ButtonSelectionStateController mButtonSelectionStateController; + private final ButtonRoleHolderController mButtonRoleHolderController; private final Lazy<HvacController> mHvacControllerLazy; private boolean mShowTop; @@ -59,11 +60,13 @@ public class CarNavigationBarController { public CarNavigationBarController(Context context, NavigationBarViewFactory navigationBarViewFactory, ButtonSelectionStateController buttonSelectionStateController, - Lazy<HvacController> hvacControllerLazy) { + Lazy<HvacController> hvacControllerLazy, + ButtonRoleHolderController buttonRoleHolderController) { mContext = context; mNavigationBarViewFactory = navigationBarViewFactory; mButtonSelectionStateController = buttonSelectionStateController; mHvacControllerLazy = hvacControllerLazy; + mButtonRoleHolderController = buttonRoleHolderController; // Read configuration. mShowTop = mContext.getResources().getBoolean(R.bool.config_enableTopNavigationBar); @@ -101,9 +104,11 @@ public class CarNavigationBarController { mHvacControllerLazy.get().connectToCarService(); } - /** Clean up hvac. */ - public void removeAllFromHvac() { + /** Clean up */ + public void removeAll() { mHvacControllerLazy.get().removeAllComponents(); + mButtonSelectionStateController.removeAll(); + mButtonRoleHolderController.removeAll(); } /** Gets the top window if configured to do so. */ @@ -211,6 +216,7 @@ public class CarNavigationBarController { view.setStatusBarWindowTouchListener(statusBarTouchListener); view.setNotificationsPanelController(notifShadeController); mButtonSelectionStateController.addAllButtonsWithSelectionState(view); + mButtonRoleHolderController.addAllButtonsWithRoleName(view); mHvacControllerLazy.get().addTemperatureViewToController(view); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java index 5f4ac2dcb141..5e113d6366a1 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationButton.java @@ -17,9 +17,11 @@ package com.android.systemui.car.navigationbar; import android.app.ActivityOptions; +import android.app.role.RoleManager; import android.content.Context; import android.content.Intent; import android.content.res.TypedArray; +import android.graphics.drawable.Drawable; import android.os.Build; import android.os.UserHandle; import android.util.AttributeSet; @@ -29,6 +31,7 @@ import android.view.View; import android.widget.ImageView; import android.widget.LinearLayout; +import com.android.internal.annotations.VisibleForTesting; import com.android.keyguard.AlphaOptimizedImageButton; import com.android.systemui.R; @@ -62,6 +65,8 @@ public class CarNavigationButton extends LinearLayout { private float mUnselectedAlpha; private int mSelectedIconResourceId; private int mIconResourceId; + private Drawable mAppIcon; + private boolean mIsDefaultAppIconForRoleEnabled; private String[] mComponentNames; /** App categories that are to be used with this widget */ private String[] mButtonCategories; @@ -92,7 +97,9 @@ public class CarNavigationButton extends LinearLayout { super.setSelected(selected); mSelected = selected; if (mHighlightWhenSelected) { - setAlpha(mSelected ? mSelectedAlpha : mUnselectedAlpha); + // Always apply selected alpha if the button does not toggle alpha based on selection + // state. + setAlpha(!mHighlightWhenSelected || mSelected ? mSelectedAlpha : mUnselectedAlpha); } if (mShowMoreWhenSelected && mMoreIcon != null) { mMoreIcon.setVisibility(selected ? VISIBLE : GONE); @@ -108,6 +115,20 @@ public class CarNavigationButton extends LinearLayout { updateImage(); } + /** + * Sets the current icon of the default application associated with this button. + */ + public void setAppIcon(Drawable appIcon) { + mAppIcon = appIcon; + updateImage(); + } + + /** Gets the icon of the app currently associated to the role of this button. */ + @VisibleForTesting + protected Drawable getAppIcon() { + return mAppIcon; + } + /** Gets whether the icon is in an unseen state. */ public boolean getUnseen() { return mHasUnseen; @@ -144,6 +165,22 @@ public class CarNavigationButton extends LinearLayout { } /** + * Subclasses should override this method to return the {@link RoleManager} role associated + * with this button. + */ + protected String getRoleName() { + return null; + } + + /** + * @return true if this button should show the icon of the default application for the + * role returned by {@link #getRoleName()}. + */ + protected boolean isDefaultAppIconForRoleEnabled() { + return mIsDefaultAppIconForRoleEnabled; + } + + /** * @return The id of the display the button is on or Display.INVALID_DISPLAY if it's not yet on * a display. */ @@ -240,7 +277,6 @@ public class CarNavigationButton extends LinearLayout { }; } - /** * Initializes view-related aspects of the button. */ @@ -256,28 +292,27 @@ public class CarNavigationButton extends LinearLayout { R.styleable.CarNavigationButton_showMoreWhenSelected, mShowMoreWhenSelected); - mSelectedIconResourceId = typedArray.getResourceId( - R.styleable.CarNavigationButton_selectedIcon, mIconResourceId); mIconResourceId = typedArray.getResourceId( R.styleable.CarNavigationButton_icon, 0); - + mSelectedIconResourceId = typedArray.getResourceId( + R.styleable.CarNavigationButton_selectedIcon, mIconResourceId); + mIsDefaultAppIconForRoleEnabled = typedArray.getBoolean( + R.styleable.CarNavigationButton_useDefaultAppIconForRole, false); mIcon = findViewById(R.id.car_nav_button_icon_image); - mIcon.setScaleType(ImageView.ScaleType.CENTER); // Always apply selected alpha if the button does not toggle alpha based on selection state. mIcon.setAlpha(mHighlightWhenSelected ? mUnselectedAlpha : mSelectedAlpha); - mIcon.setImageResource(mIconResourceId); - mMoreIcon = findViewById(R.id.car_nav_button_more_icon); mMoreIcon.setAlpha(mSelectedAlpha); - mMoreIcon.setVisibility(GONE); - mUnseenIcon = findViewById(R.id.car_nav_button_unseen_icon); - - mUnseenIcon.setVisibility(mHasUnseen ? VISIBLE : GONE); + updateImage(); } private void updateImage() { - mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId); + if (mIsDefaultAppIconForRoleEnabled && mAppIcon != null) { + mIcon.setImageDrawable(mAppIcon); + } else { + mIcon.setImageResource(mSelected ? mSelectedIconResourceId : mIconResourceId); + } mUnseenIcon.setVisibility(mHasUnseen ? VISIBLE : GONE); } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java index d18eadd18386..d692487d410e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBar.java @@ -45,7 +45,6 @@ import com.android.systemui.car.bluetooth.CarBatteryController; import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.fragments.FragmentHostManager; import com.android.systemui.keyguard.DismissCallbackRegistry; @@ -173,7 +172,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, - @Main Executor mainExecutor, NotificationMediaManager notificationMediaManager, NotificationLockscreenUserManager lockScreenUserManager, NotificationRemoteInputManager remoteInputManager, @@ -254,7 +252,6 @@ public class CarStatusBar extends StatusBar implements CarBatteryController.Batt displayMetrics, metricsLogger, uiBgExecutor, - mainExecutor, notificationMediaManager, lockScreenUserManager, remoteInputManager, diff --git a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java index 4f6890e3aba1..dc2eb04c2990 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/statusbar/CarStatusBarModule.java @@ -33,7 +33,6 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -148,7 +147,6 @@ public class CarStatusBarModule { DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, - @Main Executor mainExecutor, NotificationMediaManager notificationMediaManager, NotificationLockscreenUserManager lockScreenUserManager, NotificationRemoteInputManager remoteInputManager, @@ -228,7 +226,6 @@ public class CarStatusBarModule { displayMetrics, metricsLogger, uiBgExecutor, - mainExecutor, notificationMediaManager, lockScreenUserManager, remoteInputManager, diff --git a/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml b/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml new file mode 100644 index 000000000000..25ec2c179c8c --- /dev/null +++ b/packages/CarSystemUI/tests/res/layout/button_role_holder_controller_test.xml @@ -0,0 +1,41 @@ +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:systemui="http://schemas.android.com/apk/res-auto" + android:id="@id/nav_buttons" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" + android:paddingStart="20dp" + android:paddingEnd="20dp" + android:gravity="center"> + + <com.android.systemui.car.navigationbar.AssitantButton + android:id="@+id/assistant_role_button" + style="@style/NavigationBarButton" + systemui:icon="@drawable/car_ic_overview" + systemui:useDefaultAppIconForRole="true" + /> + + <com.android.systemui.car.navigationbar.AssitantButton + android:id="@+id/assistant_role_disabled_button" + style="@style/NavigationBarButton" + systemui:icon="@drawable/car_ic_overview" + /> + +</LinearLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml index f0e02164a24b..a8e83d6d7717 100644 --- a/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml +++ b/packages/CarSystemUI/tests/res/layout/car_button_selection_state_controller_test.xml @@ -25,7 +25,7 @@ android:paddingEnd="20dp" android:gravity="center"> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/detectable_by_component_name" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -34,7 +34,7 @@ systemui:highlightWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/detectable_by_category" style="@style/NavigationBarButton" systemui:categories="android.intent.category.APP_MAPS" @@ -43,7 +43,7 @@ systemui:highlightWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/detectable_by_package" style="@style/NavigationBarButton" systemui:icon="@drawable/car_ic_phone" diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml index b0ca8dc4cd34..94edc4b5e245 100644 --- a/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml +++ b/packages/CarSystemUI/tests/res/layout/car_navigation_bar_view_test.xml @@ -14,7 +14,7 @@ ~ limitations under the License. --> -<com.android.systemui.navigationbar.car.CarNavigationBarView +<com.android.systemui.car.navigationbar.CarNavigationBarView xmlns:android="http://schemas.android.com/apk/res/android" xmlns:systemui="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" @@ -32,7 +32,7 @@ android:paddingEnd="20dp" android:gravity="center"> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/home" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -55,4 +55,4 @@ android:visibility="gone" /> -</com.android.systemui.navigationbar.car.CarNavigationBarView> +</com.android.systemui.car.navigationbar.CarNavigationBarView> diff --git a/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml b/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml index 576928cda089..44f834040391 100644 --- a/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml +++ b/packages/CarSystemUI/tests/res/layout/car_navigation_button_test.xml @@ -25,7 +25,7 @@ android:paddingEnd="20dp" android:gravity="center"> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/default_no_selection_state" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -34,7 +34,7 @@ systemui:selectedIcon="@drawable/car_ic_overview_selected" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/app_grid_activity" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.AppGridActivity" @@ -44,7 +44,7 @@ systemui:highlightWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/long_click_app_grid_activity" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.AppGridActivity" @@ -54,7 +54,7 @@ systemui:highlightWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/broadcast" android:layout_width="match_parent" android:layout_height="match_parent" @@ -63,7 +63,7 @@ systemui:intent="intent:#Intent;action=android.car.intent.action.TOGGLE_HVAC_CONTROLS;end" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/selected_icon_undefined" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -71,7 +71,7 @@ systemui:intent="intent:#Intent;action=android.intent.action.MAIN;category=android.intent.category.HOME;launchFlags=0x14000000;end" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/highlightable_no_more_button" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -81,7 +81,7 @@ systemui:highlightWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/not_highlightable_more_button" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -91,7 +91,7 @@ systemui:showMoreWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/highlightable_more_button" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -102,7 +102,7 @@ systemui:showMoreWhenSelected="true" /> - <com.android.systemui.navigationbar.car.CarNavigationButton + <com.android.systemui.car.navigationbar.CarNavigationButton android:id="@+id/broadcast" style="@style/NavigationBarButton" systemui:componentNames="com.android.car.carlauncher/.CarLauncher" @@ -112,4 +112,13 @@ systemui:broadcast="true" /> + <com.android.systemui.car.navigationbar.AssitantButton + android:id="@+id/role_based_button" + style="@style/NavigationBarButton" + systemui:icon="@drawable/car_ic_overview" + systemui:selectedIcon="@drawable/car_ic_overview_selected" + systemui:useDefaultAppIconForRole="true" + systemui:highlightWhenSelected="true" + /> + </LinearLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java new file mode 100644 index 000000000000..a57736bb3502 --- /dev/null +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/ButtonRoleHolderControllerTest.java @@ -0,0 +1,187 @@ +/* + * 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.car.navigationbar; + +import static com.google.common.truth.Truth.assertThat; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; + +import android.app.role.RoleManager; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.graphics.drawable.Drawable; +import android.os.UserHandle; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.widget.LinearLayout; + +import androidx.test.filters.SmallTest; + +import com.android.systemui.SysuiTestCase; +import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.tests.R; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.List; + +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper +@SmallTest +public class ButtonRoleHolderControllerTest extends SysuiTestCase { + private static final String TEST_VALID_PACKAGE_NAME = "foo"; + private static final String TEST_INVALID_PACKAGE_NAME = "bar"; + private static final UserHandle TEST_CURRENT_USER = UserHandle.of(100); + private static final UserHandle TEST_NON_CURRENT_USER = UserHandle.of(101); + + private LinearLayout mTestView; + private CarNavigationButton mNavButtonDefaultAppIconForRoleWithEnabled; + private CarNavigationButton mNavButtonDefaultAppIconForRoleWithDisabled; + private ButtonRoleHolderController mControllerUnderTest; + private Drawable mAppIcon; + + @Mock + private RoleManager mRoleManager; + @Mock + private CarDeviceProvisionedController mDeviceProvisionedController; + @Mock + private PackageManager mPackageManager; + @Mock + private ApplicationInfo mApplicationInfo; + + @Before + public void setUp() throws PackageManager.NameNotFoundException { + MockitoAnnotations.initMocks(this); + + mTestView = (LinearLayout) LayoutInflater.from(mContext).inflate( + R.layout.button_role_holder_controller_test, /* root= */ null); + mNavButtonDefaultAppIconForRoleWithEnabled = mTestView + .findViewById(R.id.assistant_role_button); + mNavButtonDefaultAppIconForRoleWithDisabled = mTestView + .findViewById(R.id.assistant_role_disabled_button); + mAppIcon = mContext.getDrawable(R.drawable.car_ic_apps); + when(mApplicationInfo.loadIcon(any())).thenReturn(mAppIcon); + doThrow(new PackageManager.NameNotFoundException()).when(mPackageManager) + .getApplicationInfo(any(), anyInt()); + doReturn(mApplicationInfo).when(mPackageManager) + .getApplicationInfo(eq(TEST_VALID_PACKAGE_NAME), anyInt()); + when(mDeviceProvisionedController + .getCurrentUser()) + .thenReturn(TEST_CURRENT_USER.getIdentifier()); + mControllerUnderTest = new ButtonRoleHolderController(mContext, + mPackageManager, mRoleManager, mDeviceProvisionedController); + } + + @Test + public void addAllButtonsWithRoleName_roleAssigned_appIconEnabled_useAssignedAppIcon() { + when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_VALID_PACKAGE_NAME)); + + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + + assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isEqualTo(mAppIcon); + } + + @Test + public void addAllButtonsWithRoleName_roleUnassigned_appIconEnabled_useDefaultIcon() { + when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(null); + + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + + assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isNull(); + } + + @Test + public void onRoleChanged_currentUser_appIconEnabled_useAssignedAppIcon() { + when(mRoleManager.getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(null); + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_VALID_PACKAGE_NAME)); + + mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_CURRENT_USER); + + assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isEqualTo(mAppIcon); + } + + @Test + public void onRoleChanged_nonCurrentUser_appIconEnabled_iconIsNotUpdated() { + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(null); + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + Drawable beforeIcon = mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon(); + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_VALID_PACKAGE_NAME)); + + mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_NON_CURRENT_USER); + + Drawable afterIcon = mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon(); + assertThat(afterIcon).isEqualTo(beforeIcon); + } + + @Test + public void onRoleChanged_invalidPackage_useDefaultIcon() { + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_INVALID_PACKAGE_NAME)); + + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + + assertThat(mNavButtonDefaultAppIconForRoleWithEnabled.getAppIcon()).isNull(); + } + + @Test + public void addAllButtonsWithRoleName_appIconDisabled_useDefaultIcon() { + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_VALID_PACKAGE_NAME)); + + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + + assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull(); + } + + @Test + public void onRoleChanged_roleAssigned_appIconDisabled_useDefaultIcon() { + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(null); + mControllerUnderTest.addAllButtonsWithRoleName(mTestView); + assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull(); + when(mRoleManager + .getRoleHoldersAsUser(eq(RoleManager.ROLE_ASSISTANT), any())) + .thenReturn(List.of(TEST_VALID_PACKAGE_NAME)); + + mControllerUnderTest.onRoleChanged(RoleManager.ROLE_ASSISTANT, TEST_CURRENT_USER); + + assertThat(mNavButtonDefaultAppIconForRoleWithDisabled.getAppIcon()).isNull(); + } +} diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java index 911f624d1fb3..e84e42c77245 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarControllerTest.java @@ -53,6 +53,8 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Mock private ButtonSelectionStateController mButtonSelectionStateController; @Mock + private ButtonRoleHolderController mButtonRoleHolderController; + @Mock private HvacController mHvacController; @Before @@ -66,10 +68,15 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { mDependency.injectMockDependency(StatusBarIconController.class); } + private CarNavigationBarController createNavigationBarController() { + return new CarNavigationBarController(mContext, mNavigationBarViewFactory, + mButtonSelectionStateController, () -> mHvacController, + mButtonRoleHolderController); + } + @Test public void testConnectToHvac_callsConnect() { - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); mCarNavigationBar.connectToHvac(); @@ -77,20 +84,37 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { } @Test - public void testRemoveAllFromHvac_callsRemoveAll() { - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + public void testRemoveAll_callsHvacControllerRemoveAllComponents() { + mCarNavigationBar = createNavigationBarController(); - mCarNavigationBar.removeAllFromHvac(); + mCarNavigationBar.removeAll(); verify(mHvacController).removeAllComponents(); } + + @Test + public void testRemoveAll_callsButtonRoleHolderControllerRemoveAll() { + mCarNavigationBar = createNavigationBarController(); + + mCarNavigationBar.removeAll(); + + verify(mButtonRoleHolderController).removeAll(); + } + + @Test + public void testRemoveAll_callsButtonSelectionStateControllerRemoveAll() { + mCarNavigationBar = createNavigationBarController(); + + mCarNavigationBar.removeAll(); + + verify(mButtonSelectionStateController).removeAll(); + } + @Test public void testGetTopWindow_topDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, false); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getTopWindow(); @@ -100,8 +124,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetTopWindow_topEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getTopWindow(); @@ -111,8 +134,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetTopWindow_topEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableTopNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window1 = mCarNavigationBar.getTopWindow(); ViewGroup window2 = mCarNavigationBar.getTopWindow(); @@ -123,8 +145,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetBottomWindow_bottomDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, false); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -134,8 +155,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetBottomWindow_bottomEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getBottomWindow(); @@ -145,8 +165,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetBottomWindow_bottomEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window1 = mCarNavigationBar.getBottomWindow(); ViewGroup window2 = mCarNavigationBar.getBottomWindow(); @@ -157,8 +176,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetLeftWindow_leftDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, false); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getLeftWindow(); assertThat(window).isNull(); } @@ -166,8 +184,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetLeftWindow_leftEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getLeftWindow(); @@ -177,8 +194,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetLeftWindow_leftEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window1 = mCarNavigationBar.getLeftWindow(); ViewGroup window2 = mCarNavigationBar.getLeftWindow(); @@ -189,8 +205,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetRightWindow_rightDisabled_returnsNull() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, false); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -200,8 +215,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetRightWindow_rightEnabled_returnsWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getRightWindow(); @@ -211,8 +225,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testGetRightWindow_rightEnabled_calledTwice_returnsSameWindow() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window1 = mCarNavigationBar.getRightWindow(); ViewGroup window2 = mCarNavigationBar.getRightWindow(); @@ -223,8 +236,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetBottomWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.VISIBLE); @@ -235,8 +247,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetBottomWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getBottomWindow(); mCarNavigationBar.setBottomWindowVisibility(View.GONE); @@ -247,8 +258,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetLeftWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.VISIBLE); @@ -259,8 +269,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetLeftWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableLeftNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getLeftWindow(); mCarNavigationBar.setLeftWindowVisibility(View.GONE); @@ -271,8 +280,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetRightWindowVisibility_setTrue_isVisible() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.VISIBLE); @@ -283,8 +291,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testSetRightWindowVisibility_setFalse_isGone() { mTestableResources.addOverride(R.bool.config_enableRightNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); ViewGroup window = mCarNavigationBar.getRightWindow(); mCarNavigationBar.setRightWindowVisibility(View.GONE); @@ -295,8 +302,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRegisterBottomBarTouchListener_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View.OnTouchListener controller = bottomBar.getStatusBarWindowTouchListener(); @@ -310,8 +316,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRegisterBottomBarTouchListener_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); mCarNavigationBar.registerBottomBarTouchListener(mock(View.OnTouchListener.class)); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); @@ -323,8 +328,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRegisterNotificationController_createViewFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationBarController.NotificationsShadeController controller = @@ -340,8 +344,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testRegisterNotificationController_registerFirst_registrationSuccessful() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); mCarNavigationBar.registerNotificationController( mock(CarNavigationBarController.NotificationsShadeController.class)); @@ -355,8 +358,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testShowAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -368,8 +370,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testShowAllKeyguardButtons_bottomEnabled_bottomNavButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -381,8 +382,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testHideAllKeyguardButtons_bottomEnabled_bottomKeyguardButtonsGone() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomKeyguardButtons = bottomBar.findViewById(R.id.lock_screen_nav_buttons); @@ -396,8 +396,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testHideAllKeyguardButtons_bottomEnabled_bottomNavButtonsVisible() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); View bottomButtons = bottomBar.findViewById(R.id.nav_buttons); @@ -411,8 +410,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_hasUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); @@ -426,8 +424,7 @@ public class CarNavigationBarControllerTest extends SysuiTestCase { @Test public void testToggleAllNotificationsUnseenIndicator_bottomEnabled_noUnseen_setCorrectly() { mTestableResources.addOverride(R.bool.config_enableBottomNavigationBar, true); - mCarNavigationBar = new CarNavigationBarController(mContext, mNavigationBarViewFactory, - mButtonSelectionStateController, () -> mHvacController); + mCarNavigationBar = createNavigationBarController(); CarNavigationBarView bottomBar = mCarNavigationBar.getBottomBar(/* isSetUp= */ true); CarNavigationButton notifications = bottomBar.findViewById(R.id.notifications); diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java index 04e0a7324adf..0caa86f0eab2 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationBarTest.java @@ -89,6 +89,8 @@ public class CarNavigationBarTest extends SysuiTestCase { @Mock private ButtonSelectionStateListener mButtonSelectionStateListener; @Mock + private ButtonRoleHolderController mButtonRoleHolderController; + @Mock private IStatusBarService mBarService; @Mock private KeyguardStateController mKeyguardStateController; @@ -137,8 +139,8 @@ public class CarNavigationBarTest extends SysuiTestCase { mCarNavigationBarController, mLightBarController, mStatusBarIconController, mWindowManager, mDeviceProvisionedController, new CommandQueue(mContext), mAutoHideController, mButtonSelectionStateListener, mHandler, mUiBgExecutor, - mBarService, () -> mKeyguardStateController, mButtonSelectionStateController, - () -> mIconPolicy, () -> mIconController); + mBarService, () -> mKeyguardStateController, () -> mIconPolicy, + () -> mIconController); } @Test diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java index 11f2fa48783f..54282d39998b 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/navigationbar/CarNavigationButtonTest.java @@ -180,6 +180,56 @@ public class CarNavigationButtonTest extends SysuiTestCase { } @Test + public void onUnselected_withAppIcon_showsAppIcon() { + CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); + Drawable appIcon = getContext().getDrawable(R.drawable.ic_android); + + roleBasedButton.setSelected(false); + roleBasedButton.setAppIcon(appIcon); + + Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + assertThat(currentDrawable).isEqualTo(appIcon); + } + + @Test + public void onUnselected_withAppIcon_applyUnselectedAlpha() { + CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); + + roleBasedButton.setSelected(false); + roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android)); + + assertThat(roleBasedButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_UNSELECTED_ALPHA); + } + + @Test + public void onSelected_withAppIcon_showsAppIconWithSelectedAlpha() { + CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); + Drawable appIcon = getContext().getDrawable(R.drawable.ic_android); + + roleBasedButton.setSelected(true); + roleBasedButton.setAppIcon(appIcon); + + Drawable currentDrawable = ((AlphaOptimizedImageButton) roleBasedButton.findViewById( + R.id.car_nav_button_icon_image)).getDrawable(); + + assertThat(currentDrawable).isEqualTo(appIcon); + } + + @Test + public void onSelected_withAppIcon_applySelectedAlpha() { + CarNavigationButton roleBasedButton = mTestView.findViewById(R.id.role_based_button); + + roleBasedButton.setSelected(true); + roleBasedButton.setAppIcon(getContext().getDrawable(R.drawable.ic_android)); + + assertThat(roleBasedButton.getAlpha()).isEqualTo( + CarNavigationButton.DEFAULT_SELECTED_ALPHA); + } + + @Test public void onClick_launchesIntentActivity() { mDefaultButton.performClick(); diff --git a/packages/SettingsLib/Android.bp b/packages/SettingsLib/Android.bp index ac4e1ea11dae..5afe2f3d2efc 100644 --- a/packages/SettingsLib/Android.bp +++ b/packages/SettingsLib/Android.bp @@ -50,6 +50,7 @@ java_defaults { "SettingsLibAdaptiveIcon", "SettingsLibRadioButtonPreference", "SettingsLibDisplayDensityUtils", + "SettingsLibUtils", ], } diff --git a/packages/SettingsLib/Utils/Android.bp b/packages/SettingsLib/Utils/Android.bp new file mode 100644 index 000000000000..c5f0ee6c939c --- /dev/null +++ b/packages/SettingsLib/Utils/Android.bp @@ -0,0 +1,15 @@ +android_library { + name: "SettingsLibUtils", + + srcs: ["src/**/*.java"], + resource_dirs: ["res"], + + sdk_version: "system_current", + min_sdk_version: "21", + + apex_available: [ + + "//apex_available:platform", + "com.android.permission", + ], +} diff --git a/packages/SettingsLib/Utils/AndroidManifest.xml b/packages/SettingsLib/Utils/AndroidManifest.xml new file mode 100644 index 000000000000..fd89676ab6d7 --- /dev/null +++ b/packages/SettingsLib/Utils/AndroidManifest.xml @@ -0,0 +1,23 @@ +<?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. + --> + +<manifest xmlns:android="http://schemas.android.com/apk/res/android" + package="com.android.settingslib.utils"> + + <uses-sdk android:minSdkVersion="21" /> + +</manifest> diff --git a/packages/SettingsLib/Utils/res/values/strings.xml b/packages/SettingsLib/Utils/res/values/strings.xml new file mode 100644 index 000000000000..035e7f230d60 --- /dev/null +++ b/packages/SettingsLib/Utils/res/values/strings.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2020 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> + <!-- A content description for work profile app [CHAR LIMIT=35] --> + <string name="accessibility_work_profile_app_description">Work <xliff:g id="app_name" example="Camera">%s</xliff:g></string> +</resources>
\ No newline at end of file diff --git a/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java new file mode 100644 index 000000000000..6125b8509fcf --- /dev/null +++ b/packages/SettingsLib/Utils/src/com/android/settingslib/utils/applications/AppUtils.java @@ -0,0 +1,59 @@ +/* + * 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.settingslib.utils.applications; + +import android.content.Context; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.os.UserManager; +import android.util.Log; + +import com.android.settingslib.utils.R; + +public class AppUtils { + + private static final String TAG = AppUtils.class.getSimpleName(); + + /** Returns the label for a given package. */ + public static CharSequence getApplicationLabel( + PackageManager packageManager, String packageName) { + try { + final ApplicationInfo appInfo = + packageManager.getApplicationInfo( + packageName, + PackageManager.MATCH_DISABLED_COMPONENTS + | PackageManager.MATCH_ANY_USER); + return appInfo.loadLabel(packageManager); + } catch (PackageManager.NameNotFoundException e) { + Log.w(TAG, "Unable to find info for package: " + packageName); + } + return null; + } + + /** + * Returns a content description of an app name which distinguishes a personal app from a + * work app for accessibility purpose. + * If the app is in a work profile, then add a "work" prefix to the app name. + */ + public static String getAppContentDescription(Context context, String packageName, + int userId) { + final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName); + return context.getSystemService(UserManager.class).isManagedProfile(userId) + ? context.getString(R.string.accessibility_work_profile_app_description, appLabel) + : appLabel.toString(); + } +} diff --git a/packages/SettingsLib/res/drawable/ic_headphone.xml b/packages/SettingsLib/res/drawable/ic_headphone.xml new file mode 100644 index 000000000000..3b44f8f2153f --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_headphone.xml @@ -0,0 +1,29 @@ +<!-- + 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" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#000000" + android:pathData="M19,15v3c0,0.55 -0.45,1 -1,1h-1v-4h2M7,15v4H6c-0.55, + 0 -1,-0.45 -1,-1v-3h2m5,-13c-4.97,0 -9,4.03 -9,9v7c0,1.66 1.34,3 3,3h3v-8H5v-2c0, + -3.87 3.13,-7 7,-7s7,3.13 7,7v2h-4v8h3c1.66,0 3,-1.34 3,-3v-7c0,-4.97 -4.03, + -9 -9,-9z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_media_device.xml b/packages/SettingsLib/res/drawable/ic_media_display_device.xml index 5a6aeb4a8e23..78b4e2a23d45 100644 --- a/packages/SettingsLib/res/drawable/ic_media_device.xml +++ b/packages/SettingsLib/res/drawable/ic_media_display_device.xml @@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8"?> <!-- - Copyright (C) 2019 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,19 +15,16 @@ limitations under the License. --> <vector xmlns:android="http://schemas.android.com/apk/res/android" - android:viewportWidth="24" - android:viewportHeight="24" - android:width="24dp" - android:height="24dp" + android:width="14dp" + android:height="11dp" + android:viewportWidth="14" + android:viewportHeight="11" android:tint="?android:attr/colorControlNormal"> <path - android:fillColor="#00000000" - android:fillAlpha=".1" - android:pathData="M0 0h24v24H0z" /> - <path - android:fillColor="#00000000" - android:pathData="M0 0h24v24H0z" /> - <path + android:pathData="M10,10v1H4v-1H1.5A1.5,1.5 0,0 1,0 8.5v-7A1.5,1.5 0, + 0 1,1.5 0h11A1.5,1.5 0,0 1,14 1.5v7a1.5,1.5 0,0 1,-1.5 1.5H10zM1.5, + 1a0.5,0.5 0,0 0,-0.5 0.5v7a0.5,0.5 0,0 0,0.5 0.5h11a0.5,0.5 0,0 0, + 0.5 -0.5v-7a0.5,0.5 0,0 0,-0.5 -0.5h-11z" android:fillColor="#000000" - android:pathData="M21 3H3c-1.1 0-2 0.9-2 2v3h2V5h18v14h-7v2h7c1.1 0 2 -0.9 2-2V5c0-1.1 -0.9-2-2-2zM1 18v3h3c0-1.66-1.34-3-3-3zm0-4v2c2.76 0 5 2.24 5 5h2c0-3.87-3.13-7-7-7zm0-4v2c4.97 0 9 4.03 9 9h2c0-6.08-4.93-11-11-11z" /> + android:fillType="evenOdd"/> </vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_media_group_device.xml b/packages/SettingsLib/res/drawable/ic_media_group_device.xml index ba5e65119ead..478a86095869 100644 --- a/packages/SettingsLib/res/drawable/ic_media_group_device.xml +++ b/packages/SettingsLib/res/drawable/ic_media_group_device.xml @@ -21,12 +21,16 @@ android:viewportHeight="24" android:tint="?android:attr/colorControlNormal"> <path - android:pathData="M18.2,1L9.8,1C8.81,1 8,1.81 8,2.8v14.4c0,0.99 0.81,1.79 1.8,1.79l8.4,0.01c0.99,0 1.8,-0.81 1.8,-1.8L20,2.8c0,-0.99 -0.81,-1.8 -1.8,-1.8zM14,3c1.1,0 2,0.89 2,2s-0.9,2 -2,2 -2,-0.89 -2,-2 0.9,-2 2,-2zM14,16.5c-2.21,0 -4,-1.79 -4,-4s1.79,-4 4,-4 4,1.79 4,4 -1.79,4 -4,4z" - android:fillColor="#000000"/> + android:fillColor="#000000" + android:pathData="M19,4v14l-10,-0.01V4h10m0,-2H9c-1.1,0 -2,0.9 -2,2v13.99c0,1.1 0.89, + 2 2,2L19,20c1.1,0 2,-0.9 2,-2V4c0,-1.1 -0.9,-2 -2,-2z"/> <path - android:pathData="M14,12.5m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0" - android:fillColor="#000000"/> + android:fillColor="#000000" + android:pathData="M14,7m-1.5,0a1.5,1.5 0,1 1,3 0a1.5,1.5 0,1 1,-3 0"/> <path - android:pathData="M6,5H4v16c0,1.1 0.89,2 2,2h10v-2H6V5z" - android:fillColor="#000000"/> + android:fillColor="#000000" + android:pathData="M14,17c1.93,0 3.5,-1.57 3.5,-3.5S15.93,10 14,10s-3.5, + 1.57 -3.5,3.5S12.07,17 14,17zM14,12c0.83,0 1.5,0.67 1.5,1.5S14.83,15 14, + 15s-1.5,-0.67 -1.5,-1.5 0.67,-1.5 1.5,-1.5zM6,5L4,5v16c0,1.1 0.89,2 2, + 2h10v-2L6,21L6,5z"/> </vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_media_speaker_device.xml b/packages/SettingsLib/res/drawable/ic_media_speaker_device.xml new file mode 100644 index 000000000000..32fe7d1c17ff --- /dev/null +++ b/packages/SettingsLib/res/drawable/ic_media_speaker_device.xml @@ -0,0 +1,30 @@ +<!-- + 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" + android:tint="?android:attr/colorControlNormal"> + <path + android:fillColor="#000000" + android:pathData="M17,2L7,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,1.99 2,1.99L17, + 22c1.1,0 2,-0.9 2,-2L19,4c0,-1.1 -0.9,-2 -2,-2zM7,20L7,4h10v16L7,20zM12,9c1.1,0 2, + -0.9 2,-2s-0.9,-2 -2,-2c-1.11,0 -2,0.9 -2,2s0.89,2 2,2zM12,11c-2.21,0 -4,1.79 -4, + 4s1.79,4 4,4 4,-1.79 4,-4 -1.79,-4 -4,-4zM12,17c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2, + 0.9 2,2 -0.9,2 -2,2z"/> +</vector>
\ No newline at end of file diff --git a/packages/SettingsLib/res/drawable/ic_smartphone.xml b/packages/SettingsLib/res/drawable/ic_smartphone.xml index 84a96da95fb1..09811bb4b792 100644 --- a/packages/SettingsLib/res/drawable/ic_smartphone.xml +++ b/packages/SettingsLib/res/drawable/ic_smartphone.xml @@ -21,9 +21,8 @@ android:height="24dp" android:tint="?android:attr/colorControlNormal"> <path - android:fillColor="#00000000" - android:pathData="M0 0h24v24H0z" /> - <path android:fillColor="#000000" - android:pathData="M17 1.01L7 1c-1.1 0-2 0.9-2 2v18c0 1.1 0.9 2 2 2h10c1.1 0 2 -0.9 2-2V3c0-1.1 -0.9-1.99-2-1.99zM17 19H7V5h10v14z" /> + android:pathData="M17,1.01L7,1c-1.1,0 -2,0.9 -2,2v18c0,1.1 0.9, + 2 2,2h10c1.1,0 2,-0.9 2,-2L19,3c0,-1.1 -0.9,-1.99 -2,-1.99zM17, + 21L7,21v-1h10v1zM17,18L7,18L7,6h10v12zM7,4L7,3h10v1L7,4z"/> </vector> diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml index 66787c2a8663..704d264d1983 100644 --- a/packages/SettingsLib/res/values-af/strings.xml +++ b/packages/SettingsLib/res/values-af/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Gedeaktiveer"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Geaktiveer"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Jou toestel moet herselflaai om hierdie verandering toe te pas. Herselflaai nou of kanselleer."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Werk-<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedraade oorfoon"</string> </resources> diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml index ead0ebfa73bd..585924d7efb9 100644 --- a/packages/SettingsLib/res/values-am/strings.xml +++ b/packages/SettingsLib/res/values-am/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ተሰናክሏል"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ነቅቷል"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"የእርስዎን መሣሪያ ይህ ለው ለማመልከት እንደገና መነሣት አለበት። አሁን እንደገና ያስነሡ ወይም ይተዉት።"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"የስራ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ባለገመድ ጆሮ ማዳመጫ"</string> </resources> diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml index c1f4fd95813f..2b51b54a2fe3 100644 --- a/packages/SettingsLib/res/values-ar/strings.xml +++ b/packages/SettingsLib/res/values-ar/strings.xml @@ -557,7 +557,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غير مفعّل"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"مفعّل"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"يجب إعادة تشغيل جهازك ليتم تطبيق هذا التغيير. يمكنك إعادة التشغيل الآن أو إلغاء التغيير."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> المخصّص للعمل"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"سمّاعة رأس سلكية"</string> </resources> diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml index b5d642a9ae8f..e0455cb5f19c 100644 --- a/packages/SettingsLib/res/values-as/strings.xml +++ b/packages/SettingsLib/res/values-as/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"অক্ষম কৰা আছে"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"সক্ষম কৰা আছে"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই সলনিটো কার্যকৰী হ’বলৈ আপোনাৰ ডিভাইচটো ৰিবুট কৰিবই লাগিব। এতিয়াই ৰিবুট কৰক অথবা বাতিল কৰক।"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"কৰ্মস্থান <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তাঁৰযুক্ত হেডফ\'ন"</string> </resources> diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml index aecaf704b02f..6565d530f6a1 100644 --- a/packages/SettingsLib/res/values-az/strings.xml +++ b/packages/SettingsLib/res/values-az/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiv"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu dəyişikliyin tətbiq edilməsi üçün cihaz yenidən başladılmalıdır. İndi yenidən başladın və ya ləğv edin."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"İş <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli qulaqlıq"</string> </resources> diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml index 092bd42e60ce..3ced29b47dd6 100644 --- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml +++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate da restartujete uređaj da bi se ova promena primenila. Restartujte ga odmah ili otkažite."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za posao"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string> </resources> diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml index d610973d891c..d039c9f646df 100644 --- a/packages/SettingsLib/res/values-be/strings.xml +++ b/packages/SettingsLib/res/values-be/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Выключана"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Уключана"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Перазагрузіце прыладу, каб прымяніць гэта змяненне. Перазагрузіце ці скасуйце."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (праца)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Правадныя навушнікі"</string> </resources> diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml index 5c3fe75857dc..16029ee2b3b0 100644 --- a/packages/SettingsLib/res/values-bg/strings.xml +++ b/packages/SettingsLib/res/values-bg/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Деактивирано"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Активирано"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да бъде приложена тази промяна, устройството ви трябва да бъде рестартирано. Рестартирайте сега или анулирайте."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> за работа"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Слушалки с кабел"</string> </resources> diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml index 27d370714a0d..6ca48283a103 100644 --- a/packages/SettingsLib/res/values-bn/strings.xml +++ b/packages/SettingsLib/res/values-bn/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"বন্ধ করা আছে"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"চালু করা আছে"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"এই পরিবর্তনটি প্রয়োগ করার জন্য আপনার ডিভাইসটি অবশ্যই রিবুট করতে হবে। এখন রিবুট করুন বা বাতিল করুন।"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"অফিস <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"তার যুক্ত হেডফোন"</string> </resources> diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml index a9d9e7025236..50f0b76b6448 100644 --- a/packages/SettingsLib/res/values-bs/strings.xml +++ b/packages/SettingsLib/res/values-bs/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Morate ponovo pokrenuti uređaj da se ova promjena primijeni. Ponovo pokrenite odmah ili otkažite."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Poslovna aplikacija <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string> </resources> diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml index 5ed0f1b2d3ca..3ca9d5272d48 100644 --- a/packages/SettingsLib/res/values-ca/strings.xml +++ b/packages/SettingsLib/res/values-ca/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivat"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Has de reiniciar el teu dispositiu perquè s\'apliquin els canvis. Reinicia\'l ara o cancel·la."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de la feina"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculars amb cable"</string> </resources> diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml index d4d37353fb82..a5532e0bff02 100644 --- a/packages/SettingsLib/res/values-cs/strings.xml +++ b/packages/SettingsLib/res/values-cs/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuto"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuto"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aby se tato změna projevila, je třeba zařízení restartovat. Restartujte zařízení nebo zrušte akci."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Pracovní <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelová sluchátka"</string> </resources> diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml index 89dbf2581746..0dda52accbc5 100644 --- a/packages/SettingsLib/res/values-da/strings.xml +++ b/packages/SettingsLib/res/values-da/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiveret"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiveret"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Din enhed skal genstartes for at denne enhed bliver anvendt. Genstart nu, eller annuller."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> – arbejde"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Høretelefoner med ledning"</string> </resources> diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml index c2030b162e56..fe2a7751bead 100644 --- a/packages/SettingsLib/res/values-de/strings.xml +++ b/packages/SettingsLib/res/values-de/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Deaktiviert"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiviert"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Damit diese Änderung übernommen wird, musst du dein Gerät neu starten. Du kannst es jetzt neu starten oder den Vorgang abbrechen."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (geschäftlich)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kabelgebundene Kopfhörer"</string> </resources> diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml index bfc183e40a53..8db0b7e9dd28 100644 --- a/packages/SettingsLib/res/values-el/strings.xml +++ b/packages/SettingsLib/res/values-el/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ανενεργή"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ενεργή"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Για να εφαρμοστεί αυτή η αλλαγή, θα πρέπει να επανεκκινήσετε τη συσκευή σας. Επανεκκίνηση τώρα ή ακύρωση."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Εργασία <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ενσύρματα ακουστικά"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml index 9d869ba30717..0ef8e0677d6d 100644 --- a/packages/SettingsLib/res/values-en-rAU/strings.xml +++ b/packages/SettingsLib/res/values-en-rAU/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml index 9d869ba30717..0ef8e0677d6d 100644 --- a/packages/SettingsLib/res/values-en-rCA/strings.xml +++ b/packages/SettingsLib/res/values-en-rCA/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml index 9d869ba30717..0ef8e0677d6d 100644 --- a/packages/SettingsLib/res/values-en-rGB/strings.xml +++ b/packages/SettingsLib/res/values-en-rGB/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml index 9d869ba30717..0ef8e0677d6d 100644 --- a/packages/SettingsLib/res/values-en-rIN/strings.xml +++ b/packages/SettingsLib/res/values-en-rIN/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml index 77658243864e..41c20e0c915f 100644 --- a/packages/SettingsLib/res/values-en-rXC/strings.xml +++ b/packages/SettingsLib/res/values-en-rXC/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Disabled"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Enabled"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Your device must be rebooted for this change to apply. Reboot now or cancel."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Work <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml index 6a76bebc78ee..c27973f8bc86 100644 --- a/packages/SettingsLib/res/values-es-rUS/strings.xml +++ b/packages/SettingsLib/res/values-es-rUS/strings.xml @@ -153,7 +153,7 @@ <string name="unknown" msgid="3544487229740637809">"Desconocido"</string> <string name="running_process_item_user_label" msgid="3988506293099805796">"Usuario: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string> <string name="launch_defaults_some" msgid="3631650616557252926">"Configuraciones predeterminadas establecidas"</string> - <string name="launch_defaults_none" msgid="8049374306261262709">"No se establecieron configuraciones predeterminadas"</string> + <string name="launch_defaults_none" msgid="8049374306261262709">"Sin configuraciones predeterminadas"</string> <string name="tts_settings" msgid="8130616705989351312">"Configuración de texto a voz"</string> <string name="tts_settings_title" msgid="7602210956640483039">"Salida de texto a voz"</string> <string name="tts_default_rate_title" msgid="3964187817364304022">"Velocidad de voz"</string> @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Debes reiniciar el dispositivo para que se aplique el cambio. Reinícialo ahora o cancela la acción."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de trabajo"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string> </resources> diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml index 010b85b86df3..a0c00c33e466 100644 --- a/packages/SettingsLib/res/values-es/strings.xml +++ b/packages/SettingsLib/res/values-es/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inhabilitado"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Habilitado"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Es necesario reiniciar tu dispositivo para que se apliquen los cambios. Reiniciar ahora o cancelar."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de trabajo"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string> </resources> diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml index ad2a56152452..65f456e20e4e 100644 --- a/packages/SettingsLib/res/values-et/strings.xml +++ b/packages/SettingsLib/res/values-et/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Keelatud"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Lubatud"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Selle muudatuse rakendamiseks tuleb seade taaskäivitada. Taaskäivitage kohe või tühistage."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Töö: <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Juhtmega kõrvaklapid"</string> </resources> diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml index 1ceb738914f2..137116fcac2e 100644 --- a/packages/SettingsLib/res/values-eu/strings.xml +++ b/packages/SettingsLib/res/values-eu/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desgaituta"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Gaituta"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Aldaketa aplikatzeko, berrabiarazi egin behar da gailua. Berrabiaraz ezazu orain, edo utzi bertan behera."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Laneko <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Entzungailu kableduna"</string> </resources> diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml index d3f1c56cd1d7..1c0881531f89 100644 --- a/packages/SettingsLib/res/values-fa/strings.xml +++ b/packages/SettingsLib/res/values-fa/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیرفعال"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"برای اعمال این تغییر، دستگاهتان باید راهاندازی مجدد شود. اکنون راهاندازی مجدد کنید یا لغو کنید."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> محل کار"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"هدفون سیمی"</string> </resources> diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml index 5ab01c4b51b4..33e6659d633b 100644 --- a/packages/SettingsLib/res/values-fi/strings.xml +++ b/packages/SettingsLib/res/values-fi/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ei käytössä"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Käytössä"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Laitteesi on käynnistettävä uudelleen, jotta muutos tulee voimaan. Käynnistä uudelleen nyt tai peruuta."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (työ)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Langalliset kuulokkeet"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml index 26e50421cad8..140d4cee6ad7 100644 --- a/packages/SettingsLib/res/values-fr-rCA/strings.xml +++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Votre appareil doit être redémarré pour que ce changement prenne effet. Redémarrez-le maintenant ou annulez la modification."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (travail)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Écouteurs filaires"</string> </resources> diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml index b8fc50dc028b..09fe903baba2 100644 --- a/packages/SettingsLib/res/values-fr/strings.xml +++ b/packages/SettingsLib/res/values-fr/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Désactivé"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activé"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Vous devez redémarrer l\'appareil pour que cette modification soit appliquée. Redémarrez maintenant ou annulez l\'opération."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (travail)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Casque filaire"</string> </resources> diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml index 8dc58ef6f32f..3e8b1c1b9cde 100644 --- a/packages/SettingsLib/res/values-gl/strings.xml +++ b/packages/SettingsLib/res/values-gl/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desactivado"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activado"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necesario reiniciar o teu dispositivo para aplicar este cambio. Reiníciao agora ou cancela o cambio."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Aplicación <xliff:g id="APP_NAME">%s</xliff:g> do traballo"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auriculares con cable"</string> </resources> diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml index 9f69a2c0fa20..aa1f9605b07d 100644 --- a/packages/SettingsLib/res/values-gu/strings.xml +++ b/packages/SettingsLib/res/values-gu/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"બંધ છે"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ચાલુ છે"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"આ ફેરફારને લાગુ કરવા માટે તમારા ડિવાઇસને રીબૂટ કરવાની જરૂર છે. હમણાં જ રીબૂટ કરો કે રદ કરો."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ઑફિસ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"વાયરવાળો હૅડફોન"</string> </resources> diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml index dc8e28bb9df2..bfc4a4339345 100644 --- a/packages/SettingsLib/res/values-hi/strings.xml +++ b/packages/SettingsLib/res/values-hi/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद है"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"चालू है"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"बदली गई सेटिंग को लागू करने के लिए, अपने डिवाइस को फिर से चालू करें. डिवाइस को फिर से चालू करें या रद्द करें."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ऑफ़िस वाला <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर वाला हेडफ़ोन"</string> </resources> diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml index f8878396d867..14e3330a1670 100644 --- a/packages/SettingsLib/res/values-hr/strings.xml +++ b/packages/SettingsLib/res/values-hr/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogućeno"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogućeno"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Uređaj se mora ponovno pokrenuti da bi se ta promjena primijenila. Ponovo pokrenite uređaj odmah ili odustanite."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za posao"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žičane slušalice"</string> </resources> diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml index d7d269406f84..d16ff03b0903 100644 --- a/packages/SettingsLib/res/values-hu/strings.xml +++ b/packages/SettingsLib/res/values-hu/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Letiltva"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Engedélyezve"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Az eszközt újra kell indítani, hogy a módosítás megtörténjen. Indítsa újra most, vagy vesse el a módosítást."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Munkahelyi <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vezetékes fejhallgató"</string> </resources> diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml index a5ef6b557e4b..276ad88c43ef 100644 --- a/packages/SettingsLib/res/values-hy/strings.xml +++ b/packages/SettingsLib/res/values-hy/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Անջատված է"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Միացված է"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Սարքն անհրաժեշտ է վերագործարկել, որպեսզի փոփոխությունը կիրառվի։ Վերագործարկեք հիմա կամ չեղարկեք փոփոխությունը։"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Աշխատանքային <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Լարով ականջակալ"</string> </resources> diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml index 04ca2f69cc61..9735c163857d 100644 --- a/packages/SettingsLib/res/values-in/strings.xml +++ b/packages/SettingsLib/res/values-in/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Nonaktif"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktif"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Perangkat Anda harus di-reboot agar perubahan ini diterapkan. Reboot sekarang atau batalkan."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> kerja"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Headphone berkabel"</string> </resources> diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml index ce60eb50031d..0ebc341a9541 100644 --- a/packages/SettingsLib/res/values-is/strings.xml +++ b/packages/SettingsLib/res/values-is/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slökkt"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Virkt"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Endurræsa þarf tækið til að þessi breyting taki gildi. Endurræstu núna eða hættu við."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> í vinnu"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Heyrnartól með snúru"</string> </resources> diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml index bef644b60a3b..efc186aa24bb 100644 --- a/packages/SettingsLib/res/values-it/strings.xml +++ b/packages/SettingsLib/res/values-it/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Non attivo"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Attivo"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Devi riavviare il dispositivo per applicare questa modifica. Riavvia ora o annulla."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"App <xliff:g id="APP_NAME">%s</xliff:g> di lavoro"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Cuffie con cavo"</string> </resources> diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml index ed796326c708..3a45526290e0 100644 --- a/packages/SettingsLib/res/values-iw/strings.xml +++ b/packages/SettingsLib/res/values-iw/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"מושבת"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"מופעל"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"צריך להפעיל מחדש את המכשיר כדי להחיל את השינוי. יש להפעיל מחדש עכשיו או לבטל."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> של עבודה"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"אוזניות עם חוט"</string> </resources> diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml index 3f08a6ac83e2..0395770da819 100644 --- a/packages/SettingsLib/res/values-ja/strings.xml +++ b/packages/SettingsLib/res/values-ja/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"無効"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"有効"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"この変更を適用するには、デバイスの再起動が必要です。今すぐ再起動してください。キャンセルすることもできます。"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"仕事の<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線ヘッドフォン"</string> </resources> diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml index 2ebc3ee32c38..9b671a864e15 100644 --- a/packages/SettingsLib/res/values-ka/strings.xml +++ b/packages/SettingsLib/res/values-ka/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"გათიშული"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ჩართული"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ამ ცვლილების ასამოქმედებლად თქვენი მოწყობილობა უნდა გადაიტვირთოს. გადატვირთეთ ახლავე ან გააუქმეთ."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"სამსახურის <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"სადენიანი ყურსასმენი"</string> </resources> diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml index 91e548830ee9..1ee06b8353c9 100644 --- a/packages/SettingsLib/res/values-kk/strings.xml +++ b/packages/SettingsLib/res/values-kk/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өшірулі"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Қосулы"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бұл өзгеріс күшіне енуі үшін, құрылғыны қайта жүктеу керек. Қазір қайта жүктеңіз не бас тартыңыз."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (жұмыс)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Сымды құлақаспап"</string> </resources> diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml index 143f5f90a457..6c36d2f0f363 100644 --- a/packages/SettingsLib/res/values-km/strings.xml +++ b/packages/SettingsLib/res/values-km/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"បានបិទ"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"បានបើក"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ត្រូវតែចាប់ផ្ដើមឧបករណ៍របស់អ្នកឡើងវិញ ទើបការផ្លាស់ប្ដូរនេះត្រូវបានអនុវត្ត។ ចាប់ផ្ដើមឡើងវិញឥឡូវនេះ ឬបោះបង់។"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> សម្រាប់ការងារ"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"កាសមានខ្សែ"</string> </resources> diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml index 1df141ca9d9b..71c5e491d927 100644 --- a/packages/SettingsLib/res/values-kn/strings.xml +++ b/packages/SettingsLib/res/values-kn/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ಸಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ಈ ಬದಲಾವಣೆ ಅನ್ವಯವಾಗಲು ನಿಮ್ಮ ಸಾಧನವನ್ನು ರೀಬೂಟ್ ಮಾಡಬೇಕು. ಇದೀಗ ರೀಬೂಟ್ ಮಾಡಿ ಅಥವಾ ರದ್ದುಗೊಳಿಸಿ."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ಉದ್ಯೋಗ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ವೈಯರ್ ಹೊಂದಿರುವ ಹೆಡ್ಫೋನ್"</string> </resources> diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml index 86e165027652..5d82eae2fcba 100644 --- a/packages/SettingsLib/res/values-ko/strings.xml +++ b/packages/SettingsLib/res/values-ko/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"사용 중지됨"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"사용 설정됨"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"변경사항을 적용하려면 기기를 재부팅해야 합니다. 지금 재부팅하거나 취소하세요."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"직장용 <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"유선 헤드폰"</string> </resources> diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml index 925f4a706f70..6003e09f97bb 100644 --- a/packages/SettingsLib/res/values-ky/strings.xml +++ b/packages/SettingsLib/res/values-ky/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Өчүк"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Күйүк"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Бул өзгөртүүнү колдонуу үчүн түзмөктү өчүрүп күйгүзүңүз. Азыр өчүрүп күйгүзүңүз же жокко чыгарыңыз."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Жумуш <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Зымдуу гарнитура"</string> </resources> diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml index 3bf1996591f5..7a2c338ef008 100644 --- a/packages/SettingsLib/res/values-lo/strings.xml +++ b/packages/SettingsLib/res/values-lo/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ປິດການນຳໃຊ້ແລ້ວ"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ເປີດການນຳໃຊ້ແລ້ວ"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ທ່ານຕ້ອງປິດເປີດອຸປະກອນຄືນໃໝ່ເພື່ອນຳໃຊ້ການປ່ຽນແປງນີ້. ປິດເປີດໃໝ່ດຽວນີ້ ຫຼື ຍົກເລີກ."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ບ່ອນເຮັດວຽກ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ຫູຟັງແບບມີສາຍ"</string> </resources> diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml index 153c9956dc84..b73aa66ae54b 100644 --- a/packages/SettingsLib/res/values-lt/strings.xml +++ b/packages/SettingsLib/res/values-lt/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Išjungta"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Įgalinta"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kad pakeitimas būtų pritaikytas, įrenginį reikia paleisti iš naujo. Dabar paleiskite iš naujo arba atšaukite."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Darbo „<xliff:g id="APP_NAME">%s</xliff:g>“"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Laidinės ausinės"</string> </resources> diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml index f6e7f35d9211..8e5d24cfa81a 100644 --- a/packages/SettingsLib/res/values-lv/strings.xml +++ b/packages/SettingsLib/res/values-lv/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Atspējots"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Iespējots"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Lai šīs izmaiņas tiktu piemērotas, nepieciešama ierīces atkārtota palaišana. Atkārtoti palaidiet to tūlīt vai atceliet izmaiņas."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Darbā: <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vadu austiņas"</string> </resources> diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml index d55f1aff6f96..34299d801946 100644 --- a/packages/SettingsLib/res/values-mk/strings.xml +++ b/packages/SettingsLib/res/values-mk/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Оневозможено"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Овозможено"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"За да се примени променава, уредот мора да се рестартира. Рестартирајте сега или откажете."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Работна <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичени слушалки"</string> </resources> diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml index c5267d6b5b0a..ac643c3a6e62 100644 --- a/packages/SettingsLib/res/values-ml/strings.xml +++ b/packages/SettingsLib/res/values-ml/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"പ്രവർത്തനരഹിതമാക്കി"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"പ്രവർത്തനക്ഷമമാക്കി"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ഈ മാറ്റം ബാധകമാകുന്നതിന് നിങ്ങളുടെ ഉപകരണം റീബൂട്ട് ചെയ്യേണ്ടതുണ്ട്. ഇപ്പോൾ റീബൂട്ട് ചെയ്യുകയോ റദ്ദാക്കുകയോ ചെയ്യുക."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ഔദ്യോഗികം <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"വയർ മുഖേന ബന്ധിപ്പിച്ച ഹെഡ്ഫോൺ"</string> </resources> diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml index 0a01f8480d0c..0dd982b4cfc8 100644 --- a/packages/SettingsLib/res/values-mn/strings.xml +++ b/packages/SettingsLib/res/values-mn/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Идэвхгүй болгосон"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Идэвхжүүлсэн"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Энэ өөрчлөлтийг хэрэгжүүлэхийн тулд таны төхөөрөмжийг дахин асаах ёстой. Одоо дахин асаах эсвэл болино уу."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Ажлын <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Утастай чихэвч"</string> </resources> diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml index 075c748f1bb7..c50f365f68e3 100644 --- a/packages/SettingsLib/res/values-mr/strings.xml +++ b/packages/SettingsLib/res/values-mr/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"बंद केले आहे"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सुरू केले आहे"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"हा बदल लागू करण्यासाठी तुमचे डिव्हाइस रीबूट करणे आवश्यक आहे. आता रीबूट करा किंवा रद्द करा."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"कार्य <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"वायर असलेला हेडफोन"</string> </resources> diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml index cdf32a7b39ce..a0a434f05959 100644 --- a/packages/SettingsLib/res/values-ms/strings.xml +++ b/packages/SettingsLib/res/values-ms/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dilumpuhkan"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Didayakan"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Peranti anda mesti dibut semula supaya perubahan ini berlaku. But semula sekarang atau batalkan."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Kerja <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fon kepala berwayar"</string> </resources> diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml index 2bd3b450238f..fa499293ceab 100644 --- a/packages/SettingsLib/res/values-my/strings.xml +++ b/packages/SettingsLib/res/values-my/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ပိတ်ထားသည်"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ဖွင့်ထားသည်"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ဤအပြောင်းအလဲ ထည့်သွင်းရန် သင့်စက်ကို ပြန်လည်စတင်ရမည်။ ယခု ပြန်လည်စတင်ပါ သို့မဟုတ် ပယ်ဖျက်ပါ။"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"အလုပ် <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ကြိုးတပ်နားကြပ်"</string> </resources> diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml index de5bed63b70a..aeaba31691f9 100644 --- a/packages/SettingsLib/res/values-nb/strings.xml +++ b/packages/SettingsLib/res/values-nb/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Slått av"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Slått på"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten din må startes på nytt for at denne endringen skal tre i kraft. Start på nytt nå eller avbryt."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Jobb-<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hodetelefoner med kabel"</string> </resources> diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml index bfe295a4066a..4a2c1719aeb7 100644 --- a/packages/SettingsLib/res/values-ne/strings.xml +++ b/packages/SettingsLib/res/values-ne/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"असक्षम पारिएको छ"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"सक्षम पारिएको छ"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"यो परिवर्तन लागू गर्न तपाईंको यन्त्र अनिवार्य रूपमा रिबुट गर्नु पर्छ। अहिले रिबुट गर्नुहोस् वा रद्द गर्नुहोस्।"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"कार्यालयको प्रोफाइल <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"तारसहितको हेडफोन"</string> </resources> diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml index a82271981fca..e33df4ad7d1c 100644 --- a/packages/SettingsLib/res/values-nl/strings.xml +++ b/packages/SettingsLib/res/values-nl/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Uitgeschakeld"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ingeschakeld"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Je apparaat moet opnieuw worden opgestart om deze wijziging toe te passen. Start nu opnieuw op of annuleer de wijziging."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> voor werk"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Bedrade hoofdtelefoon"</string> </resources> diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml index ab9fbc364f43..8e5bf25a19ca 100644 --- a/packages/SettingsLib/res/values-or/strings.xml +++ b/packages/SettingsLib/res/values-or/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ଅକ୍ଷମ କରାଯାଇଛି"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ସକ୍ଷମ କରାଯାଇଛି"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ଏହି ପରିବର୍ତ୍ତନ ଲାଗୁ କରିବା ପାଇଁ ଆପଣଙ୍କ ଡିଭାଇସକୁ ନିଶ୍ଚିତ ରୂପେ ରିବୁଟ୍ କରାଯିବା ଆବଶ୍ୟକ। ବର୍ତ୍ତମାନ ରିବୁଟ୍ କରନ୍ତୁ କିମ୍ବା ବାତିଲ୍ କରନ୍ତୁ।"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ୱାର୍କ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ତାରଯୁକ୍ତ ହେଡଫୋନ୍"</string> </resources> diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml index 35d8cbab0b36..df9443057e28 100644 --- a/packages/SettingsLib/res/values-pa/strings.xml +++ b/packages/SettingsLib/res/values-pa/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ਬੰਦ ਕੀਤਾ ਗਿਆ"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ਚਾਲੂ ਕੀਤਾ ਗਿਆ"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ਇਸ ਤਬਦੀਲੀ ਨੂੰ ਲਾਗੂ ਕਰਨ ਲਈ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਨੂੰ ਰੀਬੂਟ ਕਰਨਾ ਲਾਜ਼ਮੀ ਹੈ। ਹੁਣੇ ਰੀਬੂਟ ਕਰੋ ਜਾਂ ਰੱਦ ਕਰੋ।"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ਕੰਮ <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"ਤਾਰ ਵਾਲੇ ਹੈੱਡਫ਼ੋਨ"</string> </resources> diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml index 54ed131797a9..fd5dfa5c9e8b 100644 --- a/packages/SettingsLib/res/values-pl/strings.xml +++ b/packages/SettingsLib/res/values-pl/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Wyłączono"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Włączono"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Wprowadzenie zmiany wymaga ponownego uruchomienia urządzenia. Uruchom ponownie teraz lub anuluj."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (do pracy)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Słuchawki przewodowe"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml index c6dc1d3376b9..4214a2720813 100644 --- a/packages/SettingsLib/res/values-pt-rBR/strings.xml +++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"App <xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml index 999e684f124d..40022677aeb4 100644 --- a/packages/SettingsLib/res/values-pt-rPT/strings.xml +++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativada"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativada"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reiniciar o dispositivo para aplicar esta alteração. Reinicie agora ou cancele."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Auscultadores com fios"</string> </resources> diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml index c6dc1d3376b9..4214a2720813 100644 --- a/packages/SettingsLib/res/values-pt/strings.xml +++ b/packages/SettingsLib/res/values-pt/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Desativado"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Ativado"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"É necessário reinicializar o dispositivo para que a mudança seja aplicada. Faça isso agora ou cancele."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"App <xliff:g id="APP_NAME">%s</xliff:g> de trabalho"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Fones de ouvido com fio"</string> </resources> diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml index ba2f36fc5c1d..f43387955711 100644 --- a/packages/SettingsLib/res/values-ro/strings.xml +++ b/packages/SettingsLib/res/values-ro/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Dezactivat"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Activat"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pentru ca modificarea să se aplice, trebuie să reporniți dispozitivul. Reporniți-l acum sau anulați."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> de serviciu"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Căști cu fir"</string> </resources> diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml index 8ec387584c5a..9c0a2f5beb8b 100644 --- a/packages/SettingsLib/res/values-ru/strings.xml +++ b/packages/SettingsLib/res/values-ru/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Отключено"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Включено"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Чтобы изменение вступило в силу, необходимо перезапустить устройство. Вы можете сделать это сейчас или позже."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Рабочее приложение \"<xliff:g id="APP_NAME">%s</xliff:g>\""</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Проводные наушники"</string> </resources> diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml index 01c36349bb8f..8d0e93e4b5f7 100644 --- a/packages/SettingsLib/res/values-si/strings.xml +++ b/packages/SettingsLib/res/values-si/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"අබල කළා"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"සබලයි"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"මෙම වෙනස යෙදීමට ඔබේ උපාංගය නැවත පණ ගැන්විය යුතුය. දැන් නැවත පණ ගන්වන්න හෝ අවලංගු කරන්න."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"කාර්යාල <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"රැහැන්ගත කළ හෙඩ්ෆෝන්"</string> </resources> diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml index b5cbf435f356..fc9a49ce0a5a 100644 --- a/packages/SettingsLib/res/values-sk/strings.xml +++ b/packages/SettingsLib/res/values-sk/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Vypnuté"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Zapnuté"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Táto zmena sa uplatní až po reštartovaní zariadenia. Zariadenie reštartujte alebo zmenu zrušte."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Pracovná aplikácia <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Slúchadlá s káblom"</string> </resources> diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml index 86cccb859e27..233c8e48635a 100644 --- a/packages/SettingsLib/res/values-sl/strings.xml +++ b/packages/SettingsLib/res/values-sl/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Onemogočeno"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Omogočeno"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Napravo je treba znova zagnati, da bo ta sprememba uveljavljena. Znova zaženite zdaj ali prekličite."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> za delo"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Žične slušalke"</string> </resources> diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml index bd3353cfc2d3..6af1062a98f8 100644 --- a/packages/SettingsLib/res/values-sq/strings.xml +++ b/packages/SettingsLib/res/values-sq/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Joaktiv"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiv"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Pajisja jote duhet të riniset që ky ndryshim të zbatohet. Rinise tani ose anuloje."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> për punën"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kufje me tela"</string> </resources> diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml index 29f23b48d5e0..74c2aec7c174 100644 --- a/packages/SettingsLib/res/values-sr/strings.xml +++ b/packages/SettingsLib/res/values-sr/strings.xml @@ -554,7 +554,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Онемогућено"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Омогућено"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Морате да рестартујете уређај да би се ова промена применила. Рестартујте га одмах или откажите."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> за посао"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Жичане слушалице"</string> </resources> diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml index a40100e83f51..fe1b0a856802 100644 --- a/packages/SettingsLib/res/values-sv/strings.xml +++ b/packages/SettingsLib/res/values-sv/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Inaktiverat"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Aktiverat"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Enheten måste startas om för att ändringen ska börja gälla. Starta om nu eller avbryt."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> för arbetet"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Hörlurar med sladd"</string> </resources> diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml index fedf1c85946c..41ccdeb29f3e 100644 --- a/packages/SettingsLib/res/values-sw/strings.xml +++ b/packages/SettingsLib/res/values-sw/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Imezimwa"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Imewashwa"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Ni lazima uwashe tena kifaa chako ili mabadiliko haya yatekelezwe. Washa tena sasa au ughairi."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Ya kazini <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Vipokea sauti vyenye waya vinavyobanwa kichwani"</string> </resources> diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml index 345f0a7c560d..241644f631d3 100644 --- a/packages/SettingsLib/res/values-ta/strings.xml +++ b/packages/SettingsLib/res/values-ta/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"முடக்கப்பட்டது"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"இயக்கப்பட்டது"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"இந்த மாற்றங்கள் செயல்படுத்தப்பட உங்கள் சாதனத்தை மறுபடி தொடங்க வேண்டும். இப்போதே மறுபடி தொடங்கவும் அல்லது ரத்துசெய்யவும்."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"பணியிடம் <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"வயருள்ள ஹெட்ஃபோன்"</string> </resources> diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml index c4fda01c19d2..a9ec2ea95ac5 100644 --- a/packages/SettingsLib/res/values-te/strings.xml +++ b/packages/SettingsLib/res/values-te/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"డిజేబుల్ చేయబడింది"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"ఎనేబుల్ చేయబడింది"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"ఈ మార్పును వర్తింపజేయాలంటే మీరు మీ పరికరాన్ని తప్పనిసరిగా రీబూట్ చేయాలి. ఇప్పుడే రీబూట్ చేయండి లేదా రద్దు చేయండి."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"ఆఫీసు <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"వైర్ ఉన్న హెడ్ఫోన్"</string> </resources> diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml index a9032ebf4fd2..b8343c6a82e7 100644 --- a/packages/SettingsLib/res/values-th/strings.xml +++ b/packages/SettingsLib/res/values-th/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"ปิดใช้"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"เปิดใช้"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"คุณต้องรีบูตอุปกรณ์เพื่อให้การเปลี่ยนแปลงนี้มีผล รีบูตเลยหรือยกเลิก"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> ในโปรไฟล์งาน"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"หูฟังแบบมีสาย"</string> </resources> diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml index 712c06bbea74..8aeb39256748 100644 --- a/packages/SettingsLib/res/values-tl/strings.xml +++ b/packages/SettingsLib/res/values-tl/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Naka-disable"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Na-enable"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Dapat i-reboot ang iyong device para mailapat ang pagbabagong ito. Mag-reboot ngayon o kanselahin."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> sa Trabaho"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Wired na headphone"</string> </resources> diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml index 8818498bbcfd..b113affdac71 100644 --- a/packages/SettingsLib/res/values-tr/strings.xml +++ b/packages/SettingsLib/res/values-tr/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Devre dışı"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Etkin"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bu değişikliğin geçerli olması için cihazının yeniden başlatılması gerekir. Şimdi yeniden başlatın veya iptal edin."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> (İş)"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Kablolu kulaklık"</string> </resources> diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml index f6568e3dbb5e..83329401f0bd 100644 --- a/packages/SettingsLib/res/values-uk/strings.xml +++ b/packages/SettingsLib/res/values-uk/strings.xml @@ -555,7 +555,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Вимкнено"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Увімкнено"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Щоб застосувати ці зміни, перезапустіть пристрій. Перезапустіть пристрій або скасуйте зміни."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Робочий додаток <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Дротові навушники"</string> </resources> diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml index f13f8fb40847..05cfeb67f86a 100644 --- a/packages/SettingsLib/res/values-ur/strings.xml +++ b/packages/SettingsLib/res/values-ur/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"غیر فعال"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"فعال"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"اس تبدیلی کو لاگو کرنے کے ليے آپ کے آلہ کو ریبوٹ کرنا ضروری ہے۔ ابھی ریبوٹ کریں یا منسوخ کریں۔"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"دفتر <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"وائرڈ ہیڈ فون"</string> </resources> diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml index 7b8f627ac0db..29a96371a2b1 100644 --- a/packages/SettingsLib/res/values-uz/strings.xml +++ b/packages/SettingsLib/res/values-uz/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Yoqilmagan"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Yoniq"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Oʻzgarishlar qurilma oʻchib yonganda bajariladi. Hoziroq oʻchib yoqish yoki bekor qilish."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Ish <xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Simli quloqlik"</string> </resources> diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml index 35cecc1a7b9f..380cd8ec1fba 100644 --- a/packages/SettingsLib/res/values-vi/strings.xml +++ b/packages/SettingsLib/res/values-vi/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Đã tắt"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Đã bật"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Bạn phải khởi động lại thiết bị để áp dụng sự thay đổi này. Hãy khởi động lại ngay hoặc hủy."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"<xliff:g id="APP_NAME">%s</xliff:g> dành cho công việc"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Tai nghe có dây"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml index c69ea2d4b668..75c1333c37c1 100644 --- a/packages/SettingsLib/res/values-zh-rCN/strings.xml +++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已启用"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"设备必须重新启动才能应用此更改。您可以立即重新启动或取消。"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"工作资料中的<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有线耳机"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml index b0324d9a2f46..26ddfb13717b 100644 --- a/packages/SettingsLib/res/values-zh-rHK/strings.xml +++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"您的裝置必須重新開機,才能套用此變更。請立即重新開機或取消。"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"工作設定檔入面嘅「<xliff:g id="APP_NAME">%s</xliff:g>」"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string> </resources> diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml index 0574c7ecf626..72ea0439b1f6 100644 --- a/packages/SettingsLib/res/values-zh-rTW/strings.xml +++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"已停用"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"已啟用"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"裝置必須重新啟動才能套用這項變更。請立即重新啟動或取消變更。"</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"工作資料夾中的<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"有線耳機"</string> </resources> diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml index b60553a052e4..6b8739fd017a 100644 --- a/packages/SettingsLib/res/values-zu/strings.xml +++ b/packages/SettingsLib/res/values-zu/strings.xml @@ -553,7 +553,5 @@ <string name="cached_apps_freezer_disabled" msgid="4816382260660472042">"Ikhutshaziwe"</string> <string name="cached_apps_freezer_enabled" msgid="8866703500183051546">"Inikwe amandla"</string> <string name="cached_apps_freezer_reboot_dialog_text" msgid="695330563489230096">"Kufanele idivayisi yakho iqaliswe ukuze lolu shintsho lusebenze. Qalisa manje noma khansela."</string> - <string name="accessibility_work_profile_app_description" msgid="5470883112342119165">"Umsebenzi we-<xliff:g id="APP_NAME">%s</xliff:g>"</string> - <!-- no translation found for media_transfer_wired_usb_device_name (7699141088423210903) --> - <skip /> + <string name="media_transfer_wired_usb_device_name" msgid="7699141088423210903">"Ama-headphone anentambo"</string> </resources> diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml index 9c7bdbd5b927..8e8368f9bc62 100644 --- a/packages/SettingsLib/res/values/strings.xml +++ b/packages/SettingsLib/res/values/strings.xml @@ -1374,9 +1374,6 @@ <!-- Developer setting dialog prompting the user to reboot after changing the app freezer setting [CHAR LIMIT=NONE]--> <string name="cached_apps_freezer_reboot_dialog_text">Your device must be rebooted for this change to apply. Reboot now or cancel.</string> - <!-- A content description for work profile app [CHAR LIMIT=35] --> - <string name="accessibility_work_profile_app_description">Work <xliff:g id="app_name" example="Camera">%s</xliff:g></string> - <!-- Name of the 3.5mm and usb audio device. [CHAR LIMIT=50] --> <string name="media_transfer_wired_usb_device_name">Wired headphone</string> </resources> diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java index b1f2a397bde6..a6202956efa5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/AppUtils.java @@ -26,7 +26,6 @@ import android.hardware.usb.IUsbManager; import android.os.RemoteException; import android.os.SystemProperties; import android.os.UserHandle; -import android.os.UserManager; import android.util.Log; import com.android.settingslib.R; @@ -112,17 +111,8 @@ public class AppUtils { /** Returns the label for a given package. */ public static CharSequence getApplicationLabel( PackageManager packageManager, String packageName) { - try { - final ApplicationInfo appInfo = - packageManager.getApplicationInfo( - packageName, - PackageManager.MATCH_DISABLED_COMPONENTS - | PackageManager.MATCH_ANY_USER); - return appInfo.loadLabel(packageManager); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "Unable to find info for package: " + packageName); - } - return null; + return com.android.settingslib.utils.applications.AppUtils + .getApplicationLabel(packageManager, packageName); } /** @@ -160,9 +150,7 @@ public class AppUtils { */ public static String getAppContentDescription(Context context, String packageName, int userId) { - final CharSequence appLabel = getApplicationLabel(context.getPackageManager(), packageName); - return UserManager.get(context).isManagedProfile(userId) - ? context.getString(R.string.accessibility_work_profile_app_description, appLabel) - : appLabel.toString(); + return com.android.settingslib.utils.applications.AppUtils.getAppContentDescription(context, + packageName, userId); } } diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java index af728887c917..1d4cfdc88ad5 100644 --- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java +++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java @@ -500,6 +500,20 @@ public class ApplicationsState { } } + /** + * To generate and cache the label description. + * + * @param entry contain the entries of an app + */ + public void ensureLabelDescription(AppEntry entry) { + if (entry.labelDescription != null) { + return; + } + synchronized (entry) { + entry.ensureLabelDescriptionLocked(mContext); + } + } + public void requestSize(String packageName, int userId) { if (DEBUG_LOCKING) Log.v(TAG, "requestSize about to acquire lock..."); synchronized (mEntriesMap) { @@ -1524,6 +1538,7 @@ public class ApplicationsState { public long size; public long internalSize; public long externalSize; + public String labelDescription; public boolean mounted; @@ -1616,6 +1631,24 @@ public class ApplicationsState { return ""; } } + + /** + * Get the label description which distinguishes a personal app from a work app for + * accessibility purpose. If the app is in a work profile, then add a "work" prefix to the + * app label. + * + * @param context The application context + */ + public void ensureLabelDescriptionLocked(Context context) { + final int userId = UserHandle.getUserId(this.info.uid); + if (UserManager.get(context).isManagedProfile(userId)) { + this.labelDescription = context.getString( + com.android.settingslib.R.string.accessibility_work_profile_app_description, + this.label); + } else { + this.labelDescription = this.label; + } + } } private static boolean hasFlag(int flags, int flag) { diff --git a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java index a2f77e2d5046..40d80488af96 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/BluetoothMediaDevice.java @@ -59,12 +59,18 @@ public class BluetoothMediaDevice extends MediaDevice { public Drawable getIcon() { final Pair<Drawable, String> pair = BluetoothUtils .getBtRainbowDrawableWithDescription(mContext, mCachedDevice); - return pair.first; + return isFastPairDevice() + ? pair.first + : BluetoothUtils.buildBtRainbowDrawable(mContext, + mContext.getDrawable(R.drawable.ic_headphone), + mCachedDevice.getAddress().hashCode()); } @Override public Drawable getIconWithoutBackground() { - return BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first; + return isFastPairDevice() + ? BluetoothUtils.getBtDrawableWithDescription(mContext, mCachedDevice).first + : mContext.getDrawable(R.drawable.ic_headphone); } @Override diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java index 22dc90643128..8d6bc5c97228 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java @@ -73,9 +73,11 @@ public class InfoMediaDevice extends MediaDevice { resId = R.drawable.ic_media_group_device; break; case TYPE_REMOTE_TV: + resId = R.drawable.ic_media_display_device; + break; case TYPE_REMOTE_SPEAKER: default: - resId = R.drawable.ic_media_device; + resId = R.drawable.ic_media_speaker_device; break; } return resId; diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java index 959c42fe75c9..b83a9c4835e0 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java @@ -219,6 +219,33 @@ public class InfoMediaManager extends MediaManager { } /** + * Get the MediaDevice list that can be removed from current media session. + * + * @return list of MediaDevice + */ + List<MediaDevice> getDeselectableMediaDevice() { + final List<MediaDevice> deviceList = new ArrayList<>(); + if (TextUtils.isEmpty(mPackageName)) { + Log.d(TAG, "getDeselectableMediaDevice() package name is null or empty!"); + return deviceList; + } + + final RoutingSessionInfo info = getRoutingSessionInfo(); + if (info != null) { + for (MediaRoute2Info route : mRouterManager.getDeselectableRoutes(info)) { + deviceList.add(new InfoMediaDevice(mContext, mRouterManager, + route, mPackageName)); + Log.d(TAG, route.getName() + " is deselectable for " + mPackageName); + } + return deviceList; + } + Log.d(TAG, "getDeselectableMediaDevice() cannot found deselectable MediaDevice from : " + + mPackageName); + + return deviceList; + } + + /** * Get the MediaDevice list that has been selected to current media. * * @return list of MediaDevice diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java index f34903cf7f98..e89f628a2757 100644 --- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java +++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java @@ -308,6 +308,15 @@ public class LocalMediaManager implements BluetoothCallback { } /** + * Get the MediaDevice list that can be removed from current media session. + * + * @return list of MediaDevice + */ + public List<MediaDevice> getDeselectableMediaDevice() { + return mInfoMediaManager.getDeselectableMediaDevice(); + } + + /** * Release session to stop playing media on MediaDevice. */ public boolean releaseSession() { diff --git a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java index 9dc454f53834..d5f1ece5f83f 100644 --- a/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java +++ b/packages/SettingsLib/src/com/android/settingslib/notification/ConversationIconFactory.java @@ -22,6 +22,7 @@ import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.graphics.Canvas; +import android.graphics.Color; import android.graphics.ColorFilter; import android.graphics.Paint; import android.graphics.Rect; @@ -40,18 +41,31 @@ import com.android.settingslib.R; * also includes shadows, which are only appropriate on top of wallpaper, not embedded in UI. */ public class ConversationIconFactory extends BaseIconFactory { - // Geometry of the various parts of the design. All values are 1dp on a 48x48dp icon grid. + // Geometry of the various parts of the design. All values are 1dp on a 56x56dp icon grid. // Space is left around the "head" (main avatar) for // ........ // .HHHHHH. // .HHHrrrr // .HHHrBBr // ....rrrr - - private static final float BASE_ICON_SIZE = 48f; - private static final float RING_STROKE_WIDTH = 2f; - private static final float HEAD_SIZE = BASE_ICON_SIZE - RING_STROKE_WIDTH * 2 - 2; // 40 - private static final float BADGE_SIZE = HEAD_SIZE * 0.4f; // 16 + // This is trying to recreate the view layout in notification_template_material_conversation.xml + + private static final float HEAD_SIZE = 52f; + private static final float BADGE_SIZE = 12f; + private static final float BADGE_CENTER = 46f; + private static final float CIRCLE_MARGIN = 36f; + private static final float BADGE_ORIGIN = HEAD_SIZE - BADGE_SIZE; // 40f + private static final float BASE_ICON_SIZE = 56f; + + private static final float OUT_CIRCLE_DIA = (BASE_ICON_SIZE - CIRCLE_MARGIN); // 20f + private static final float INN_CIRCLE_DIA = (float) Math.sqrt(2 * BADGE_SIZE * BADGE_SIZE) ; + private static final float OUT_CIRCLE_RAD = OUT_CIRCLE_DIA / 2; + private static final float INN_CIRCLE_RAD = INN_CIRCLE_DIA / 2; + // Android draws strokes centered on the radius, so our actual radius is an avg of the outside + // and inside of the ring stroke + private static final float CIRCLE_RADIUS = + INN_CIRCLE_RAD + ((OUT_CIRCLE_RAD - INN_CIRCLE_RAD) / 2); + private static final float RING_STROKE_WIDTH = (OUT_CIRCLE_DIA - INN_CIRCLE_DIA) / 2; final LauncherApps mLauncherApps; final PackageManager mPackageManager; @@ -125,6 +139,7 @@ public class ConversationIconFactory extends BaseIconFactory { private int mIconSize; private Paint mRingPaint; private boolean mShowRing; + private Paint mPaddingPaint; public ConversationIconDrawable(Drawable baseIcon, Drawable badgeIcon, @@ -138,6 +153,9 @@ public class ConversationIconFactory extends BaseIconFactory { mRingPaint = new Paint(); mRingPaint.setStyle(Paint.Style.STROKE); mRingPaint.setColor(ringColor); + mPaddingPaint = new Paint(); + mPaddingPaint.setStyle(Paint.Style.FILL_AND_STROKE); + mPaddingPaint.setColor(Color.WHITE); } /** @@ -165,40 +183,38 @@ public class ConversationIconFactory extends BaseIconFactory { public void draw(Canvas canvas) { final Rect bounds = getBounds(); - // scale to our internal 48x48 grid + // scale to our internal grid final float scale = bounds.width() / BASE_ICON_SIZE; - final int centerX = bounds.centerX(); - final int centerY = bounds.centerX(); final int ringStrokeWidth = (int) (RING_STROKE_WIDTH * scale); final int headSize = (int) (HEAD_SIZE * scale); - final int badgeSize = (int) (BADGE_SIZE * scale); + final int badgePadding = (int) (BADGE_ORIGIN * scale); + final int badgeCenter = (int) (BADGE_CENTER * scale); + mPaddingPaint.setStrokeWidth(ringStrokeWidth); + final float radius = (int) (CIRCLE_RADIUS * scale); // stroke outside if (mBaseIcon != null) { - mBaseIcon.setBounds( - centerX - headSize / 2, - centerY - headSize / 2, - centerX + headSize / 2, - centerY + headSize / 2); + mBaseIcon.setBounds(0, + 0, + headSize , + headSize); mBaseIcon.draw(canvas); } else { Log.w("ConversationIconFactory", "ConversationIconDrawable has null base icon"); } if (mBadgeIcon != null) { + canvas.drawCircle(badgeCenter, badgeCenter, radius, mPaddingPaint); mBadgeIcon.setBounds( - bounds.right - badgeSize - ringStrokeWidth, - bounds.bottom - badgeSize - ringStrokeWidth, - bounds.right - ringStrokeWidth, - bounds.bottom - ringStrokeWidth); + badgePadding, + badgePadding, + headSize, + headSize); mBadgeIcon.draw(canvas); } else { Log.w("ConversationIconFactory", "ConversationIconDrawable has null badge icon"); } if (mShowRing) { mRingPaint.setStrokeWidth(ringStrokeWidth); - final float radius = badgeSize * 0.5f + ringStrokeWidth * 0.5f; // stroke outside - final float cx = bounds.right - badgeSize * 0.5f - ringStrokeWidth; - final float cy = bounds.bottom - badgeSize * 0.5f - ringStrokeWidth; - canvas.drawCircle(cx, cy, radius, mRingPaint); + canvas.drawCircle(badgeCenter, badgeCenter, radius, mRingPaint); } } diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java index 685c834ff328..49b236a2188f 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java @@ -95,11 +95,13 @@ public class InfoMediaDeviceTest { public void getDrawableResId_returnCorrectResId() { when(mRouteInfo.getType()).thenReturn(TYPE_REMOTE_TV); - assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_device); + assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo( + R.drawable.ic_media_display_device); when(mRouteInfo.getType()).thenReturn(TYPE_REMOTE_SPEAKER); - assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo(R.drawable.ic_media_device); + assertThat(mInfoMediaDevice.getDrawableResId()).isEqualTo( + R.drawable.ic_media_speaker_device); when(mRouteInfo.getType()).thenReturn(TYPE_GROUP); diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java index c51467123233..248eb5b96b92 100644 --- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java +++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java @@ -416,6 +416,31 @@ public class InfoMediaManagerTest { } @Test + public void getDeselectableMediaDevice_packageNameIsNull_returnFalse() { + mInfoMediaManager.mPackageName = null; + + assertThat(mInfoMediaManager.getDeselectableMediaDevice()).isEmpty(); + } + + @Test + public void getDeselectableMediaDevice_checkList() { + final List<RoutingSessionInfo> routingSessionInfos = new ArrayList<>(); + final RoutingSessionInfo info = mock(RoutingSessionInfo.class); + routingSessionInfos.add(info); + final List<MediaRoute2Info> mediaRoute2Infos = new ArrayList<>(); + final MediaRoute2Info mediaRoute2Info = mock(MediaRoute2Info.class); + mediaRoute2Infos.add(mediaRoute2Info); + mShadowRouter2Manager.setRoutingSessions(routingSessionInfos); + mShadowRouter2Manager.setDeselectableRoutes(mediaRoute2Infos); + when(mediaRoute2Info.getName()).thenReturn(TEST_NAME); + + final List<MediaDevice> mediaDevices = mInfoMediaManager.getDeselectableMediaDevice(); + + assertThat(mediaDevices.size()).isEqualTo(1); + assertThat(mediaDevices.get(0).getName()).isEqualTo(TEST_NAME); + } + + @Test public void adjustSessionVolume_routingSessionInfoIsNull_noCrash() { mInfoMediaManager.adjustSessionVolume(null, 10); } diff --git a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java index db0cb0668a2f..5bb550053a12 100644 --- a/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java +++ b/packages/SettingsLib/tests/robotests/testutils/com/android/settingslib/testutils/shadow/ShadowRouter2Manager.java @@ -15,6 +15,7 @@ */ package com.android.settingslib.testutils.shadow; +import android.annotation.NonNull; import android.media.MediaRoute2Info; import android.media.MediaRouter2Manager; import android.media.RoutingSessionInfo; @@ -31,6 +32,7 @@ public class ShadowRouter2Manager { private List<MediaRoute2Info> mAvailableRoutes; private List<MediaRoute2Info> mAllRoutes; + private List<MediaRoute2Info> mDeselectableRoutes; private List<RoutingSessionInfo> mActiveSessions; private List<RoutingSessionInfo> mRoutingSessions; @@ -70,6 +72,15 @@ public class ShadowRouter2Manager { mRoutingSessions = infos; } + @Implementation + public List<MediaRoute2Info> getDeselectableRoutes(@NonNull RoutingSessionInfo sessionInfo) { + return mDeselectableRoutes; + } + + public void setDeselectableRoutes(List<MediaRoute2Info> routes) { + mDeselectableRoutes = routes; + } + public static ShadowRouter2Manager getShadow() { return (ShadowRouter2Manager) Shadow.extract( MediaRouter2Manager.getInstance(RuntimeEnvironment.application)); diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java index 3d7559b2c1a6..aae72e55b549 100644 --- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java +++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java @@ -1131,6 +1131,10 @@ class SettingsProtoDumpUtil { Settings.Global.NSD_ON, GlobalSettingsProto.NSD_ON); + dumpSetting(s, p, + Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE, + GlobalSettingsProto.NR_NSA_TRACKING_SCREEN_OFF_MODE); + final long ntpToken = p.start(GlobalSettingsProto.NTP); dumpSetting(s, p, Settings.Global.NTP_SERVER, diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java index e537b768d1af..fa87b62bd73a 100644 --- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java +++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java @@ -391,6 +391,7 @@ public class SettingsBackupTest { Settings.Global.NITZ_UPDATE_DIFF, Settings.Global.NITZ_UPDATE_SPACING, Settings.Global.NOTIFICATION_SNOOZE_OPTIONS, + Settings.Global.NR_NSA_TRACKING_SCREEN_OFF_MODE, Settings.Global.NSD_ON, Settings.Global.NTP_SERVER, Settings.Global.NTP_TIMEOUT, diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml index b85c7714bf96..ae8e8e82241d 100644 --- a/packages/Shell/AndroidManifest.xml +++ b/packages/Shell/AndroidManifest.xml @@ -300,6 +300,12 @@ <!-- Permissions needed to test shared libraries --> <uses-permission android:name="android.permission.ACCESS_SHARED_LIBRARIES" /> + <!-- Permissions required for CTS test - TVInputManagerTest --> + <uses-permission android:name="android.permission.TV_INPUT_HARDWARE" /> + + <!-- Permission needed for CTS test - PrivilegedLocationPermissionTest --> + <uses-permission android:name="android.permission.LOCATION_HARDWARE" /> + <application android:label="@string/app_label" android:theme="@android:style/Theme.DeviceDefault.DayNight" android:defaultToDeviceProtectedStorage="true" diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 055b2beaaa65..985269b2bb75 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -607,7 +607,7 @@ android:excludeFromRecents="true" android:stateNotNeeded="true" android:resumeWhilePausing="true" - android:theme="@android:style/Theme.Black.NoTitleBar"> + android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"> <intent-filter> <action android:name="android.app.action.CONFIRM_DEVICE_CREDENTIAL_WITH_USER" /> <category android:name="android.intent.category.DEFAULT" /> diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS index c8cf7f503468..28491d6e7e1f 100644 --- a/packages/SystemUI/OWNERS +++ b/packages/SystemUI/OWNERS @@ -41,6 +41,7 @@ tracyzhou@google.com tsuji@google.com twickham@google.com winsonc@google.com +zakcohen@google.com #Android Auto stenning@google.com diff --git a/packages/SystemUI/res-product/values/strings.xml b/packages/SystemUI/res-product/values/strings.xml index 54e5d4178d7a..f1c539e8eb4e 100644 --- a/packages/SystemUI/res-product/values/strings.xml +++ b/packages/SystemUI/res-product/values/strings.xml @@ -122,4 +122,12 @@ Try again in <xliff:g id="number">%3$d</xliff:g> seconds. </string> + + <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> + <string name="global_action_lock_message" product="default">Unlock your phone for more options</string> + <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> + <string name="global_action_lock_message" product="tablet">Unlock your tablet for more options</string> + <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> + <string name="global_action_lock_message" product="device">Unlock your device for more options</string> + </resources> diff --git a/packages/SystemUI/res/layout/controls_more_item.xml b/packages/SystemUI/res/layout/controls_more_item.xml index f24850e11e46..df03787d567c 100644 --- a/packages/SystemUI/res/layout/controls_more_item.xml +++ b/packages/SystemUI/res/layout/controls_more_item.xml @@ -18,5 +18,7 @@ style="@style/Control.MenuItem" android:layout_width="match_parent" android:layout_height="wrap_content" - android:layout_gravity="start" /> + android:layout_gravity="start" + android:paddingStart="@dimen/control_menu_horizontal_padding" + android:paddingEnd="@dimen/control_menu_horizontal_padding"/> diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 9f0a9bf971ee..3bd7e04f2094 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -21,33 +21,33 @@ android:layout_width="match_parent" android:layout_height="wrap_content" android:focusable="true" - android:clipChildren="false" + android:clipChildren="true" android:clipToPadding="true" android:orientation="vertical" android:background="@color/notification_material_background_color" - android:paddingStart="@*android:dimen/notification_content_margin_start"> + android:paddingStart="12dp"> <!-- Package Info --> <LinearLayout android:id="@+id/header" android:layout_width="match_parent" - android:layout_height="@dimen/notification_guts_conversation_header_height" + android:layout_height="wrap_content" android:gravity="center_vertical" android:clipChildren="false" - android:clipToPadding="false"> + android:paddingTop="8dp" + android:clipToPadding="true"> <ImageView android:id="@+id/conversation_icon" android:layout_width="@dimen/notification_guts_conversation_icon_size" android:layout_height="@dimen/notification_guts_conversation_icon_size" - android:layout_centerVertical="true" + android:layout_centerVertical="false" android:layout_alignParentStart="true" - android:layout_marginEnd="15dp" /> + android:layout_marginEnd="12dp" /> <LinearLayout android:id="@+id/names" android:layout_weight="1" android:layout_width="0dp" android:orientation="vertical" - android:layout_height="wrap_content" android:minHeight="@dimen/notification_guts_conversation_icon_size" android:layout_centerVertical="true" @@ -63,6 +63,8 @@ android:id="@+id/parent_channel_name" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:ellipsize="end" + android:textDirection="locale" android:layout_weight="1" style="@style/TextAppearance.NotificationImportanceChannel"/> <TextView diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index e8e0133103eb..af5a8f4d3c23 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -46,7 +46,6 @@ android:layout_weight="1" android:layout_width="0dp" android:orientation="vertical" - android:layout_height="wrap_content" android:minHeight="@dimen/notification_guts_conversation_icon_size" android:layout_centerVertical="true" @@ -57,6 +56,7 @@ android:id="@+id/channel_name" android:layout_width="match_parent" android:layout_height="wrap_content" + android:textDirection="locale" style="@style/TextAppearance.NotificationImportanceChannel"/> <LinearLayout android:layout_width="match_parent" @@ -84,6 +84,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_weight="1" + android:textDirection="locale" style="@style/TextAppearance.NotificationImportanceChannelGroup"/> </LinearLayout> <TextView diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml index 17469cd04b67..9e6b80bd1b25 100644 --- a/packages/SystemUI/res/values-af/strings.xml +++ b/packages/SystemUI/res/values-af/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoem om skerm te vul"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Strek om skerm te vul"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skermkiekie"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontsluit jou foon vir meer opsies"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontsluit jou tablet vir meer opsies"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontsluit jou toestel vir meer opsies"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"het \'n prent gestuur"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Stoor tans skermkiekie..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Stoor tans skermkiekie..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Ligging deur GPS gestel"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Liggingversoeke aktief"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors Af is aktief"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is aktief"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Verwyder alle kennisgewings."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Bestuur"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geskiedenis"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Stil"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Kennisgewings"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekke"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vee alle stil kennisgewings uit"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kennisgewings onderbreek deur Moenie Steur Nie"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Skakel kennisgewings af"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Hou aan om kennisgewings van hierdie program af te wys?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Verstek"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Borrel"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen klank of vibrasie nie"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen klank of vibrasie nie en verskyn laer in gespreksafdeling"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan lui of vibreer op grond van fooninstellings"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan lui of vibreer op grond van fooninstellings. Gesprekke van <xliff:g id="APP_NAME">%1$s</xliff:g> af verskyn by verstek in \'n borrel."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Hou jou aandag met \'n swewende kortpad na hierdie inhoud toe."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wys boaan die gespreksafdeling, verskyn as \'n swewende borrel, wys profielfoto op sluitskerm"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> steun nie gesprekspesifieke-instellings nie"</string> diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml index b40a617bb2bc..227194607ca5 100644 --- a/packages/SystemUI/res/values-am/strings.xml +++ b/packages/SystemUI/res/values-am/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ማያ እንዲሞላ አጉላ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ማያ ለመሙለት ሳብ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ቅጽበታዊ ገጽ እይታ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ለተጨማሪ አማራጮች የእርስዎን ስልክ ይክፈቱ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ለተጨማሪ አማራጮች የእርስዎን ጡባዊ ይክፈቱ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ለተጨማሪ አማራጮች የእርስዎን መሣሪያ ይክፈቱ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ምስል ተልኳል"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ቅጽበታዊ ገጽ እይታ በማስቀመጥ ላይ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"በ GPS የተዘጋጀ ሥፍራ"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"የአካባቢ ጥያቄዎች ነቅተዋል"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ዳሳሾች ጠፍተዋል ገቢር"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"ሚዲያ ገቢር ነው"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ሁሉንም ማሳወቂያዎች አጽዳ"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"ያቀናብሩ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ታሪክ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ገቢ"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ጸጥ ያለ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"ማሳወቂያዎች"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ውይይቶች"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ሁሉንም ጸጥ ያሉ ማሳወቂያዎችን ያጽዱ"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ማሳወቂያዎች በአትረብሽ ባሉበት ቆመዋል"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"ማሳወቂያዎችን አጥፋ"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ከዚህ መተግበሪያ ማሳወቂያዎችን ማሳየት ይቀጥል?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ፀጥ ያለ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ነባሪ"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"አረፋ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ምንም ድምጽ ወይም ንዝረት የለም"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ምንም ድምጽ ወይም ንዝረት የለም እና በውይይት ክፍል ላይ አይታይም"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"በእርስዎ የስልክ ቅንብሮች የሚወሰን ሆኖ ሊደውል ወይም ሊነዝር ይችላል"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"በእርስዎ የስልክ ቅንብሮች የሚወሰን ሆኖ ሊደውል ወይም ሊነዝር ይችላል። የ<xliff:g id="APP_NAME">%1$s</xliff:g> አረፋ ውይይቶች በነባሪነት።"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ለዚህ ይዞታ ከተንሳፋፊ አቋራጭ ጋር የእርስዎን ትኩረት ያቆያል።"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"በውይይት ክፍል አናት ላይ ያሳያል፣ እንደ ተንሳፋፊ አረፋ ብቅ ይላል፣ በቆልፍ ማያ ገጽ ላይ የመገለጫ ሥዕልን ያሳያል"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ቅንብሮች"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ቅድሚያ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ውይይት-ተኮር ቅንብሮችን አይደግፍም"</string> diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml index f33847c6406f..f871c10c0f5d 100644 --- a/packages/SystemUI/res/values-as/strings.xml +++ b/packages/SystemUI/res/values-as/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্ৰীণ পূর্ণ কৰিবলৈ জুম কৰক"</string> <string name="compat_mode_off" msgid="7682459748279487945">"স্ক্ৰীণ পূর্ণ কৰিবলৈ প্ৰসাৰিত কৰক"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্ৰীনশ্বট"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"অধিক বিকল্পৰ বাবে আপোনাৰ ফ’নটো আনলক কৰক"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"অধিক বিকল্পৰ বাবে আপোনাৰ টেবলেটটো আনলক কৰক"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"অধিক বিকল্পৰ বাবে আপোনাৰ ডিভাইচটো আনলক কৰক"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"এখন প্ৰতিচ্ছবি পঠিয়াইছে"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্ৰীণশ্বট ছেভ কৰি থকা হৈছে…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"জিপিএছএ অৱস্থান ছেট কৰিছে"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"অৱস্থানৰ অনুৰোধ সক্ৰিয় হৈ আছে"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ছেন্সৰ অফ সক্ৰিয় কৰা আছে"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"মিডিয়া সক্ৰিয় হৈ আছে"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"সকলো জাননী মচক৷"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"পৰিচালনা"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"অন্তৰ্গামী"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"নীৰৱ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"জাননীসমূহ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"বাৰ্তালাপ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সকলো নীৰৱ জাননী মচক"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"অসুবিধা নিদিব-ই জাননী পজ কৰিছে"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"জাননী অফ কৰক"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"এই এপটোৰ জাননী দেখুওৱাই থাকিব লাগিবনে?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"নীৰৱ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ডিফ’ল্ট"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"বাবল"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"কোনো ধ্বনি অথবা কম্পন নাই"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"কোনো ধ্বনি অথবা কম্পন নাই আৰু বাৰ্তালাপ শাখাটোৰ তলৰ অংশত দেখা পোৱা যায়"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ফ’নৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ফ’নৰ ছেটিঙৰ ওপৰত নিৰ্ভৰ কৰি ৰিং কৰিব অথবা কম্পন হ’ব পাৰে। <xliff:g id="APP_NAME">%1$s</xliff:g>ৰ বাৰ্তালাপ ডিফ’ল্ট হিচাপে বাবল হয়।"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"উপঙি থকা এটা শ্বৰ্টকাটৰ জৰিয়তে এই সমলখিনিৰ প্ৰতি আপোনাক মনোযোগী কৰি ৰাখে।"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"বাৰ্তালাপ শাখাটোৰ শীৰ্ষত দেখুৱায়, ওপঙা বাবল হিচাপে দেখা পোৱা যায়, লক স্ক্ৰীনত প্ৰ’ফাইলৰ চিত্ৰ প্ৰদৰ্শন কৰে"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ছেটিংসমূহ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"অগ্ৰাধিকাৰ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>এ বাৰ্তালাপ নিৰ্দিষ্ট ছেটিংসমূহ সমৰ্থন নকৰে"</string> diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml index 443d2f211f08..b7777cdeee69 100644 --- a/packages/SystemUI/res/values-az/strings.xml +++ b/packages/SystemUI/res/values-az/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ekranı doldurmaq üçün yaxınlaşdır"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ekranı doldurmaq üçün uzat"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinşot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Daha çox seçim üçün telefonu kiliddən çıxarın"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Daha çox seçim üçün planşeti kiliddən çıxarın"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Daha çox seçim üçün cihazı kiliddən çıxarın"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"şəkil göndərdi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinşot yadda saxlanılır..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinşot yadda saxlanır..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Yer GPS tərəfindən müəyyən edildi"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Məkan sorğuları arxivi"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"\"Deaktiv sensorlar\" aktivdir"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media aktivdir"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Bütün bildirişləri sil."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"İdarə edin"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Tarixçə"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gələn"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Səssiz"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirişlər"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Söhbətlər"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Səssiz bildirişlərin hamısını silin"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirişlər \"Narahat Etməyin\" rejimi tərəfindən dayandırıldı"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Bildirişləri deaktiv edin"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu tətbiqin bildirişləri göstərilməyə davam edilsin?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Səssiz"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Defolt"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Qabarcıq"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Səs və ya vibrasiya yoxdur"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Səs və ya vibrasiya yoxdur və söhbət bölməsinin aşağısında görünür"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon ayarlarına əsasən zəng çala və ya vibrasiya edə bilər"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon ayarlarına əsasən zəng çala və ya vibrasiya edə bilər. <xliff:g id="APP_NAME">%1$s</xliff:g> tətbiqindən söhbətlərdə defolt olaraq qabarcıq çıxır."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Bu məzmuna üzən qısayol ilə diqqətinizi cəlb edir."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Söhbət bölməsinin yuxarısında göstərilir, üzən qabarcıq kimi görünür, kilid ekranında profil şəkli göstərir"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> söhbətə aid ayarları dəstəkləmir"</string> diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml index 0f14ff1df298..e8f5dbb0fa95 100644 --- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml +++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj na celom ekranu"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci na ceo ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za još opcija"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za još opcija"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za još opcija"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Čuvanje snimka ekrana..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Čuvanje snimka ekrana..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokaciju je podesio GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Ima aktivnih zahteva za lokaciju"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Senzori su isključeni"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Medijum je aktivan"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Obriši sva obaveštenja."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"i još <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obaveštenja"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzacije"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obrišite sva nečujna obaveštenja"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obaveštenja su pauzirana režimom Ne uznemiravaj"</string> @@ -720,20 +714,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Isključi obaveštenja"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite li da se obaveštenja iz ove aplikacije i dalje prikazuju?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Podrazumevano"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka i vibriranja"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka i vibriranja i prikazuje se u nastavku odeljka za konverzacije"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Može da zvoni ili vibrira u zavisnosti od podešavanja telefona"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Može da zvoni ili vibrira u zavisnosti od podešavanja telefona. Konverzacije iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> se podrazumevano prikazuju u oblačićima."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Privlači vam pažnju pomoću plutajuće prečice do ovog sadržaja."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se u vrhu odeljka za konverzacije kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Podešavanja"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava podešavanja za konverzacije"</string> diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml index 610c18658930..d508ab3bcb77 100644 --- a/packages/SystemUI/res/values-be/strings.xml +++ b/packages/SystemUI/res/values-be/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Павял. на ўвесь экран"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Расцягн. на ўвесь экран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Здымак экрана"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Каб адкрыць іншыя параметры, разблакіруйце тэлефон"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Каб адкрыць іншыя параметры, разблакіруйце планшэт"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Каб адкрыць іншыя параметры, разблакіруйце прыладу"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"адпраўлены відарыс"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Захаванне скрыншота..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Захаванне скрыншота..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Месца задана праз GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Ёсць актыўныя запыты пра месцазнаходжанне"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Датчыкі выключаны"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Мультымедыя ўключана"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Выдалiць усе апавяшчэннi."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Кіраваць"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Гісторыя"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Уваходныя"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без гуку"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Апавяшчэнні"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Размовы"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Выдаліць усе апавяшчэнні без гуку"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Паказ апавяшчэнняў прыпынены ў рэжыме \"Не турбаваць\""</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Выключыць апавяшчэнні"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Працягваць паказваць апавяшчэнні гэтай праграмы?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Бязгучны рэжым"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Стандартна"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Усплывальнае апавяшчэнне"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без гуку ці вібрацыі"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Паказваецца без гуку ці вібрацыі ў раздзеле размоў"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"У залежнасці ад налад тэлефона магчымы званок або вібрацыя"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"У залежнасці ад налад тэлефона магчымы званок або вібрацыя. Размовы ў праграме \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" стандартна паяўляюцца ў выглядзе ўсплывальных апавяшчэнняў."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Прыцягвае ўвагу да гэтага змесціва ўсплывальнай кнопкай."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Паказваецца ўверсе раздзела размоў у выглядзе ўсплывальнага апавяшчэння, а на экране блакіроўкі – у выглядзе відарыса профілю"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налады"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Прыярытэт"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не падтрымлівае пэўныя налады размоў"</string> diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml index 26790c5eb4a3..a224bd6213ac 100644 --- a/packages/SystemUI/res/values-bg/strings.xml +++ b/packages/SystemUI/res/values-bg/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Мащаб – запълва екрана"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Разпъване – запълва екрана"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Екранна снимка"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Отключете телефона си за още опции"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Отключете таблета си за още опции"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Отключете устройството си за още опции"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"изпратено изображение"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Екранната снимка се запазва..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Екранната снимка се запазва..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Местоположението е зададено от GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Активни заявки за местоположение"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Сензорите са изключени"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Мултимедията е активна"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Изчистване на всички известия."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Управление"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящи"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Беззвучни"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Известия"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговори"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Изчистване на всички беззвучни известия"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Известията са поставени на пауза от режима „Не безпокойте“"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Изключване на известията"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Да продължат ли да се показват известията от това приложение?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Тих режим"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Стандартно"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Балонче"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звук или вибриране"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звук или вибриране и се показва по-долу в секцията с разговори"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може да звъни или да вибрира въз основа на настройките за телефона"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може да звъни или да вибрира въз основа на настройките за телефона. Разговорите от <xliff:g id="APP_NAME">%1$s</xliff:g> се показват като балончета по подразбиране."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Задържа вниманието ви посредством плаващ пряк път към това съдържание."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Показва се като плаващо балонче в горната част на секцията с разговори и показва снимката на потребителския профил на заключения екран"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не поддържа свързаните с разговорите настройки"</string> diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml index 46dd9b9afaf1..43a3f4e6306c 100644 --- a/packages/SystemUI/res/values-bn/strings.xml +++ b/packages/SystemUI/res/values-bn/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"আরও বিকল্প দেখতে আপনার ফোন আনলক করুন"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"আরও বিকল্প দেখতে আপনার ট্যাবলেট আনলক করুন"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"আরও বিকল্প দেখতে আপনার ডিভাইস আনলক করুন"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS এর দ্বারা সেট করা লোকেশন"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"লোকেশন অনুরোধ সক্রিয় রয়েছে"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"সেন্সর অফ অ্যাক্টিভ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"মিডিয়া চালু আছে"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"সমস্ত বিজ্ঞপ্তি সাফ করুন৷"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>টি"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"পরিচালনা করুন"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ইতিহাস"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ইনকামিং"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"আওয়াজ করবে না"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"বিজ্ঞপ্তি"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"কথোপকথন"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"সব নীরব বিজ্ঞপ্তি মুছুন"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'বিরক্ত করবে না\' দিয়ে বিজ্ঞপ্তি পজ করা হয়েছে"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"বিজ্ঞপ্তি বন্ধ করুন"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"এই অ্যাপের বিজ্ঞপ্তি পরেও দেখে যেতে চান?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"সাইলেন্ট"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ডিফল্ট"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"বাবল"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"আওয়াজ করবে না বা ভাইব্রেট হবে না"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"আওয়াজ করবে না বা ভাইব্রেট হবে না এবং কথোপকথন বিভাগের নিচের দিকে দেখা যাবে"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ফোনের সেটিংস অনুযায়ী ফোন রিং বা ভাইব্রেট হতে পারে"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ফোনের সেটিংস অনুযায়ী ফোন রিং বা ভাইব্রেট হতে পারে। <xliff:g id="APP_NAME">%1$s</xliff:g>-এর কথোপকথন সাধারণত বাবলের মতো দেখাবে।"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ফ্লোটিং শর্টকাট ব্যবহার করে এই কন্টেন্টে আপনার দৃষ্টি আকর্ষণ করে রাখে।"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"কথোপকথন বিভাগের উপরে ভাসমান বাবলের মতো দেখা যাবে, লক স্ক্রিনে প্রোফাইল ছবি দেখাবে"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"সেটিংস"</string> <string name="notification_priority_title" msgid="2079708866333537093">"অগ্রাধিকার"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> অ্যাপে কথোপকথনের ক্ষেত্রে প্রযোজ্য সেটিংস কাজ করে না"</string> diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml index 89ecc728e3ff..abb0167ba544 100644 --- a/packages/SystemUI/res/values-bs/strings.xml +++ b/packages/SystemUI/res/values-bs/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Uvećaj prikaz na ekran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Razvuci prikaz na ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimak ekrana"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Otključajte telefon za više opcija"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Otključajte tablet za više opcija"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Otključajte uređaj za više opcija"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslao/la sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spašavanje snimka ekrana..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spašavanje snimka ekrana..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokacija utvrđena GPS signalom"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktiviran je zahtjev za lokaciju"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Senzori su isključeni"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Medij je aktivan"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Uklanjanje svih obavještenja."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historija"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Nečujno"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavještenja"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Obriši sva nečujna obavještenja"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Obavještenja su pauzirana načinom rada Ne ometaj"</string> @@ -722,20 +716,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Isključi obavještenja"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Nastaviti prikazivanje obavještenja iz ove aplikacije?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Nečujno"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i pojavljuje se pri dnu odjeljka za razgovor"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Može zvoniti ili vibrirati na osnovu postavki vašeg telefona"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Može zvoniti ili vibrirati na osnovu postavki vašeg telefona. Razgovori iz oblačića u aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> kao zadana opcija."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Privlači vašu pažnju pomoću plutajuće prečice do ovog sadržaja."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se na vrhu odjeljka za razgovor, pojavljuje se kao plutajući oblačić, prikazuje sliku profila na zaključanom ekranu"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetni"</string> <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke za određeni razgovor"</string> diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml index e47865467ee7..62f5d9596581 100644 --- a/packages/SystemUI/res/values-ca/strings.xml +++ b/packages/SystemUI/res/values-ca/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per omplir pantalla"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estira per omplir pant."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueja el teu telèfon per veure més opcions"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueja la teva tauleta per veure més opcions"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueja el teu dispositiu per veure més opcions"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviat una imatge"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"S\'està desant captura de pantalla..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"S\'està desant la captura de pantalla..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"S\'ha establert la ubicació per GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Sol·licituds d\'ubicació actives"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors desactivats"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Hi ha fitxers multimèdia actius"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Esborra totes les notificacions."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gestiona"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrants"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenci"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacions"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Converses"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Esborra totes les notificacions silencioses"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificacions pausades pel mode No molestis"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desactiva les notificacions"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Vols continuar rebent notificacions d\'aquesta aplicació?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silenci"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bombolla"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sense so ni vibració"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sense so ni vibració i es mostra més avall a la secció de converses"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pot sonar o vibrar en funció de la configuració del telèfon"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pot sonar o vibrar en funció de la configuració del telèfon. Les converses de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g> es mostren com a bombolles de manera predeterminada."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Atrau la teva atenció amb una drecera flotant a aquest contingut."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Es mostra com a bombolla flotant a la part superior de la secció de converses i mostra la foto de perfil a la pantalla de bloqueig"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuració"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritat"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admet opcions de configuració específiques de converses"</string> diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml index a717c50d57f2..12b3d24ac8d6 100644 --- a/packages/SystemUI/res/values-cs/strings.xml +++ b/packages/SystemUI/res/values-cs/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Přiblížit na celou obrazovku"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Na celou obrazovku"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snímek obrazovky"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Chcete-li zobrazit další možnosti, odemkněte telefon"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Chcete-li zobrazit další možnosti, odemkněte tablet"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Chcete-li zobrazit další možnosti, odemkněte zařízení"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odesílá obrázek"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ukládání snímku obrazovky..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ukládání snímku obrazovky..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Poloha nastavena pomocí systému GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktivní žádosti o polohu"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Vypnutí senzorů je aktivní"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Média jsou aktivní"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Vymazat všechna oznámení."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"a ještě <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovat"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historie"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Příchozí"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tiché"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Oznámení"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzace"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazat všechna tichá oznámení"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Oznámení jsou pozastavena režimem Nerušit"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Vypnout oznámení"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Mají se oznámení z této aplikace nadále zobrazovat?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Ticho"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Výchozí"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bublina"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Žádný zvuk ani vibrace"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žádný zvuk ani vibrace a zobrazovat níže v sekci konverzací"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Může vyzvánět nebo vibrovat v závislosti na nastavení telefonu"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Může vyzvánět nebo vibrovat v závislosti na nastavení telefonu. Konverzace z aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> ve výchozím nastavení bublají."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Přitahuje pozornost pomocí plovoucí zkratky k tomuto obsahu."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Zobrazuje se v horní části sekce konverzace a má podobu plovoucí bubliny, zobrazuje profilovou fotku na obrazovce uzamčení"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavení"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string> <string name="no_shortcut" msgid="7176375126961212514">"Aplikace <xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavení specifická pro konverzaci"</string> diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml index a17311f65443..ede673d8fe73 100644 --- a/packages/SystemUI/res/values-da/strings.xml +++ b/packages/SystemUI/res/values-da/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom til fuld skærm"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stræk til fuld skærm"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås din telefon op for at se flere valgmuligheder"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås din tablet op for at se flere valgmuligheder"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås din enhed op for at se flere valgmuligheder"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendte et billede"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gemmer screenshot..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Gemmer screenshot..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Placeringen er angivet ved hjælp af GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktive placeringsanmodninger"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensorer er slået fra"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Der er aktive mediefiler"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Ryd alle notifikationer."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> mere"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Indgående"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Lydløs"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikationer"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ryd alle lydløse notifikationer"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikationer er sat på pause af Forstyr ikke"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Deaktiver notifikationer"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Vil du fortsætte med at se notifikationer fra denne app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Boble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibration, og den vises længere nede i samtalesektionen"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringe eller vibrere baseret på telefonens indstillinger"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringe eller vibrere baseret på telefonens indstillinger. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> vises som standard i bobler."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Fastholder din opmærksomhed med en svævende genvej til indholdet."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtalesektionen, som en svævende boble og med profilbillede på låseskærmen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Indstillinger"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> understøtter ikke samtalespecifikke indstillinger"</string> @@ -792,7 +780,7 @@ <string name="keyboard_key_dpad_left" msgid="8329738048908755640">"Venstre"</string> <string name="keyboard_key_dpad_right" msgid="6282105433822321767">"Højre"</string> <string name="keyboard_key_dpad_center" msgid="4079412840715672825">"Midtertast"</string> - <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab-tast"</string> + <string name="keyboard_key_tab" msgid="4592772350906496730">"Tab"</string> <string name="keyboard_key_space" msgid="6980847564173394012">"Mellemrumstast"</string> <string name="keyboard_key_enter" msgid="8633362970109751646">"Enter"</string> <string name="keyboard_key_backspace" msgid="4095278312039628074">"Tilbagetast"</string> diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml index a42c5126b66a..c0751c8a4fb0 100644 --- a/packages/SystemUI/res/values-el/strings.xml +++ b/packages/SystemUI/res/values-el/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ζουμ σε πλήρη οθόνη"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Προβoλή σε πλήρη οθ."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Στιγμιότυπο οθόνης"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ξεκλειδώστε το τηλέφωνό σας για περισσότερες επιλογές."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ξεκλειδώστε το tablet για περισσότερες επιλογές."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ξεκλειδώστε τη συσκευή σας για περισσότερες επιλογές."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"έστειλε μια εικόνα"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Αποθήκ. στιγμιότυπου οθόνης..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Αποθήκευση στιγμιότυπου οθόνης..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Ρύθμιση τοποθεσίας με GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Τα αιτήματα τοποθεσίας έχουν ενεργοποιηθεί"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Απενεργοποίηση αισθητήρων ενεργή"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Το πολυμέσο είναι ενεργό."</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Διαγραφή όλων των ειδοποιήσεων."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Διαχείριση"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ιστορικό"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Εισερχόμενες"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Σίγαση"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ειδοποιήσεις"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Συζητήσεις"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Διαγραφή όλων των ειδοποιήσεων σε σίγαση"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Οι ειδοποιήσεις τέθηκαν σε παύση από τη λειτουργία \"Μην ενοχλείτε\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Απενεργοποίηση ειδοποιήσεων"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Να συνεχίσουν να εμφανίζονται ειδοποιήσεις από αυτήν την εφαρμογή;"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Σίγαση"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Προεπιλογή"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Φούσκα"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Χωρίς ήχο ή δόνηση"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Χωρίς ήχο ή δόνηση και εμφανίζεται χαμηλά στην ενότητα συζητήσεων"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Ενδέχεται να κουδουνίζει ή να δονείται βάσει των ρυθμίσεων του τηλεφώνου. Οι συζητήσεις από την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> εμφανίζονται σε συννεφάκι από προεπιλογή."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Κρατάει την προσοχή σας με μια κινούμενη συντόμευση προς αυτό το περιεχόμενο."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Εμφανίζεται στο επάνω μέρος της ενότητας συζητήσεων, προβάλλεται ως κινούμενο συννεφάκι, εμφανίζει τη φωτογραφία προφίλ στην οθόνη κλειδώματος"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ρυθμίσεις"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Προτεραιότητα"</string> <string name="no_shortcut" msgid="7176375126961212514">"Η εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g> δεν υποστηρίζει ρυθμίσεις για συγκεκριμένη συνομιλία"</string> diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml index 7ca02ddf7beb..6f86e5089da9 100644 --- a/packages/SystemUI/res/values-en-rAU/strings.xml +++ b/packages/SystemUI/res/values-en-rAU/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Location set by GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Location requests active"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors off active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is active"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Clear all notifications."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+<xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Turn off notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Keeps your attention with a floating shortcut to this content."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string> diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml index 2e09b6562e0b..711e6458f6f0 100644 --- a/packages/SystemUI/res/values-en-rCA/strings.xml +++ b/packages/SystemUI/res/values-en-rCA/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Location set by GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Location requests active"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors off active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is active"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Clear all notifications."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+<xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Turn off notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Keeps your attention with a floating shortcut to this content."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string> diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml index 7ca02ddf7beb..6f86e5089da9 100644 --- a/packages/SystemUI/res/values-en-rGB/strings.xml +++ b/packages/SystemUI/res/values-en-rGB/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Location set by GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Location requests active"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors off active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is active"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Clear all notifications."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+<xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Turn off notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Keeps your attention with a floating shortcut to this content."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string> diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml index 7ca02ddf7beb..6f86e5089da9 100644 --- a/packages/SystemUI/res/values-en-rIN/strings.xml +++ b/packages/SystemUI/res/values-en-rIN/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Location set by GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Location requests active"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensors off active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is active"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Clear all notifications."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+<xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Manage"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Incoming"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silent"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Clear all silent notifications"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications paused by Do Not Disturb"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Turn off notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Keep showing notifications from this app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silent"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"No sound or vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No sound or vibration and appears lower in conversation section"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"May ring or vibrate based on phone settings"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"May ring or vibrate based on phone settings. Conversations from <xliff:g id="APP_NAME">%1$s</xliff:g> bubble by default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Keeps your attention with a floating shortcut to this content."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shows at top of conversation section, appears as floating bubble, displays profile picture on lock screen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Settings"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priority"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> does not support conversation-specific settings"</string> diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml index 9b8d5d716b8f..ee0e232ec9b4 100644 --- a/packages/SystemUI/res/values-en-rXC/strings.xml +++ b/packages/SystemUI/res/values-en-rXC/strings.xml @@ -77,9 +77,6 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom to fill screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stretch to fill screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Unlock your phone for more options"</string> - <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Unlock your tablet for more options"</string> - <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Unlock your device for more options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sent an image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saving screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Saving screenshot…"</string> diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml index 90ff857fa153..a0328677e775 100644 --- a/packages/SystemUI/res/values-es-rUS/strings.xml +++ b/packages/SystemUI/res/values-es-rUS/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ocupar la pantalla"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estirar p/ ocupar la pantalla"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea la tablet para ver más opciones"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"envió una imagen"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura de pantalla"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando la captura de pantalla..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"La ubicación se estableció por GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitudes de ubicación activas"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados sí"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Se está reproduciendo contenido multimedia"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Eliminar todas las notificaciones"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Administrar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrante"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciosas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo \"No interrumpir\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desactivar notificaciones"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"¿Quieres seguir viendo las notificaciones de esta app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencio"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Cuadro"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"No suena ni vibra, y aparece en una parte inferior de la sección de conversaciones"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Puede sonar o vibrar en función de la configuración del teléfono"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Puede sonar o vibrar en función de la configuración del teléfono. Conversaciones de la burbuja de <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Retiene tu atención con un acceso directo flotante a este contenido."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece en la parte superior de la sección de conversaciones, en forma de burbuja flotante, y muestra la foto de perfil en la pantalla de bloqueo"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no admite opciones de configuración específicas de conversaciones"</string> diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml index 5a691fce43b6..4fb2bc42e0de 100644 --- a/packages/SystemUI/res/values-es/strings.xml +++ b/packages/SystemUI/res/values-es/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para ajustar"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Expandir para ajustar"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de pantalla"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea el teléfono para ver más opciones"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea el tablet para ver más opciones"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea el dispositivo para ver más opciones"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ha enviado una imagen"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Guardando captura..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Guardando captura..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Ubicación definida por GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitudes de ubicación activas"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desactivados"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Hay archivos multimedia activos"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Borrar todas las notificaciones"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> más"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciadas"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificaciones"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversaciones"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borrar todas las notificaciones silenciadas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificaciones pausadas por el modo No molestar"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desactivar notificaciones"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"¿Quieres seguir viendo las notificaciones de esta aplicación?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencio"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Predeterminada"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Burbuja"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sin sonido ni vibración"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sin sonido ni vibración y se muestra más abajo en la sección de conversaciones"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Según los ajustes definidos en el teléfono, es posible que suene o vibre"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Según los ajustes definidos en el teléfono, es posible que suene o vibre. Las conversaciones de <xliff:g id="APP_NAME">%1$s</xliff:g> aparecen como burbujas de forma predeterminada."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Llama tu atención con un acceso directo flotante a este contenido."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se muestra en la parte superior de la sección de conversaciones en forma de burbuja flotante, y la imagen de perfil aparece en la pantalla de bloqueo"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ajustes"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridad"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> no es compatible con ajustes específicos de conversaciones"</string> diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml index ef32e10bd900..8124dd49eca6 100644 --- a/packages/SystemUI/res/values-et/strings.xml +++ b/packages/SystemUI/res/values-et/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Suumi ekraani täitmiseks"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Venita ekraani täitmiseks"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekraanipilt"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lisavalikute nägemiseks avage oma telefon"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lisavalikute nägemiseks avage oma tahvelarvuti"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lisavalikute nägemiseks avage oma seade"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"saatis kujutise"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Kuvatõmmise salvestamine ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Kuvatõmmise salvestamine ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS-i määratud asukoht"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Asukoha taotlused on aktiivsed"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Valik Andurid on väljas on aktiivne"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Meedia on aktiivne"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Kustuta kõik teatised."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Haldamine"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ajalugu"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Sissetulevad"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Hääletu"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Märguanded"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Vestlused"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kustuta kõik hääletud märguanded"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Režiim Mitte segada peatas märguanded"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Lülita märguanded välja"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Kas jätkata selle rakenduse märguannete kuvamist?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Hääletu"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Vaikeseade"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Mull"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ilma heli ja vibreerimiseta"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ilma heli ja vibreerimiseta, kuvatakse vestluste jaotises allpool"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Võib telefoni seadete põhjal heliseda või vibreerida"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Võib telefoni seadete põhjal heliseda või vibreerida. Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> vestlused kuvatakse vaikimisi mullis."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Hoiab teie tähelepanu hõljuva otseteega selle sisu juurde."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Kuvatakse vestluste jaotise ülaosas hõljuva mullina ja lukustuskuval kuvatakse profiilipilt"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Seaded"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteetne"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei toeta vestluspõhiseid seadeid"</string> diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml index b83323e874b7..d4c80a3fdf55 100644 --- a/packages/SystemUI/res/values-eu/strings.xml +++ b/packages/SystemUI/res/values-eu/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Handiagotu pantaila betetzeko"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Luzatu pantaila betetzeko"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Pantaila-argazkia"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desblokeatu telefonoa aukera gehiago ikusteko"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desblokeatu tableta aukera gehiago ikusteko"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desblokeatu gailua aukera gehiago ikusteko"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"erabiltzaileak irudi bat bidali du"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Pantaila-argazkia gordetzen…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Pantaila-argazkia gordetzen…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Kokapena GPS bidez ezarri da"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aplikazioen kokapen-eskaerak aktibo daude"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Aktibo dago sentsore guztiak desaktibatzen dituen aukera"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Multimedia-edukia aktibo dago"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Garbitu jakinarazpen guztiak."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Kudeatu"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Jasotako azkenak"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Isila"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Jakinarazpenak"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Elkarrizketak"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Garbitu soinurik gabeko jakinarazpen guztiak"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ez molestatzeko moduak pausatu egin ditu jakinarazpenak"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desaktibatu jakinarazpenak"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Aplikazio honen jakinarazpenak erakusten jarraitzea nahi duzu?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Isila"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Balio lehenetsia"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Burbuila"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ez du jotzen tonua edo egiten dar-dar"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ez du jotzen tonua edo egiten dar-dar, eta elkarrizketaren atalaren behealdean agertzen da"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Tonua jo edo dar-dar egin dezake, telefonoaren ezarpenen arabera"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Tonua jo edo dar-dar egin dezake, telefonoaren ezarpenen arabera. Modu lehenetsian, <xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko elkarrizketak burbuila gisa agertzen dira."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Eduki honetarako lasterbide gainerakor bat eskaintzen dizu, arretarik gal ez dezazun."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Burbuila gisa agertzen da elkarrizketen atalaren goialdean, eta profileko argazkia bistaratzen du pantaila blokeatuta dagoenean"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ezarpenak"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Lehentasuna"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioak ez du onartzen elkarrizketen berariazko ezarpenik"</string> diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml index 42c4e2f5c545..7c37f6662b9d 100644 --- a/packages/SystemUI/res/values-fa/strings.xml +++ b/packages/SystemUI/res/values-fa/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"بزرگنمایی برای پر کردن صفحه"</string> <string name="compat_mode_off" msgid="7682459748279487945">"گسترده کردن برای پر کردن صفحه"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"نماگرفت"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"برای گزینههای بیشتر، قفل تلفن را باز کنید"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"برای گزینههای بیشتر، قفل رایانه لوحی را باز کنید"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"برای گزینههای بیشتر، قفل دستگاه را باز کنید"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"تصویری ارسال کرد"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"در حال ذخیره نماگرفت..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"درحال ذخیره نماگرفت…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"مکان تنظیم شده توسط GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"درخواستهای موقعیت مکانی فعال است"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"«حسگرها خاموش» فعال است"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"رسانه فعال است"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"پاک کردن تمام اعلانها"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"مدیریت"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"سابقه"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ورودی"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"بیصدا"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"اعلانها"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"مکالمهها"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"پاک کردن همه اعلانهای بیصدا"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"اعلانها توسط «مزاحم نشوید» موقتاً متوقف شدند"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"خاموش کردن اعلانها"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"نمایش اعلان از این برنامه ادامه یابد؟"</string> <string name="notification_silence_title" msgid="8608090968400832335">"بیصدا"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"پیشفرض"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"حباب"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"بدون صدا یا لرزش"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"بدون صدا و لرزش در پایین بخش مکالمه نشان داده میشود"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"بسته به تنظیمات ممکن است تلفن زنگ بزند یا لرزش داشته باشد"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"بسته به تنظیمات ممکن است تلفن زنگ بزند یا لرزش داشته باشد. مکالمههای <xliff:g id="APP_NAME">%1$s</xliff:g> بهطور پیشفرض در حبابک نشان داده میشوند."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"با میانبری شناور به این محتوا، توجهتان را جلب میکند."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"در بالای بخش مکالمه بهصورت حبابک شناور نشان داده میشود و تصویر نمایه را در صفحه قفل نمایش میدهد"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"تنظیمات"</string> <string name="notification_priority_title" msgid="2079708866333537093">"اولویت"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> از تنظیمات خاص مکالمه پشتیبانی نمیکند"</string> diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml index c2a70f9f55df..6333fc509593 100644 --- a/packages/SystemUI/res/values-fi/strings.xml +++ b/packages/SystemUI/res/values-fi/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomaa koko näyttöön"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Venytä koko näyttöön"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Kuvakaappaus"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Avaa puhelimen lukitus, niin näet enemmän vaihtoehtoja"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Avaa tabletin lukitus, niin näet enemmän vaihtoehtoja"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Avaa laitteen lukitus, niin näet enemmän vaihtoehtoja"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"lähetti kuvan"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Tallennetaan kuvakaappausta..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Tallennetaan kuvakaappausta..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Sijainti määritetty GPS:n avulla"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Sijaintipyynnöt aktiiviset"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Anturit pois päältä aktiivinen"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media on aktiivinen"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Tyhjennä kaikki ilmoitukset."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Muuta asetuksia"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Saapuvat"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Äänetön"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ilmoitukset"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Keskustelut"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Tyhjennä kaikki hiljaiset ilmoitukset"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Älä häiritse ‑tila keskeytti ilmoitukset"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Poista ilmoitukset käytöstä"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Jatketaanko ilmoitusten näyttämistä tästä sovelluksesta?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Äänetön"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Oletus"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Kupla"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ei ääntä tai värinää"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ei ääntä tai värinää ja näkyy alempana keskusteluosiossa"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Voi soida tai väristä puhelimen asetuksista riippuen"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Voi soida tai väristä puhelimen asetuksista riippuen. Näistä keskusteluista (<xliff:g id="APP_NAME">%1$s</xliff:g>) syntyy oletuksena kuplia."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Kelluva sisällön pikakuvake säilyttää huomiosi"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Näkyy keskusteluosion yläosassa kelluvana kuplana, profiilikuva näkyy lukitusnäytöllä"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Asetukset"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Tärkeä"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ei tue keskustelukohtaisia asetuksia"</string> diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml index 47a84505fbe1..c03a68015b61 100644 --- a/packages/SystemUI/res/values-fr-rCA/strings.xml +++ b/packages/SystemUI/res/values-fr-rCA/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour afficher davantage d\'options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour afficher davantage d\'options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour afficher davantage d\'options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Position définie par GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Demandes de localisation actives"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option « Capteurs désactivés » active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"L\'élément multimédia est actif"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Mode silencieux"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Les notifications sont suspendues par le mode Ne pas déranger"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Désactiver les notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuer à afficher les notifications de cette application?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Mode silencieux"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bulle"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, et s\'affiche plus bas dans la section des conversations"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Peut sonner ou vibrer, selon les paramètres du téléphone"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Peut sonner ou vibrer, selon les paramètres du téléphone. Conversations des bulles de <xliff:g id="APP_NAME">%1$s</xliff:g> par défaut."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Garde votre attention à l\'aide d\'un raccourci flottant vers ce contenu."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations sous forme de bulle flottante et affiche la photo du profil sur l\'écran de verrouillage"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorité"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne prend pas en charge les paramètres propres aux conversations"</string> diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml index 577d2eada17a..33754c4a50df 100644 --- a/packages/SystemUI/res/values-fr/strings.xml +++ b/packages/SystemUI/res/values-fr/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Déverrouillez votre téléphone pour obtenir plus d\'options"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Déverrouillez votre tablette pour obtenir plus d\'options"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Déverrouillez votre appareil pour obtenir plus d\'options"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement de la capture d\'écran…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Position définie par GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Demandes de localisation actives"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Option \"Capteurs désactivés\" active"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Des contenus multimédias sont actifs"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Supprimer toutes les notifications"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> autres"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gérer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historique"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Notifications entrantes"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencieuses"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifications"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversations"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Effacer toutes les notifications silencieuses"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifications suspendues par le mode Ne pas déranger"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Désactiver les notifications"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuer d\'afficher les notifications de cette application ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencieux"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Par défaut"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bulle"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Aucun son ni vibration"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Aucun son ni vibration, s\'affiche plus bas dans la section des conversations"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Peut sonner ou vibrer en fonction des paramètres du téléphone"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Peut sonner ou vibrer en fonction des paramètres du téléphone. Les conversations provenant de <xliff:g id="APP_NAME">%1$s</xliff:g> s\'affichent sous forme de bulles par défaut."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Attire votre attention à l\'aide d\'un raccourci flottant vers ce contenu."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"S\'affiche en haut de la section des conversations, apparaît sous forme de bulle flottante, affiche la photo de profil sur l\'écran de verrouillage"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Paramètres"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritaire"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> n\'est pas compatible avec les paramètres de conversation"</string> diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml index 15740b3dba5b..c8081259e47e 100644 --- a/packages/SystemUI/res/values-gl/strings.xml +++ b/packages/SystemUI/res/values-gl/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ampliar ata ocupar todo"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estirar ata ocupar todo"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Facer captura"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloquea o teléfono para ver máis opcións"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloquea a tableta para ver máis opcións"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloquea o dispositivo para ver máis opcións"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou unha imaxe"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Gardando captura de pantalla…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Gardando captura de pantalla…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Localización establecida polo GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitudes de localización activas"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opción Desactivar sensores está activada"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"A reprodución multimedia está activa"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Eliminar todas as notificacións."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> máis"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Xestionar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historial"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Entrantes"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencio"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificacións"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Borra todas as notificacións silenciadas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"O modo Non molestar puxo en pausa as notificacións"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desactivar notificacións"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Queres seguir mostrando as notificacións desta aplicación?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silenciosas"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Configuración predeterminada"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Burbulla"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sen son nin vibración"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Non soa nin vibra, e aparece máis abaixo na sección de conversas"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Podería soar ou vibrar en función da configuración do teléfono"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Podería soar ou vibrar en función da configuración do teléfono. Conversas desde a burbulla da aplicación <xliff:g id="APP_NAME">%1$s</xliff:g> de forma predeterminada."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantén a túa atención cun atallo flotante a este contido."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Móstrase na parte superior da sección de conversas en forma de burbulla flotante e aparece a imaxe do perfil na pantalla de bloqueo"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configuración"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non admite opcións de configuración específicas para conversas"</string> diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml index 28088ff41a59..915547c09c84 100644 --- a/packages/SystemUI/res/values-hi/strings.xml +++ b/packages/SystemUI/res/values-hi/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरने के लिए ज़ूम करें"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरने के लिए खींचें"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ज़्यादा विकल्प देखने के लिए, अपना फ़ोन अनलॉक करें"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ज़्यादा विकल्प देखने के लिए, अपना टैबलेट अनलॉक करें"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ज़्यादा विकल्प देखने के लिए, अपना डिवाइस अनलॉक करें"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"एक इमेज भेजी गई"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सहेजा जा रहा है..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सहेजा जा रहा है..."</string> @@ -331,8 +328,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"जीपीएस ने यह जगह सेट की है"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"जगह का अनुरोध किया जा रहा है"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"सेंसर बंद हैं"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"मीडिया चल रहा है"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"सभी सूचनाएं साफ़ करें."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -521,10 +517,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"प्रबंधित करें"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"हाल ही में मिली सूचनाएं"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"बिना आवाज़ किए मिलने वाली सूचनाएं"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"वाइब्रेशन या आवाज़ के साथ मिलने वाली सूचनाएं"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"बिना आवाज़ की सभी सूचनाएं हटाएं"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'परेशान न करें\' सुविधा के ज़रिए कुछ समय के लिए सूचनाएं दिखाना रोक दिया गया है"</string> @@ -719,20 +713,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"सूचनाएं बंद करें"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"इस ऐप्लिकेशन से जुड़ी सूचनाएं दिखाना जारी रखें?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"आवाज़ के बिना सूचनाएं दिखाएं"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"डिफ़ॉल्ट"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"किसी तरह की आवाज़ या वाइब्रेशन न हो"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"इससे किसी तरह की आवाज़ या वाइब्रेशन नहीं होता और बातचीत, सेक्शन में सबसे नीचे दिखती है"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"फ़ोन की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फ़ोन की सेटिंग के आधार पर, सूचना आने पर घंटी बज सकती है या वाइब्रेशन हो सकता है. <xliff:g id="APP_NAME">%1$s</xliff:g> में होने वाली बातचीत, डिफ़ॉल्ट रूप से बबल के तौर पर दिखती हैं."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"फ़्लोट करने वाले शॉर्टकट की मदद से इस सामग्री पर आपका ध्यान बना रहता है."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"इससे बातचीत, सेक्शन में सबसे ऊपर और फ़्लोटिंग बबल के तौर पर दिखती है. साथ ही, लॉक स्क्रीन पर प्रोफ़ाइल फ़ोटो दिखती है"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> में हर बातचीत के लिए अलग सेटिंग तय नहीं की जा सकती"</string> diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml index a9d4b94fc292..84be202630a4 100644 --- a/packages/SystemUI/res/values-hr/strings.xml +++ b/packages/SystemUI/res/values-hr/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zumiraj i ispuni zaslon"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rastegni i ispuni zaslon"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snimka zaslona"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za više opcija otključajte telefon"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za više opcija otključajte tablet"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za više opcija otključajte uređaj"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"šalje sliku"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Spremanje snimke zaslona..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Spremanje snimke zaslona..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokaciju utvrdio GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Zahtjevi za lokaciju aktivni su"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Senzori isključeni aktivno"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Mediji su aktivni"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Brisanje svih obavijesti."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"još <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljajte"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Povijest"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dolazno"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Bešumno"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obavijesti"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Razgovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Izbriši sve bešumne obavijesti"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Značajka Ne uznemiravaj pauzirala je Obavijesti"</string> @@ -720,20 +714,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Isključi obavijesti"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite li da se obavijesti te aplikacije nastave prikazivati?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Bešumno"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Zadano"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Oblačić"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Bez zvuka ili vibracije"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Bez zvuka ili vibracije i prikazuje se pri dnu odjeljka razgovora"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Možda će zvoniti ili vibrirati, ovisno o postavkama telefona"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Možda će zvoniti ili vibrirati, ovisno o postavkama telefona. Razgovori iz aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g> prikazuju se u oblačiću prema zadanim postavkama."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Održava vam pozornost pomoću plutajućeg prečaca ovom sadržaju."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikazuje se pri vrhu odjeljka razgovora kao pomični oblačić i prikazuje profilnu sliku na zaključanom zaslonu"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Postavke"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ne podržava postavke koje se odnose na razgovor"</string> diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml index d0ae04bcbe9a..07b1b1ce4442 100644 --- a/packages/SystemUI/res/values-hu/strings.xml +++ b/packages/SystemUI/res/values-hu/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Nagyítás a kitöltéshez"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Nyújtás kitöltéshez"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Képernyőkép"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"További lehetőségekért oldja fel a telefont"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"További lehetőségekért oldja fel a táblagépet"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"További lehetőségekért oldja fel az eszközt"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"képet küldött"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Képernyőkép mentése..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Képernyőkép mentése..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"A GPS beállította a helyet"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktív helylekérések"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Az Érzékelők kikapcsolva kártya aktív"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Médialejátszás folyamatban"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Minden értesítés törlése"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Kezelés"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Előzmények"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Bejövő"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Néma"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Értesítések"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Beszélgetések"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Az összes néma értesítés törlése"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ne zavarjanak funkcióval szüneteltetett értesítések"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Az értesítések kikapcsolása"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Továbbra is megjelenjenek az alkalmazás értesítései?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Néma"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Alapértelmezett"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Buborék"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Nincs hang és rezgés"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nincs hang és rezgés, továbbá lejjebb jelenik meg a beszélgetések szakaszában"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"A telefonbeállítások alapján csöröghet és rezeghet"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"A telefonbeállítások alapján csöröghet és rezeghet. A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazásban lévő beszélgetések alapértelmezés szerint buborékban jelennek meg."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"A tartalomra mutató lebegő parancsikon segítségével tartja fenn az Ön figyelmét."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"A beszélgetések szakaszának tetején, lebegő buborékként látható, megjeleníti a profilképet a lezárási képernyőn"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Beállítások"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritás"</string> <string name="no_shortcut" msgid="7176375126961212514">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás nem támogatja a beszélgetésspecifikus beállításokat"</string> diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml index e42481a3b224..bf1322a15eb2 100644 --- a/packages/SystemUI/res/values-hy/strings.xml +++ b/packages/SystemUI/res/values-hy/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Խոշորացնել` էկրանը լցնելու համար"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ձգել` էկրանը լցնելու համար"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Սքրինշոթ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ապակողպեք ձեր հեռախոսը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ապակողպեք ձեր պլանշետը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ապակողպեք ձեր սարքը՝ լրացուցիչ կարգավորումները տեսնելու համար"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"պատկեր է ուղարկվել"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Սքրինշոթը պահվում է…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Սքրինշոթը պահվում է..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Տեղադրությունը կարգավորվել է GPS-ի կողմից"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Տեղադրության հարցումներն ակտիվ են"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Տվիչներն անջատված են"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Մեդիաֆայլը նվագարկվում է"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Մաքրել բոլոր ծանուցումները:"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Կառավարել"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Պատմություն"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Մուտքային"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Անձայն"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Ծանուցումներ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Խոսակցություններ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ջնջել բոլոր անձայն ծանուցումները"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Ծանուցումները չեն ցուցադրվի «Չանհանգստացնել» ռեժիմում"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Անջատել ծանուցումները"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Ցուցադրե՞լ ծանուցումներ այս հավելվածից։"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Անձայն"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Կանխադրված"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Պղպջակ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Առանց ձայնի կամ թրթռոցի"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Հայտնվում է զրույցների ցանկի ներքևում, առանց ձայնի և թրթռոցի"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Կարող է զնգալ կամ թրթռալ (հեռախոսի կարգավորումներից կախված)"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Կարող է զնգալ կամ թրթռալ (հեռախոսի կարգավորումներից կախված)։ <xliff:g id="APP_NAME">%1$s</xliff:g>-ի զրույցներն ըստ կանխադրման հայտնվում են ամպիկների տեսքով։"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Լողացող դյուրանցման միջոցով ձեր ուշադրությունն է գրավում բովանդակության նկատմամբ"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ցուցադրվում է զրույցների ցանկի վերևում, հայտնվում է լողացող ամպիկի տեսքով, ցուցադրում է պրոֆիլի նկարը կողպէկրանին"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Կարգավորումներ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Կարևոր"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը չի աջակցում զրույցի կարգավորումները"</string> diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml index fdf7e3d2e590..14dd5216c4a9 100644 --- a/packages/SystemUI/res/values-in/strings.xml +++ b/packages/SystemUI/res/values-in/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Perbesar utk mengisi layar"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rentangkn utk mngisi layar"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci ponsel untuk melihat opsi lainnya"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet untuk opsi lainnya"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci perangkat untuk melihat opsi lainnya"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"mengirim gambar"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan screenshot..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan screenshot..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokasi yang disetel oleh GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Permintaan lokasi aktif"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensor nonaktif diaktifkan"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media aktif"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Menghapus semua pemberitahuan."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Kelola"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histori"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Senyap"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifikasi"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Percakapan"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hapus semua notifikasi senyap"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifikasi dijeda oleh mode Jangan Ganggu"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Nonaktifkan notifikasi"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Terus tampilkan notifikasi dari aplikasi ini?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Senyap"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Balon"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Tidak ada suara atau getaran"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tidak ada suara atau getaran dan ditampilkan lebih rendah di bagian percakapan"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Dapat berdering atau bergetar berdasarkan setelan ponsel"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Dapat berdering atau bergetar berdasarkan setelan ponsel. Percakapan dari balon <xliff:g id="APP_NAME">%1$s</xliff:g> secara default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Menjaga perhatian dengan pintasan floating ke konten ini."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Muncul di atas bagian percakapan, ditampilkan sebagai balon yang mengambang, menampilkan gambar profil di layar kunci"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setelan"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritas"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak mendukung setelan khusus percakapan"</string> diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml index 7e4f1b7f2f89..a572634d4104 100644 --- a/packages/SystemUI/res/values-is/strings.xml +++ b/packages/SystemUI/res/values-is/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Fylla skjá með aðdrætti"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Teygja yfir allan skjáinn"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skjámynd"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Taktu símann úr lás til að fá fleiri valkosti"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Taktu spjaldtölvuna úr lás til að fá fleiri valkosti"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Taktu tækið úr lás til að fá fleiri valkosti"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"sendi mynd"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Vistar skjámynd…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Vistar skjámynd…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Staðsetning valin með GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Staðsetningarbeiðnir virkar"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Slökkt á skynjurum valið"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Efni er virkt"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Hreinsa allar tilkynningar."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Stjórna"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Ferill"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Mótteknar"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Hljóðlaust"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Tilkynningar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtöl"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Hreinsa allar þöglar tilkynningar"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Hlé gert á tilkynningum þar sem stillt er á „Ónáðið ekki“"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Slökkva á tilkynningum"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Sýna áfram tilkynningar frá þessu forriti?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Hljóðlaust"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Sjálfgefið"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Blaðra"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ekkert hljóð eða titringur"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ekkert hljóð eða titringur og birtist neðar í samtalshluta"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Gæti hringt eða titrað eftir stillingum símans"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Gæti hringt eða titrað eftir stillingum símans. Samtöl á <xliff:g id="APP_NAME">%1$s</xliff:g> birtast sjálfkrafa í blöðru."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Fangar athygli þína með fljótandi flýtileið á þetta efni."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Birtist efst í samtalshluta, birtist sem fljótandi blaðra, birtir prófílmynd á lásskjánum"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Áfram"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Forgangur"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> styður ekki stillingar fyrir einstök samtöl"</string> diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml index 167a2c962055..3beed3a0e3fe 100644 --- a/packages/SystemUI/res/values-it/strings.xml +++ b/packages/SystemUI/res/values-it/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom per riempire schermo"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Estendi per riemp. schermo"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Sblocca il telefono per visualizzare altre opzioni"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Sblocca il tablet per visualizzare altre opzioni"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Sblocca il dispositivo per visualizzare altre opzioni"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"è stata inviata un\'immagine"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvataggio screenshot..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvataggio screenshot..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Posizione stabilita dal GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Richieste di accesso alla posizione attive"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Opzione Sensori disattivati attiva"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Contenuti multimediali attivi"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Cancella tutte le notifiche."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gestisci"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Cronologia"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"In arrivo"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenziose"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notifiche"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversazioni"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Cancella tutte le notifiche silenziose"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notifiche messe in pausa in base alla modalità Non disturbare"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Disattiva notifiche"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuare a ricevere notifiche da questa app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Modalità silenziosa"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Livello predefinito"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Fumetto"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Nessun suono o vibrazione"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nessun suono o vibrazione e appare più in basso nella sezione delle conversazioni"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del telefono"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Potrebbero essere attivati lo squillo o la vibrazione in base alle impostazioni del telefono. Conversazioni dalla bolla <xliff:g id="APP_NAME">%1$s</xliff:g> per impostazione predefinita."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantiene la tua attenzione con una scorciatoia mobile a questi contenuti."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Viene mostrata in cima alla sezione delle conversazioni, appare sotto forma di bolla mobile, mostra l\'immagine del profilo nella schermata di blocco"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Impostazioni"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorità"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> non supporta impostazioni specifiche per le conversazioni"</string> diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml index 4730334fe117..705f7769f89f 100644 --- a/packages/SystemUI/res/values-iw/strings.xml +++ b/packages/SystemUI/res/values-iw/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"הגדל תצוגה כדי למלא את המסך"</string> <string name="compat_mode_off" msgid="7682459748279487945">"מתח כדי למלא את המסך"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"לאפשרויות נוספות, יש לבטל את נעילת הטלפון"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"לאפשרויות נוספות, יש לבטל את נעילת הטאבלט"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"לאפשרויות נוספות, יש לבטל את נעילת המכשיר"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"שומר צילום מסך..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"שומר צילום מסך..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"מיקום מוגדר על ידי GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"בקשות מיקום פעילות"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ההגדרה \'חיישנים כבויים\' פעילה"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"המדיה פעילה"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"הסרת כל ההתראות."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"ניהול"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"היסטוריה"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"התקבלו"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"שקט"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"התראות"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"שיחות"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ניקוי כל ההתראות השקטות"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"התראות הושהו על ידי מצב \'נא לא להפריע\'"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"השבתת ההתראות"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"שנמשיך להציג לך התראות מהאפליקציה הזאת?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"שקט"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ברירת מחדל"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"בועה"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ללא צליל או רטט"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ללא צליל או רטט ומופיעה למטה בקטע התראות השיחה"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות הטלפון"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ייתכן שיופעל צלצול או רטט בהתאם להגדרות הטלפון. שיחות מהאפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> מופיעות בבועות כברירת מחדל."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"מעוררת תשומת לב באמצעות קיצור דרך צף לתוכן הזה."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"מוצגת בחלק העליון של קטע התראות השיחה, מופיעה בבועה צפה, תוצג תמונת פרופיל במסך הנעילה"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"הגדרות"</string> <string name="notification_priority_title" msgid="2079708866333537093">"עדיפות"</string> <string name="no_shortcut" msgid="7176375126961212514">"האפליקציה <xliff:g id="APP_NAME">%1$s</xliff:g> לא תומכת בהגדרות ספציפיות לשיחות"</string> diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml index 0631005916f4..c1aaebe4452d 100644 --- a/packages/SystemUI/res/values-ja/strings.xml +++ b/packages/SystemUI/res/values-ja/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"画面サイズに合わせて拡大"</string> <string name="compat_mode_off" msgid="7682459748279487945">"画面サイズに合わせて拡大"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"スクリーンショット"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"スマートフォンのロックを解除してその他のオプションを表示する"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"タブレットのロックを解除してその他のオプションを表示する"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"デバイスのロックを解除してその他のオプションを表示する"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"画像を送信しました"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"スクリーンショットを保存中..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"スクリーンショットを保存しています..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPSにより現在地が設定されました"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"現在地リクエストがアクティブ"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"センサー OFF: 有効"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"メディアは有効です"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"通知をすべて消去。"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"他 <xliff:g id="NUMBER">%s</xliff:g> 件"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"履歴"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"新着"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"サイレント"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"会話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"サイレント通知がすべて消去されます"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"サイレント モードにより通知は一時停止中です"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"通知を OFF にする"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"このアプリからの通知を今後も表示しますか?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"サイレント"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"デフォルト"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"バブル"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"着信音もバイブレーションも無効です"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"着信音もバイブレーションも無効になり会話セクションの下に表示されます"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"スマートフォンの設定を基に着信音またはバイブレーションが有効になります"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"スマートフォンの設定を基に着信音またはバイブレーションが有効になります。デフォルトでは <xliff:g id="APP_NAME">%1$s</xliff:g> からの会話がふきだしで表示されます。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"このコンテンツのフローティング ショートカットで通知をお知らせします。"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"会話セクションの一番上にふきだしとして表示され、プロフィール写真がロック画面に表示されます"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先度"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> は会話専用の設定をサポートしていません"</string> diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml index 8390853e6695..e70642a1c648 100644 --- a/packages/SystemUI/res/values-ka/strings.xml +++ b/packages/SystemUI/res/values-ka/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"მასშტაბი შეცვალეთ ეკრანის შესავსებად."</string> <string name="compat_mode_off" msgid="7682459748279487945">"გაწიეთ ეკრანის შესავსებად."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ეკრანის ანაბეჭდი"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტელეფონი"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი ტაბლეტი"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"მეტი ვარიანტის სანახავად განბლოკეთ თქვენი მოწყობილობა"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"გაიგზავნა სურათი"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"სკრინშოტის შენახვა…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ეკრანის სურათის შენახვა…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS-ით დადგენილი მდებარეობა"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"მდებარეობის მოთხოვნები აქტიურია"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"სენსორების გამორთვა აქტიურია"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"მედია აქტიურია"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ყველა შეტყობინების წაშლა"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"მართვა"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ისტორია"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"შემომავალი"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ჩუმი"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"შეტყობინებები"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"საუბრები"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ყველა ჩუმი შეტყობინების გასუფთავება"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"შეტყობინებები დაპაუზდა „არ შემაწუხოთ“ რეჟიმის მეშვეობით"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"შეტყობინებების გამორთვა"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"გაგრძელდეს შეტყობინებათა ჩვენება ამ აპიდან?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ჩუმი"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ნაგულისხმევი"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ბუშტი"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ხმისა და ვიბრაციის გარეშე"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ხმისა და ვიბრაციის გარეშე, ჩნდება მიმოწერების სექციის ქვედა ნაწილში"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"დარეკვა ან ვიბრაცია ტელეფონის პარამეტრების მიხედვით"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"დარეკვა ან ვიბრაცია ტელეფონის პარამეტრების მიხედვით. მიმოწერები <xliff:g id="APP_NAME">%1$s</xliff:g>-ის ბუშტიდან, ნაგულისხმევად."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"იპყრობს თქვენს ყურადღებას ამ კონტენტის მოლივლივე მალსახმობით."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"გამოჩნდება მიმოწერების სექციის ზედა ნაწილში მოლივლივე ბუშტის სახით, აჩვენებს პროფილის სურათს ჩაკეტილ ეკრანზე"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"პარამეტრები"</string> <string name="notification_priority_title" msgid="2079708866333537093">"პრიორიტეტი"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ს არ აქვს სპეციალურად მიმოწერისთვის განკუთვნილი პარამეტრების მხარდაჭერა"</string> diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml index 7045c34fe4ea..a2e19f831664 100644 --- a/packages/SystemUI/res/values-kk/strings.xml +++ b/packages/SystemUI/res/values-kk/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Экранды толтыру үшін ұлғайту"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтыру үшін созу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Басқа опцияларды көру үшін телефон құлпын ашыңыз."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Басқа опцияларды көру үшін планшет құлпын ашыңыз."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Басқа опцияларды көру үшін құрылғы құлпын ашыңыз."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сурет жіберілді"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншотты сақтауда…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншотты сақтауда…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Орын GPS арқылы орнатылған"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Орын өтініштері қосылған"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Датчиктер өшірулі."</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Медиамазмұн ойнатылып жатыр."</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Барлық хабарларды жойыңыз."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Басқару"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Тарих"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кіріс"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Үнсіз"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Хабарландырулар"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Әңгімелер"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Барлық дыбыссыз хабарландыруларды өшіру"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Хабарландырулар \"Мазаламау\" режимінде кідіртілді"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Хабарландыруларды өшіру"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Осы қолданбаның хабарландырулары көрсетілсін бе?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Дыбыссыз"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Әдепкі"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Көпіршік"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Дыбыс не діріл қолданылмайды"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дыбыс не діріл қолданылмайды, төменде әңгімелер бөлімінде шығады"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Телефон параметрлеріне байланысты шылдырлауы не дірілдеуі мүмкін"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефон параметрлеріне байланысты шылдырлауы не дірілдеуі мүмкін. <xliff:g id="APP_NAME">%1$s</xliff:g> чаттары әдепкісінше қалқымалы етіп көрсетіледі."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Осы мазмұнға бекітілген қалқымалы таңбашамен назарыңызды өзіне тартады."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Әңгімелер бөлімінің жоғарғы жағында тұрады, қалқыма хабар түрінде шығады, құлыптаулы экранда профиль суретін көрсетеді"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Параметрлер"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Маңыздылығы"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасында чаттың арнайы параметрлеріне қолдау көрсетілмейді."</string> diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml index 82a9b33d185a..e874df25b61d 100644 --- a/packages/SystemUI/res/values-km/strings.xml +++ b/packages/SystemUI/res/values-km/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ពង្រីកដើម្បីឲ្យពេញអេក្រង់"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ទាញដើម្បីឲ្យពេញអេក្រង់"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"រូបថតអេក្រង់"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ដោះសោទូរសព្ទរបស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ដោះសោថេប្លេតរបស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ដោះសោឧបករណ៍របស់អ្នកសម្រាប់ជម្រើសច្រើនទៀត"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"បានផ្ញើរូបភាព"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"កំពុងរក្សាទុករូបថតអេក្រង់…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"កំពុងរក្សាទុករូបថតអេក្រង់..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"ទីតាំងកំណត់ដោយ GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"សំណើទីតាំងសកម្ម"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ឧបករណ៍ចាប់សញ្ញាបានបិទ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"មេឌៀកំពុងដំណើរការ"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"សម្អាតការជូនដំណឹងទាំងអស់។"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"គ្រប់គ្រង"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ប្រវត្តិ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"មកដល់"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ស្ងាត់"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"ការជូនដំណឹង"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ការសន្ទនា"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"សម្អាតការជូនដំណឹងស្ងាត់ទាំងអស់"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ការជូនដំណឹងបានផ្អាកដោយមុខងារកុំរំខាន"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"បិទការជូនដំណឹង"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"បន្តបង្ហាញការជូនដំណឹងពីកម្មវិធីនេះ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ស្ងាត់"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"លំនាំដើម"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ពពុះ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"គ្មានសំឡេង ឬការញ័រទេ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"គ្មានសំឡេង ឬការញ័រ និងការបង្ហាញកម្រិតទាបជាងនេះនៅក្នុងផ្នែកសន្ទនាទេ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ទូរសព្ទ"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"អាចរោទ៍ ឬញ័រ ដោយផ្អែកលើការកំណត់ទូរសព្ទ។ ការសន្ទនាពីពពុះ <xliff:g id="APP_NAME">%1$s</xliff:g> តាមលំនាំដើម។"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ធ្វើឱ្យអ្នកចាប់អារម្មណ៍ដោយប្រើផ្លូវកាត់អណ្ដែតសម្រាប់ខ្លឹមសារនេះ។"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"បង្ហាញនៅខាងលើផ្នែកសន្ទនា បង្ហាញជាពពុះអណ្ដែត បង្ហាញរូបភាពកម្រងព័ត៌មាននៅលើអេក្រង់ចាក់សោ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ការកំណត់"</string> <string name="notification_priority_title" msgid="2079708866333537093">"អាទិភាព"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> មិនអាចប្រើការកំណត់ជាក់លាក់ចំពោះការសន្ទនាបានទេ"</string> diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml index 3c0c09183267..750d161aa581 100644 --- a/packages/SystemUI/res/values-kn/strings.xml +++ b/packages/SystemUI/res/values-kn/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಫೋನ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಟ್ಯಾಬ್ಲೆಟ್ ಅನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ಹೆಚ್ಚಿನ ಆಯ್ಕೆಗಳಿಗಾಗಿ ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"ಸ್ಥಾನವನ್ನು GPS ಮೂಲಕ ಹೊಂದಿಸಲಾಗಿದೆ"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"ಸ್ಥಳ ವಿನಂತಿಗಳು ಸಕ್ರಿಯವಾಗಿವೆ"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ಸೆನ್ಸರ್ಗಳು ಆಫ್ ಆಗಿವೆ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"ಮೀಡಿಯಾ ಸಕ್ರಿಯವಾಗಿದೆ"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ಎಲ್ಲಾ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸು."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"ನಿರ್ವಹಿಸಿ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ಇತಿಹಾಸ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ಒಳಬರುವ"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ನಿಶ್ಶಬ್ದ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"ಅಧಿಸೂಚನೆಗಳು"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ಸಂಭಾಷಣೆಗಳು"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ಎಲ್ಲಾ ನಿಶ್ಶಬ್ಧ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೆರವುಗೊಳಿಸಿ"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ಅಡಚಣೆ ಮಾಡಬೇಡಿ ಎನ್ನುವ ಮೂಲಕ ಅಧಿಸೂಚನೆಗಳನ್ನು ವಿರಾಮಗೊಳಿಸಲಾಗಿದೆ"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"ಅಧಿಸೂಚನೆಗಳನ್ನು ಆಫ್ ಮಾಡಿ"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ಈ ಅಪ್ಲಿಕೇಶನ್ನಿಂದ ಅಧಿಸೂಚನೆಗಳನ್ನು ತೋರಿಸುತ್ತಲೇ ಇರಬೇಕೆ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ನಿಶ್ಶಬ್ದ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ಡೀಫಾಲ್ಟ್"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ಬಬಲ್"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್ ಆಗುವುದಿಲ್ಲ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ಯಾವುದೇ ಧ್ವನಿ ಅಥವಾ ವೈಬ್ರೇಷನ್ ಆಗುವುದಿಲ್ಲ, ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಕೆಳಭಾಗದಲ್ಲಿ ಗೋಚರಿಸುತ್ತದೆ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಆಧರಿಸಿ ಫೋನ್ ರಿಂಗ್ ಅಥವಾ ವೈಬ್ರೇಟ್ ಆಗುತ್ತದೆ. ಡಿಫಾಲ್ಟ್ ಆಗಿ, <xliff:g id="APP_NAME">%1$s</xliff:g> ನ ಬಬಲ್ ಸಂಭಾಷಣೆಗಳು."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ಈ ವಿಷಯಕ್ಕೆ ಲಿಂಕ್ ಮಾಡಿ ಕೊಂಡೊಯ್ಯುವ ಶಾರ್ಟ್ಕಟ್ ಕಡೆಗೆ ಗಮನ ಇರಿಸಿ."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"ಸಂಭಾಷಣೆ ವಿಭಾಗದ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೇಲುವ ಬಬಲ್ ಆಗಿ ಗೋಚರಿಸುತ್ತದೆ ಮತ್ತು ಪ್ರೊಫೈಲ್ ಚಿತ್ರವನ್ನು ಲಾಕ್ಸ್ಕ್ರೀನ್ ಮೇಲೆ ಗೋಚರಿಸುತ್ತದೆ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ಸೆಟ್ಟಿಂಗ್ಗಳು"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ಆದ್ಯತೆ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಸಂಭಾಷಣೆ ನಿರ್ದಿಷ್ಟ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಬೆಂಬಲಿಸುವುದಿಲ್ಲ"</string> diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml index 6ee038c0d6c9..6fa6e9e6be18 100644 --- a/packages/SystemUI/res/values-ko/strings.xml +++ b/packages/SystemUI/res/values-ko/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"전체화면 모드로 확대"</string> <string name="compat_mode_off" msgid="7682459748279487945">"전체화면 모드로 확대"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"스크린샷"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"더 많은 옵션을 확인하려면 휴대전화를 잠금 해제하세요."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"더 많은 옵션을 확인하려면 태블릿을 잠금 해제하세요."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"더 많은 옵션을 확인하려면 기기를 잠금 해제하세요."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"이미지 보냄"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"캡쳐화면 저장 중..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"캡쳐화면 저장 중..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS에서 위치 설정"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"위치 요청 있음"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"센서 끄기 활성화"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"미디어가 활성화되어 있음"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"모든 알림 지우기"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g>개 더보기"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"관리"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"기록"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"최근 알림"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"무음"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"알림"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"대화"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"무음 알림 모두 삭제"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"방해 금지 모드로 알림이 일시중지됨"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"알림 사용 중지"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"이 앱의 알림을 계속 표시하시겠습니까?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"무음"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"기본값"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"버블"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"소리 또는 진동 없음"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"소리나 진동이 울리지 않으며 대화 섹션 하단에 표시됨"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"휴대전화 설정에 따라 벨소리나 진동이 울릴 수 있음"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"휴대전화 설정에 따라 벨소리나 진동이 울릴 수 있습니다. 기본적으로 <xliff:g id="APP_NAME">%1$s</xliff:g>의 대화는 대화창으로 표시됩니다."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"이 콘텐츠로 연결되는 플로팅 바로가기로 사용자의 주의를 끕니다."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"대화 섹션 상단의 플로팅 대화창 또는 잠금 화면의 프로필 사진으로 표시됩니다."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"설정"</string> <string name="notification_priority_title" msgid="2079708866333537093">"우선순위"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>에서는 대화 관련 설정을 지원하지 않습니다."</string> diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml index 69d4c6834f7f..49f7c00e7b52 100644 --- a/packages/SystemUI/res/values-ky/strings.xml +++ b/packages/SystemUI/res/values-ky/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Экрнд тлтр ү. чен өлч өзг"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Экранды толтуруу ү-н чоюу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Дагы башка параметрлерди көрүү үчүн телефонуңуздун кулпусун ачыңыз"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Дагы башка параметрлерди көрүү үчүн планшетиңиздин кулпусун ачыңыз"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Дагы башка параметрлерди көрүү үчүн түзмөгүңүздүн кулпусун ачыңыз"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"сүрөт жөнөттү"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Скриншот сакталууда…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Скриншот сакталууда..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS боюнча аныкталган жайгашуу"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Жайгаштыруу талаптары иштелүүдө"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"\"Сенсорлорду өчүрүүнү\" активдештирүү"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Медиа ойнотулууда"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Бардык билдирмелерди өчүрүү."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Башкаруу"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Таржымал"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Кирүүчү"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Үнсүз"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Билдирмелер"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Жазышуулар"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бардык үнсүз билдирмелерди өчүрүү"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\"Тынчымды алба\" режиминде билдирмелер тындырылды"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Билдирмелерди өчүрүү"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Бул колдонмонун билдирмелери көрсөтүлө берсинби?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Үнсүз"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Демейки"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Көбүк"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Үнү чыкпайт жана дирилдебейт"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Үнү чыгып же дирилдебейт жана жазышуу бөлүмүнүн ылдый жагында көрүнөт"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Телефондун жөндөөлөрүнө жараша шыңгырап же дирилдеши мүмкүн. <xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосундагы жазышуулар демейки жөндөө боюнча калкып чыкма билдирмелер болуп көрүнөт."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Калкыма ыкчам баскыч менен көңүлүңүздү бул мазмунга буруп турат."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Жазышуу бөлүмүнүн жогорку жагында калкып чыкма билдирме түрүндө көрүнүп, профиль сүрөтү кулпуланган экрандан чагылдырылат"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Жөндөөлөр"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Маанилүүлүгү"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунда жазышууга болбойт"</string> diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml index 17f9184a4f66..6841a868066f 100644 --- a/packages/SystemUI/res/values-lo/strings.xml +++ b/packages/SystemUI/res/values-lo/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ຊູມໃຫ້ເຕັມໜ້າຈໍ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ປັບໃຫ້ເຕັມໜ້າຈໍ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ພາບໜ້າຈໍ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ປົດລັອກໂທລະສັບຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ປົດລັອກແທັບເລັດຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ປົດລັອກອຸປະກອນຂອງທ່ານເພື່ອໃຊ້ຕົວເລືອກເພີ່ມເຕີມ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ສົ່ງຮູບແລ້ວ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ກຳລັງບັນທຶກຮູບໜ້າຈໍ"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ກຳລັງບັນທຶກພາບໜ້າຈໍ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"ສະຖານທີ່ກຳນົດໂດຍ GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"ການຮ້ອງຂໍສະຖານທີ່ທີ່ເຮັດວຽກຢູ່"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"ປິດການເຮັດວຽກຂອງເຊັນເຊີແລ້ວ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"ເປີດໃຊ້ມີເດຍຢູ່"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ລຶບການແຈ້ງເຕືອນທັງໝົດ."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"ຈັດການ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ປະຫວັດ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ຂາເຂົ້າ"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ປິດສຽງ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"ການແຈ້ງເຕືອນ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ການສົນທະນາ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ລຶບລ້າງການແຈ້ງເຕືອນແບບງຽບທັງໝົດ"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"ຢຸດການແຈ້ງເຕືອນໂດຍໂໝດຫ້າມລົບກວນແລ້ວ"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"ປິດການແຈ້ງເຕືອນ"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ສະແດງການແຈ້ງເຕືອນຈາກແອັບນີ້ຕໍ່ໄປບໍ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ປິດສຽງ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ຄ່າເລີ່ມຕົ້ນ"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ຟອງ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ບໍ່ມີສຽງ ຫຼື ການສັ່ນເຕືອນ ແລະ ປາກົດຢູ່ທາງລຸ່ມຂອງພາກສ່ວນການສົນທະນາ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າໂທລະສັບ"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ອາດສົ່ງສຽງ ຫຼື ສັ່ນເຕືອນໂດຍອ້າງອີງຈາກການຕັ້ງຄ່າໂທລະສັບ. ການສົນທະນາຈາກ <xliff:g id="APP_NAME">%1$s</xliff:g> ຈະເປັນ bubble ຕາມຄ່າເລີ່ມຕົ້ນ."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ເອົາໃຈໃສ່ທາງລັດແບບລອຍໄປຫາເນື້ອຫານີ້."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"ສະແດງຢູ່ເທິງສຸດຂອງພາກສ່ວນການສົນທະນາ, ປາກົດເປັນ bubble ແບບລອຍ, ສະແດງຮູບໂປຣໄຟລ໌ຢູ່ໜ້າຈໍລັອກ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ຕັ້ງຄ່າ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ສຳຄັນ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ບໍ່ຮອງຮັບການຕັ້ງຄ່າສະເພາະຂອງການສົນທະນາ"</string> diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml index 5684b634b740..29a6ffdc5d61 100644 --- a/packages/SystemUI/res/values-lt/strings.xml +++ b/packages/SystemUI/res/values-lt/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Keisti mast., kad atit. ekr."</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ištempti, kad atit. ekr."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrano kopija"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atrakinkite telefoną, kad galėtumėte naudoti daugiau parinkčių"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atrakinkite planšetinį kompiuterį, kad galėtumėte naudoti daugiau parinkčių"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atrakinkite įrenginį, kad galėtumėte naudoti daugiau parinkčių"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"išsiuntė vaizdą"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Išsaugoma ekrano kopija..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Išsaugoma ekrano kopija..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS nustatyta vieta"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Vietovės užklausos aktyvios"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Parinktis „Jutikliai išjungti“ aktyvi"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Medija aktyvi"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Išvalyti visus pranešimus."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Dar <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Tvarkyti"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istorija"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gaunami"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tylūs"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pranešimai"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Pokalbiai"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Išvalyti visus tylius pranešimus"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pranešimai pristabdyti naudojant netrukdymo režimą"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Išjungti pranešimus"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Toliau rodyti iš šios programos gautus pranešimus?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Tylūs"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Numatytasis"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Debesėlis"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Neskamba ir nevibruoja"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Neskamba, nevibruoja ir rodoma apatinėje pokalbių skilties dalyje"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Gali skambėti arba vibruoti, atsižvelgiant į telefono nustatymus"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Gali skambėti arba vibruoti, atsižvelgiant į telefono nustatymus. Pokalbiai iš „<xliff:g id="APP_NAME">%1$s</xliff:g>“ debesėlio pagal numatytuosius nustatymus."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Naudojant slankųjį spartųjį klavišą lengviau sutelkti dėmesį į šį turinį."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Rodoma pokalbių skilties viršuje, rodoma kaip slankusis burbulas, pateikiama profilio nuotrauka užrakinimo ekrane"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nustatymai"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritetas"</string> <string name="no_shortcut" msgid="7176375126961212514">"Programa „<xliff:g id="APP_NAME">%1$s</xliff:g>“ nepalaiko konkrečių pokalbių nustatymų"</string> diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml index 873216e579a2..2804b6f050d2 100644 --- a/packages/SystemUI/res/values-lv/strings.xml +++ b/packages/SystemUI/res/values-lv/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Tālumm., lai aizp. ekr."</string> <string name="compat_mode_off" msgid="7682459748279487945">"Stiepiet, lai aizp. ekr."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekrānuzņēmums"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Atbloķējiet tālruni, lai skatītu citas opcijas."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Atbloķējiet planšetdatoru, lai skatītu citas opcijas."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Atbloķējiet ierīci, lai skatītu citas opcijas."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nosūtīts attēls"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Saglabā ekrānuzņēmumu…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Notiek ekrānuzņēmuma saglabāšana..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS iestatītā atrašanās vieta"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktīvi atrašanās vietu pieprasījumi"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Aktivizēts iestatījums “Sensori izslēgti”"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Tiek atskaņots multivides saturs"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Notīrīt visus paziņojumus"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"vēl <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Pārvaldīt"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Vēsture"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ienākošie"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Klusums"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Paziņojumi"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Sarunas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Notīrīt visus klusos paziņojumus"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Paziņojumi pārtraukti, izmantojot iestatījumu “Netraucēt”"</string> @@ -720,20 +714,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Izslēgt paziņojumus"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Vai turpināt rādīt paziņojumus no šīs lietotnes?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Klusums"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Noklusējums"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Burbulis"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Nav skaņas signāla vai vibrācijas"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Nav skaņas signāla vai vibrācijas, kā arī atrodas zemāk sarunu sadaļā"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Atkarībā no tālruņa iestatījumiem var zvanīt vai vibrēt"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Atkarībā no tālruņa iestatījumiem var zvanīt vai vibrēt. Sarunas no lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> pēc noklusējuma tiek parādītas burbulī."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Piesaista jūsu uzmanību, rādot peldošu saīsni uz šo saturu."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Parādās sarunu sadaļas augšdaļā un kā peldošs burbulis, kā arī bloķēšanas ekrānā tiek rādīts profila attēls"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Iestatījumi"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritārs"</string> <string name="no_shortcut" msgid="7176375126961212514">"Lietotnē <xliff:g id="APP_NAME">%1$s</xliff:g> netiek atbalstīti atsevišķu sarunu iestatījumi."</string> diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml index d7a8d1b47586..071b3d8ca04c 100644 --- a/packages/SystemUI/res/values-ml/strings.xml +++ b/packages/SystemUI/res/values-ml/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"സ്ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ സൂം ചെയ്യുക"</string> <string name="compat_mode_off" msgid="7682459748279487945">"സ്ക്രീനിൽ ഉൾക്കൊള്ളിക്കാൻ വലിച്ചുനീട്ടുക"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"സ്ക്രീൻഷോട്ട്"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഫോൺ അൺലോക്ക് ചെയ്യുക"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ടാബ്ലെറ്റ് അൺലോക്ക് ചെയ്യുക"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"കൂടുതൽ ഓപ്ഷനുകൾക്ക് നിങ്ങളുടെ ഉപകരണം അൺലോക്ക് ചെയ്യുക"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ചിത്രം അയച്ചു"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"സ്ക്രീൻഷോട്ട് സംരക്ഷിക്കുന്നു..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"ലൊക്കേഷൻ സജ്ജീകരിച്ചത് GPS ആണ്"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"ലൊക്കേഷൻ അഭ്യർത്ഥനകൾ സജീവമാണ്"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"സെൻസറുകൾ ഓഫ് സജീവമാണ്"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"മീഡിയ സജീവമാണ്"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"എല്ലാ വിവരങ്ങളും മായ്ക്കുക."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"മാനേജ് ചെയ്യുക"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ചരിത്രം"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ഇൻകമിംഗ്"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"നിശബ്ദം"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"അറിയിപ്പുകൾ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"സംഭാഷണങ്ങൾ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"എല്ലാ നിശബ്ദ അറിയിപ്പുകളും മായ്ക്കുക"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ശല്യപ്പെടുത്തരുത്\' വഴി അറിയിപ്പുകൾ താൽക്കാലികമായി നിർത്തി"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"അറിയിപ്പുകൾ ഓഫാക്കുക"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ഈ ആപ്പിൽ നിന്നുള്ള അറിയിപ്പുകൾ തുടർന്നും കാണിക്കണോ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"നിശബ്ദം"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ഡിഫോൾട്ട്"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ബബ്ൾ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ശബ്ദമോ വൈബ്രേഷനോ ഇല്ല, കൂടാതെ സംഭാഷണ വിഭാഗത്തിന് താഴെയായി ദൃശ്യമാകും"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ് ചെയ്തേക്കാം അല്ലെങ്കിൽ വൈബ്രേറ്റ് ചെയ്തേക്കാം"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ഫോൺ ക്രമീകരണം അടിസ്ഥാനമാക്കി റിംഗ് ചെയ്തേക്കാം അല്ലെങ്കിൽ വൈബ്രേറ്റ് ചെയ്തേക്കാം. <xliff:g id="APP_NAME">%1$s</xliff:g>-ൽ നിന്നുള്ള സംഭാഷണങ്ങൾ ഡിഫോൾട്ടായി ബബ്ൾ ആവുന്നു."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ഈ ഉള്ളടക്കത്തിലേക്ക് ഒരു ഫ്ലോട്ടിംഗ് കുറുക്കുവഴി ഉപയോഗിച്ച് നിങ്ങളുടെ ശ്രദ്ധ നിലനിർത്തുന്നു."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"സംഭാഷണ വിഭാഗത്തിന് മുകളിലായി കാണിക്കുന്നു, ഫ്ലോട്ടിംഗ് ബബിളായി ദൃശ്യമാകുന്നു, ലോക്ക് സ്ക്രീനിൽ പ്രൊഫൈൽ ചിത്രം പ്രദർശിപ്പിക്കുന്നു"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ക്രമീകരണം"</string> <string name="notification_priority_title" msgid="2079708866333537093">"മുൻഗണന"</string> <string name="no_shortcut" msgid="7176375126961212514">"സംഭാഷണ നിർദ്ദിഷ്ട ക്രമീകരണം <xliff:g id="APP_NAME">%1$s</xliff:g> പിന്തുണയ്ക്കുന്നില്ല"</string> diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml index 9f4be26d9dfb..fbb3b69945d4 100644 --- a/packages/SystemUI/res/values-mn/strings.xml +++ b/packages/SystemUI/res/values-mn/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Дэлгэц дүүргэх бол өсгөнө үү"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Дэлгэц дүүргэх бол татна уу"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Дэлгэцийн зураг дарах"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Бусад сонголтыг харахын тулд утасныхаа түгжээг тайлна уу"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Бусад сонголтыг харахын тулд таблетынхаа түгжээг тайлна уу"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Бусад сонголтыг харахын тулд төхөөрөмжийнхөө түгжээг тайлна уу"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"зураг илгээсэн"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Дэлгэцийн агшинг хадгалж байна…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Дэлгэцийн агшинг хадгалж байна…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS байршил"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Байршлын хүсэлтүүд идэвхтэй"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Мэдрэгчийг унтраах идэвхтэй байна"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Медиа идэвхтэй байна"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Бүх мэдэгдлийг цэвэрлэх."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Удирдах"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Түүх"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Ирж буй"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Чимээгүй"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Мэдэгдлүүд"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Харилцан яриа"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Бүх чимээгүй мэдэгдлийг арилгах"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Бүү саад бол горимын түр зогсоосон мэдэгдэл"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Мэдэгдлийг унтраах"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Энэ аппаас мэдэгдэл харуулсан хэвээр байх уу?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Чимээгүй"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Өгөгдмөл"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Бөмбөлөг"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Дуу эсвэл чичиргээ байхгүй"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Дуу эсвэл чичиргээ байхгүй бөгөөд харицан ярианы хэсгийн доод талд харагдана"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Утасны тохиргоонд тулгуурлан хонх дуугаргах буюу эсхүл чичирхийлж болзошгүй"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Утасны тохиргоонд тулгуурлан хонх дуугаргах буюу эсхүл чичирхийлж болзошгүй. <xliff:g id="APP_NAME">%1$s</xliff:g>-н харилцан яриаг өгөгдмөл тохиргооны дагуу бөмбөлөг болгоно."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Энэ контентын хөвөн гарч ирэх товчлолтойгоор таны анхаарлыг татдаг."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Харилцан ярианы хэсгийн дээд талд хөвж буй бөмбөлөг хэлбэрээр харагдах бөгөөд профайлын зургийг түгжигдсэн дэлгэцэд үзүүлнэ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Тохиргоо"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Ач холбогдол"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> харилцан ярианы тодорхой тохиргоог дэмждэггүй"</string> diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml index 76a15a852fc5..1ee0c53f22d1 100644 --- a/packages/SystemUI/res/values-mr/strings.xml +++ b/packages/SystemUI/res/values-mr/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"आणखी पर्यायांसाठी तुमचा फोन अनलॉक करा"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"आणखी पर्यायांसाठी तुमचा टॅबलेट अनलॉक करा"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"आणखी पर्यायांसाठी तुमचे डिव्हाइस अनलॉक करा"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS द्वारे स्थान सेट केले"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"स्थान विनंत्या सक्रिय"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"सेन्सर बंद आहेत"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"मीडिया अॅक्टिव्ह आहे"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"सर्व सूचना साफ करा."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थापित करा"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"आलेल्या"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"सायलंट"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचना"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"संभाषणे"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सर्व सायलंट सूचना साफ करा"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"व्यत्यय आणून नकाद्वारे सूचना थांबवल्या"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"सूचना बंद करा"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"या अॅपकडील सूचना दाखवणे सुरू ठेवायचे?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"सायलंट"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"डीफॉल्ट"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"आवाज किंवा व्हायब्रेशन नाही"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"आवाज किंवा व्हायब्रेशन नाही आणि संभाषण विभागात सर्वात तळाशी दिसते"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोन सेटिंग्जच्या आधारावर रिंग किंवा व्हायब्रेट होऊ शकतो. <xliff:g id="APP_NAME">%1$s</xliff:g> मधील संभाषणे बाय डीफॉल्ट बबल होतात."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"या आशयाच्या फ्लोटिंग शॉर्टकटसह तुमचे लक्ष केंद्रित करते."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"संभाषण विभागात सर्वात वरती फ्लोटिंग बबल म्हणून दिसते, लॉक स्क्रीनवर प्रोफाइल पिक्चर दाखवते"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिंग्ज"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राधान्य"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> संभाषण विशिष्ट सेटिंग्जना सपोर्ट करत नाही"</string> diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml index 660fe7ae1fc5..48c73dfc01ee 100644 --- a/packages/SystemUI/res/values-ms/strings.xml +++ b/packages/SystemUI/res/values-ms/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zum untuk memenuhi skrin"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Regang utk memenuhi skrin"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Tangkapan skrin"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Buka kunci telefon anda untuk mendapatkan lagi pilihan"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Buka kunci tablet anda untuk mendapatkan lagi pilihan"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Buka kunci peranti anda untuk mendapatkan lagi pilihan"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"menghantar imej"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Menyimpan tangkapan skrin..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Menyimpan tangkapan skrin..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokasi ditetapkan oleh GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Permintaan lokasi aktif"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Penderia dimatikan aktif"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media aktif"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Padamkan semua pemberitahuan."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Urus"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Sejarah"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Masuk"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Senyap"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Pemberitahuan"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Perbualan"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Kosongkan semua pemberitahuan senyap"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Pemberitahuan dijeda oleh Jangan Ganggu"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Matikan pemberitahuan"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Terus tunjukkan pemberitahuan daripada apl ini?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Senyap"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Lalai"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Gelembung"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Tiada bunyi atau getaran"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Tiada bunyi atau getaran dan muncul di sebelah bawah dalam bahagian perbualan"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Mungkin berbunyi atau bergetar berdasarkan tetapan telefon"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Mungkin berbunyi atau bergetar berdasarkan tetapan telefon. Perbualan daripada gelembung <xliff:g id="APP_NAME">%1$s</xliff:g> secara lalai."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Memastikan anda memberikan perhatian dengan pintasan terapung ke kandungan ini."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Ditunjukkan di sebelah atas bahagian perbualan, muncul sebagai gelembung terapung, memaparkan gambar profil pada skrin kunci"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Tetapan"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Keutamaan"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> tidak menyokong tetapan khusus perbualan"</string> diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml index f5b3f6e31140..cf8f8113ce8f 100644 --- a/packages/SystemUI/res/values-my/strings.xml +++ b/packages/SystemUI/res/values-my/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ဇူးမ်အပြည့်ဆွဲခြင်း"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ဖန်သားပြင်အပြည့်ဆန့်ခြင်း"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ဖန်သားပြင်ဓာတ်ပုံ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်ဖုန်းကို လော့ခ်ဖွင့်ပါ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်တက်ဘလက်ကို လော့ခ်ဖွင့်ပါ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"နောက်ထပ် ထိန်းချုပ်မှုများအတွက် သင့်စက်ကို လော့ခ်ဖွင့်ပါ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ပုံပို့ထားသည်"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ဖန်သားပြင်ဓါတ်ပုံသိမ်းစဉ်.."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ဖန်သားပြင်ဓါတ်ပုံရိုက်ခြင်းအား သိမ်းဆည်းပါမည်"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPSမှတည်နေရာကိုအတည်ပြုသည်"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"တည်နေရာပြ တောင်းဆိုချက်များ အသက်ဝင်ရန်"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"အာရုံခံစနစ်များ ပိတ်ထားသည်"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"မီဒီယာ ဖွင့်ထားသည်"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"သတိပေးချက်အားလုံးအား ဖယ်ရှားခြင်း။"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"စီမံရန်"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"မှတ်တမ်း"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"အဝင်"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"အသံတိတ်ခြင်း"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"အကြောင်းကြားချက်များ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"စကားဝိုင်းများ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"အသံတိတ် အကြောင်းကြားချက်များအားလုံးကို ရှင်းလင်းရန်"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"အကြောင်းကြားချက်များကို \'မနှောင့်ယှက်ရ\' က ခေတ္တရပ်ထားသည်"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"အကြောင်းကြားချက်များ ပိတ်ရန်"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ဤအက်ပ်ထံမှ အကြောင်းကြားချက်များကို ဆက်ပြလိုပါသလား။"</string> <string name="notification_silence_title" msgid="8608090968400832335">"အသံတိတ်ရန်"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"မူလ"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ပူဖောင်းဖောက်သံ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"အသံ သို့မဟုတ် တုန်ခါမှုမရှိပါ၊ စကားဝိုင်းကဏ္ဍ၏ အောက်ပိုင်းတွင် မြင်ရသည်"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ဖုန်းဆက်တင်များပေါ် အခြေခံပြီး အသံမြည်နိုင်သည် သို့မဟုတ် တုန်ခါနိုင်သည်။ မူရင်းသတ်မှတ်ချက်အဖြစ် <xliff:g id="APP_NAME">%1$s</xliff:g> မှ စကားဝိုင်းများကို ပူဖောင်းကွက်ဖြင့် ပြသည်။"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"အကြောင်းအရာကို floating shortcut ကိုသုံး၍ အာရုံစိုက်လာအောင်လုပ်ပါ။"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"စကားဝိုင်းကဏ္ဍ၏ ထိပ်ပိုင်းတွင် ပြပြီး ပူဖောင်းကွက်အဖြစ် မြင်ရသည်၊ လော့ခ်ချထားချိန် မျက်နှာပြင်တွင် ပရိုဖိုင်ပုံကို ပြသည်"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ဆက်တင်များ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ဦးစားပေး"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> က စကားဝိုင်းအလိုက် ဆက်တင်များကို မပံ့ပိုးပါ"</string> diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml index a38fb4ce3b5a..4bedaab59986 100644 --- a/packages/SystemUI/res/values-nb/strings.xml +++ b/packages/SystemUI/res/values-nb/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom for å fylle skjermen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Strekk for å fylle skjerm"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skjermdump"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås opp telefonen din for å få flere alternativer"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås opp nettbrettet ditt for å få flere alternativer"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås opp enheten din for å få flere alternativer"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har sendt et bilde"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Lagrer skjermdumpen …"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Lagrer skjermdumpen …"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Posisjon angitt av GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktive stedsforespørsler"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"«Sensorene er av» er aktiv"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Medier er aktive"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Fjern alle varslinger."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Administrer"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Logg"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Innkommende"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Lydløs"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Varsler"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Samtaler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Fjern alle lydløse varsler"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Varsler er satt på pause av «Ikke forstyrr»"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Slå av varsler"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Vil du fortsette å vise varsler fra denne appen?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Lydløs"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Boble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Ingen lyd eller vibrering"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Ingen lyd eller vibrering, og vises lavere i samtaledelen"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringe eller vibrere basert på telefoninnstillingene"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringe eller vibrere basert på telefoninnstillingene. Samtaler fra <xliff:g id="APP_NAME">%1$s</xliff:g> lager bobler som standard."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Holder deg oppmerksom med en svevende snarvei til dette innholdet."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Vises øverst i samtaledelen, vises som en flytende boble, viser profilbildet på låseskjermen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Innstillinger"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> støtter ikke samtalespesifikke innstillinger"</string> diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml index 4483c5e1d225..05839b3b205f 100644 --- a/packages/SystemUI/res/values-ne/strings.xml +++ b/packages/SystemUI/res/values-ne/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string> <string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"थप विकल्पहरू हेर्न आफ्नो फोन अनलक गर्नुहोस्"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"थप विकल्पहरू हेर्न आफ्नो ट्याब्लेट अनलक गर्नुहोस्"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"थप विकल्पहरू हेर्न आफ्नो यन्त्र अनलक गर्नुहोस्"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS द्वारा स्थान सेट गरिएको"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"स्थान अनुरोधहरू सक्रिय"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"सेन्सर निष्क्रिय नामक सुविधा सक्रिय छ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"मिडिया प्ले भइरहेको छ"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"सबै सूचनाहरू हटाउनुहोस्।"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"व्यवस्थित गर्नुहोस्"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"इतिहास"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"हालसालै प्राप्त भएका सूचनाहरू"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"मौन"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाहरू"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"वार्तालापहरू"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"सबै मौन सूचनाहरू हटाउनुहोस्"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"बाधा नपुऱ्याउनुहोस् नामक मोडमार्फत पज पारिएका सूचनाहरू"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"सूचनाहरू निष्क्रिय पार्नुहोस्"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"यो अनुप्रयोगका सूचनाहरू देखाउने क्रम जारी राख्ने हो?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"मौन"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"पूर्वनिर्धारित"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"बबल"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"न घन्टी बज्छ न त कम्पन नै हुन्छ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"न घन्टी बज्छ न त कम्पन नै हुन्छ र वार्तालाप खण्डको तलतिर देखा पर्छ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"फोनको सेटिङका आधारमा घन्टी बज्न वा कम्पन हुन सक्छ"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"फोनको सेटिङका आधारमा घन्टी बज्न वा कम्पन हुन सक्छ। <xliff:g id="APP_NAME">%1$s</xliff:g> का वार्तालापहरू पूर्वनिर्धारित रूपमा बबलमा देखाइन्छन्।"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"फ्लोटिङ सर्टकटमार्फत यो सामग्रीतर्फ तपाईंको ध्यान आकर्षित गर्दछ।"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"वार्तालाप खण्डको सिरानमा देखा पर्छ, तैरने बबलका रूपमा देखा पर्छ, लक स्क्रिनमा प्रोफाइल तस्बिर देखाइन्छ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"सेटिङ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"प्राथमिकता"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> मा वार्तालापविशेषका लागि सेटिङ उपलब्ध छैन"</string> diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml index deea505d17a5..811634558d89 100644 --- a/packages/SystemUI/res/values-nl/strings.xml +++ b/packages/SystemUI/res/values-nl/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom om scherm te vullen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rek uit v. schermvulling"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Ontgrendel je telefoon voor meer opties"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Ontgrendel je tablet voor meer opties"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Ontgrendel je apparaat voor meer opties"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"heeft een afbeelding gestuurd"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Screenshot opslaan..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Screenshot opslaan..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Locatie bepaald met gps"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Locatieverzoeken actief"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"\'Sensoren uit\' actief"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media is actief"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Alle meldingen wissen."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Beheren"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geschiedenis"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkomend"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Stil"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Meldingen"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Gesprekken"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Alle stille meldingen wissen"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Meldingen onderbroken door \'Niet storen\'"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Meldingen uitschakelen"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Meldingen van deze app blijven weergeven?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Stil"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Standaard"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubbel"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Geen geluid of trilling"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Geen geluid of trilling en wordt op een lagere positie in het gedeelte met gesprekken weergegeven"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan overgaan of trillen op basis van de telefooninstellingen"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan overgaan of trillen op basis van de telefooninstellingen. Gesprekken uit <xliff:g id="APP_NAME">%1$s</xliff:g> worden standaard als bubbels weergegeven."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Trekt de aandacht met een zwevende snelkoppeling naar deze content."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wordt bovenaan het gedeelte met gesprekken weergegeven, verschijnt als zwevende bubbel, geeft de profielfoto weer op het vergrendelingsscherm"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Instellingen"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioriteit"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ondersteunt geen gespreksspecifieke instellingen"</string> diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml index 696161329efd..5622788b2a64 100644 --- a/packages/SystemUI/res/values-pa/strings.xml +++ b/packages/SystemUI/res/values-pa/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਟੈਬਲੈੱਟ ਅਣਲਾਕ ਕਰੋ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ਹੋਰ ਵਿਕਲਪਾਂ ਲਈ ਆਪਣਾ ਡੀਵਾਈਸ ਅਣਲਾਕ ਕਰੋ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS ਵੱਲੋਂ ਸੈੱਟ ਕੀਤਾ ਗਿਆ ਟਿਕਾਣਾ"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"ਨਿਰਧਾਰਿਤ ਸਥਾਨ ਸੇਵਾ ਬੇਨਤੀਆਂ ਸਕਿਰਿਆ"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"\'ਸੈਂਸਰ ਬੰਦ ਕਰੋ\' ਨੂੰ ਕਿਰਿਆਸ਼ੀਲ ਕਰੋ"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"ਮੀਡੀਆ ਕਿਰਿਆਸ਼ੀਲ ਹੈ"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ਸਾਰੀਆਂ ਸੂਚਨਾਵਾਂ ਹਟਾਓ।"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"ਪ੍ਰਬੰਧਨ ਕਰੋ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ਇਤਿਹਾਸ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ਇਨਕਮਿੰਗ"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"ਸ਼ਾਂਤ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"ਸੂਚਨਾਵਾਂ"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"ਗੱਲਾਂਬਾਤਾਂ"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ਸਾਰੀਆਂ ਖਾਮੋਸ਼ ਸੂਚਨਾਵਾਂ ਕਲੀਅਰ ਕਰੋ"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ਪਰੇਸ਼ਾਨ ਨਾ ਕਰੋ\' ਵੱਲੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਰੋਕਿਆ ਗਿਆ"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"ਸੂਚਨਾਵਾਂ ਬੰਦ ਕਰੋ"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ਕੀ ਇਸ ਐਪ ਤੋਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਦਿਖਾਉਣਾ ਜਾਰੀ ਰੱਖਣਾ ਹੈ?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"ਸ਼ਾਂਤ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ਪੂਰਵ-ਨਿਰਧਾਰਤ"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"ਬੁਲਬੁਲਾ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ਕੋਈ ਧੁਨੀ ਜਾਂ ਥਰਥਰਾਹਟ ਨਹੀਂ ਅਤੇ ਸੂਚਨਾਵਾਂ ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਵਿੱਚ ਹੇਠਲੇ ਪਾਸੇ ਦਿਸਦੀਆਂ ਹਨ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ਫ਼ੋਨ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ਫ਼ੋਨ ਸੈਟਿੰਗਾਂ ਦੇ ਆਧਾਰ \'ਤੇ ਘੰਟੀ ਵੱਜ ਸਕਦੀ ਹੈ ਜਾਂ ਥਰਥਰਾਹਟ ਹੋ ਸਕਦੀ ਹੈ। ਪੂਰਵ-ਨਿਰਧਾਰਤ ਤੌਰ \'ਤੇ <xliff:g id="APP_NAME">%1$s</xliff:g> ਬਬਲ ਤੋਂ ਗੱਲਾਂਬਾਤਾਂ।"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ਇਸ ਸਮੱਗਰੀ ਦੇ ਅਸਥਿਰ ਸ਼ਾਰਟਕੱਟ ਨਾਲ ਆਪਣਾ ਧਿਆਨ ਕੇਂਦਰਿਤ ਰੱਖੋ।"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"ਗੱਲਬਾਤ ਸੈਕਸ਼ਨ ਦੇ ਸਿਖਰ \'ਤੇ ਦਿਖਾਈਆਂ ਜਾਂਦੀਆਂ ਹਨ, ਬਬਲ ਵਜੋਂ ਦਿਸਦੀਆਂ ਹਨ, ਲਾਕ ਸਕ੍ਰੀਨ \'ਤੇ ਪ੍ਰੋਫਾਈਲ ਤਸਵੀਰ ਦਿਖਾਈ ਜਾਂਦੀ ਹੈ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ਸੈਟਿੰਗਾਂ"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ਤਰਜੀਹ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਗੱਲਬਾਤ ਸੰਬੰਧੀ ਵਿਸ਼ੇਸ਼ ਸੈਟਿੰਗਾਂ ਦਾ ਸਮਰਥਨ ਨਹੀਂ ਕਰਦੀ"</string> diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml index cd6facc78722..abb4cfc06292 100644 --- a/packages/SystemUI/res/values-pl/strings.xml +++ b/packages/SystemUI/res/values-pl/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Powiększ, aby wypełnić ekran"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Rozciągnij, aby wypełnić ekran"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Zrzut ekranu"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odblokuj telefon, by wyświetlić więcej opcji"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odblokuj tablet, by wyświetlić więcej opcji"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odblokuj urządzenie, by wyświetlić więcej opcji"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"wysłano obraz"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Zapisywanie zrzutu ekranu..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Zapisywanie zrzutu ekranu..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokalizacja z GPSa"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Prośby o lokalizację są aktywne"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Wyłączenie czujników aktywne"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Multimedia są aktywne"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Usuń wszystkie powiadomienia."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Zarządzaj"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Przychodzące"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ciche"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Powiadomienia"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Rozmowy"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Usuń wszystkie ciche powiadomienia"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Powiadomienia wstrzymane przez tryb Nie przeszkadzać"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Wyłącz powiadomienia"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Nadal pokazywać powiadomienia z tej aplikacji?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Bez dźwięku"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Domyślne"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Dymek"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Brak dźwięku i wibracji"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brak dźwięku i wibracji, wyświetla się niżej w sekcji rozmów"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Może włączyć dzwonek lub wibracje w zależności od ustawień telefonu"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Może włączyć dzwonek lub wibracje w zależności od ustawień telefonu. Rozmowy z aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g> są domyślnie wyświetlane jako dymki."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Przyciąga uwagę dzięki pływającym skrótom do treści."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Wyświetla się jako pływający dymek u góry sekcji rozmów, pokazuje zdjęcie profilowe na ekranie blokady"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ustawienia"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorytet"</string> <string name="no_shortcut" msgid="7176375126961212514">"Aplikacja <xliff:g id="APP_NAME">%1$s</xliff:g> nie obsługuje ustawień rozmowy"</string> diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml index c106584b6f77..e581176ae47c 100644 --- a/packages/SystemUI/res/values-pt-rBR/strings.xml +++ b/packages/SystemUI/res/values-pt-rBR/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Local definido por GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitações de localização ativas"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"A mídia está ativa"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciosas"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desativar notificações"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuar mostrando notificações desse app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bolha"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode vibrar ou tocar com base nas configurações do smartphone"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode vibrar ou tocar com base nas configurações do smartphone. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantém sua atenção com um atalho flutuante para esse conteúdo."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</string> diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml index fefff49850af..8102e6bdb2b4 100644 --- a/packages/SystemUI/res/values-pt-rPT/strings.xml +++ b/packages/SystemUI/res/values-pt-rPT/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom para preencher o ecrã"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Esticar p. caber em ec. int."</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captura de ecrã"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie o telemóvel para obter mais opções."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie o tablet para obter mais opções."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie o dispositivo para obter mais opções."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"A guardar captura de ecrã..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"A guardar captura de ecrã..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Localização definida por GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Pedidos de localização ativos"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensores desativados ativo"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"O conteúdo multimédia está ativo."</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gerir"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"A receber"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silencioso"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Limpar todas as notificações silenciosas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações colocadas em pausa pelo modo Não incomodar."</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desativar notificações"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Pretende continuar a ver notificações desta app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Predefinição"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Balão"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sem som ou vibração"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sem som ou vibração e aparece na parte inferior na secção de conversas."</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode tocar ou vibrar com base nas definições do telemóvel."</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode tocar ou vibrar com base nas definições do telemóvel. As conversas da app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem como um balão por predefinição."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantém a sua atenção com um atalho flutuante para este conteúdo."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior da secção de conversas, surge como um balão flutuante e apresenta a imagem do perfil no ecrã de bloqueio."</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Definições"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="7176375126961212514">"A app <xliff:g id="APP_NAME">%1$s</xliff:g> não suporta definições específicas de conversas."</string> diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml index c106584b6f77..e581176ae47c 100644 --- a/packages/SystemUI/res/values-pt/strings.xml +++ b/packages/SystemUI/res/values-pt/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom p/ preencher a tela"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ampliar p/ preencher tela"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Capturar tela"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Desbloqueie seu smartphone para ver mais opções"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Desbloqueie seu tablet para ver mais opções"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Desbloqueie seu dispositivo para ver mais opções"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"enviou uma imagem"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Salvando captura de tela..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Salvando captura de tela..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Local definido por GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitações de localização ativas"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"A opção \"Sensores desativados\" está ativa"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"A mídia está ativa"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Limpar todas as notificações."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"Mais <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gerenciar"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Histórico"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Recebidas"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silenciosas"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificações"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversas"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Apagar todas as notificações silenciosas"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificações pausadas pelo modo \"Não perturbe\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Desativar notificações"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Continuar mostrando notificações desse app?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silencioso"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Padrão"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bolha"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Som e vibração desativados"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"O som e a vibração estão desativados, e o balão aparece na parte inferior da seção de conversa"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Pode vibrar ou tocar com base nas configurações do smartphone"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Pode vibrar ou tocar com base nas configurações do smartphone. As conversas do app <xliff:g id="APP_NAME">%1$s</xliff:g> aparecem em balões por padrão."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mantém sua atenção com um atalho flutuante para esse conteúdo."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Aparece na parte superior de uma seção de conversa, em forma de balão, mostrando a foto do perfil na tela de bloqueio"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Configurações"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioridade"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> não é compatível com configurações específicas de conversa"</string> diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml index b5534fd18c47..d5a774decd72 100644 --- a/packages/SystemUI/res/values-ro/strings.xml +++ b/packages/SystemUI/res/values-ro/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zoom pt. a umple ecranul"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Înt. pt. a umple ecranul"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Captură de ecran"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Deblocați telefonul pentru mai multe opțiuni"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Deblocați tableta pentru mai multe opțiuni"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Deblocați dispozitivul pentru mai multe opțiuni"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a trimis o imagine"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Se salv. captura de ecran..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Se salvează captura de ecran..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Locație setată prin GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Solicitări locație active"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Dezactivarea senzorilor este activă"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Serviciile media sunt active"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Ștergeți toate notificările."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Gestionați"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Istoric"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Primite"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Silențioase"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Notificări"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Conversații"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Ștergeți toate notificările silențioase"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Notificări întrerupte prin „Nu deranja”"</string> @@ -720,20 +714,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Dezactivați notificările"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Doriți să continuați afișarea notificărilor de la această aplicație?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Silențios"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Prestabilite"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Balon"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Fără sunet sau vibrații"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Fără sunet sau vibrații și apare în partea de jos a secțiunii de conversație"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Poate să sune sau să vibreze, în funcție de setările telefonului"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Poate să sune sau să vibreze, în funcție de setările telefonului. Conversațiile din balonul <xliff:g id="APP_NAME">%1$s</xliff:g> în mod prestabilit."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Vă atrage atenția printr-o comandă rapidă flotantă la acest conținut."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Se afișează în partea de sus a secțiunii de conversație, apare ca un balon flotant, afișează fotografia de profil pe ecranul de blocare"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Setări"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritate"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nu acceptă setările pentru conversații"</string> diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml index fd4ed6e26686..da367e744110 100644 --- a/packages/SystemUI/res/values-ru/strings.xml +++ b/packages/SystemUI/res/values-ru/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Подогнать по размерам экрана"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Растянуть на весь экран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Скриншот"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Чтобы посмотреть дополнительные параметры, разблокируйте телефон."</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Чтобы посмотреть дополнительные параметры, разблокируйте планшет."</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Чтобы посмотреть дополнительные параметры, разблокируйте устройство."</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"отправлено изображение"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Сохранение..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Сохранение..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Координаты по GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Есть активные запросы на определение местоположения"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Датчики отключены"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Идет воспроизведение мультимедиа"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Удалить все уведомления"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Настроить"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"История"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Входящие"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без звука"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Уведомления"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Разговоры"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Отклонить все беззвучные уведомления"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"В режиме \"Не беспокоить\" уведомления заблокированы"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Выключить уведомления"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Показывать уведомления от этого приложения?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Без звука"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"По умолчанию"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Всплывающая подсказка"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука или вибрации"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука или вибрации, появляется в нижней части списка разговоров"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Звонок или вибрация в зависимости от настроек телефона"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Звонок или вибрация в зависимости от настроек телефона. Разговоры из приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" по умолчанию появляются в виде всплывающего чата."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Привлекает ваше внимание к контенту с помощью плавающего ярлыка"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Появляется в верхней части списка разговоров и как всплывающий чат, а также показывает фото профиля на заблокированном экране"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Настройки"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> <string name="no_shortcut" msgid="7176375126961212514">"Приложение \"<xliff:g id="APP_NAME">%1$s</xliff:g>\" не поддерживает настройки разговора."</string> diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml index 1cabf2a85131..a75d5eef237b 100644 --- a/packages/SystemUI/res/values-si/strings.xml +++ b/packages/SystemUI/res/values-si/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"තිරය පිරවීමට විශාලනය කරන්න"</string> <string name="compat_mode_off" msgid="7682459748279487945">"තිරය පිරවීමට අදින්න"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"තිර රුව"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"තව විකල්ප සඳහා ඔබේ දුරකථනය අගුලු හරින්න"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"තව විකල්ප සඳහා ඔබේ ටැබ්ලට් පරිගණකය අගුලු හරින්න"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"තව විකල්ප සඳහා ඔබේ උපාංගය අගුලු හරින්න"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"රූපයක් එවන ලදී"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"තිර රුව සුරකිමින්…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"තිර රුව සුරැකෙමින් පවතී…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS මඟින් ස්ථානය සකසා ඇත"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"පිහිටීම් ඉල්ලීම් සක්රියයි"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"සංවේදක ක්රියාවිරහිතය සක්රියයි"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"මාධ්ය සක්රියයි"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"සියලු දැනුම්දීම් හිස් කරන්න."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"කළමනාකරණය කරන්න"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ඉතිහාසය"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"එන"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"නිහඬ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"දැනුම් දීම්"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"සංවාද"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"සියලු නිහඬ දැනුම්දීම් හිස් කරන්න"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"බාධා නොකරන්න මගින් විරාම කරන ලද දැනුම්දීම්"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"දැනුම්දීම් අක්රිය කරන්න"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"මෙම යෙදුම වෙතින් දැනුම්දීම් පෙන්වමින් තබන්නද?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"නිහඬ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"පෙරනිමි"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"බුබුළු"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"හඬක් හෝ කම්පනයක් නැත"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"හඬක් හෝ කම්පනයක් නැති අතර සංවාද කොටසේ පහළම දිස් වේ"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"දුරකථන සැකසීම් මත පදනම්ව නාද කිරීමට හෝ කම්පනය කිරීමට හැකිය"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"දුරකථන සැකසීම් මත පදනම්ව නාද කිරීමට හෝ කම්පනය කිරීමට හැකිය. <xliff:g id="APP_NAME">%1$s</xliff:g> වෙතින් සංවාද පෙරනිමියෙන් බුබුළු දමයි"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"පාවෙන කෙටිමගක් සමග ඔබේ අවධානය මෙම අන්තර්ගතය වෙත තබා ගන්න."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"සංවාද කොටසේ ඉහළම පෙන්වයි, බුබුළක් ලෙස දිස් වේ, අගුලු තිරයේ පැතිකඩ පින්තූරය සංදර්ශනය වේ"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"සැකසීම්"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ප්රමුඛතාව"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> සංවාදය නිශ්චිත සැකසීම්වලට සහාය නොදක්වයි"</string> diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml index e71c3ee2771e..7add73fe88d3 100644 --- a/packages/SystemUI/res/values-sk/strings.xml +++ b/packages/SystemUI/res/values-sk/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Priblížiť na celú obrazovku"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Na celú obrazovku"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Snímka obrazovky"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Odomknite svoj telefón pre ďalšie možnosti"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Odomknite svoj tablet pre ďalšie možnosti"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Odomknite svoje zariadenie pre ďalšie možnosti"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"odoslal(a) obrázok"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Prebieha ukladanie snímky obrazovky..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Prebieha ukladanie snímky obrazovky..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Poloha nastavená pomocou GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Žiadosti o polohu sú aktívne"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Funkcia Senzory sú vypnuté je aktívna"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Médium je aktívne"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Vymazať všetky upozornenia."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Spravovať"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"História"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Prichádzajúce"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ticho"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Upozornenia"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konverzácie"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Vymazať všetky tiché upozornenia"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Upozornenia sú pozastavené režimom bez vyrušení"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Vypnúť upozornenia"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Majú sa upozornenia z tejto aplikácie naďalej zobrazovať?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Tiché"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Predvolené"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bublina"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Žiadny zvuk ani vibrácie"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Žiadny zvuk ani vibrácie a zobrazuje sa v dolnej sekcii konverzácie"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Môže zvoniť alebo vibrovať podľa nastavení telefónu"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Môže zvoniť alebo vibrovať podľa nastavení telefónu. Predvolene sa zobrazia konverzácie z bubliny <xliff:g id="APP_NAME">%1$s</xliff:g>."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Upúta vás plávajúcim odkazom na tento obsah."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Nájdete ju v hornej sekcii konverzácie ako plávajúcu bublinu a zobrazuje profilovú fotku na uzamknutej obrazovke"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavenia"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priorita"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nepodporuje nastavenia konkrétnych konverzácií"</string> diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml index 5615c3a83cd6..024188f719ad 100644 --- a/packages/SystemUI/res/values-sl/strings.xml +++ b/packages/SystemUI/res/values-sl/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Povečava čez cel zaslon"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Raztegnitev čez zaslon"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Posnetek zaslona"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Za več možnosti odklenite telefon"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Za več možnosti odklenite tablični računalnik"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Za več možnosti odklenite napravo"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"je poslal(-a) sliko"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Shranjev. posnetka zaslona ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Shranjevanje posnetka zaslona ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokacija nastavljena z GPS-om"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktivne zahteve za lokacijo"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Izklop za tipala je aktiven"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Predstavnost je aktivna"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Izbriši vsa obvestila."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"in <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Upravljanje"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Zgodovina"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Dohodno"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Tiho"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Obvestila"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Pogovori"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Brisanje vseh tihih obvestil"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Prikazovanje obvestil je začasno zaustavljeno z načinom »ne moti«"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Izklopi obvestila"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Želite, da so obvestila te aplikacije še naprej prikazana?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Tiho"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Privzeto"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Mehurček"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Brez zvočnega opozarjanja ali vibriranja"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Brez zvočnega opozarjanja ali vibriranja, prikaz nižje v razdelku s pogovorom"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev telefona"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Zvonjenje ali vibriranje je omogočeno na podlagi nastavitev telefona. Pogovori v aplikaciji <xliff:g id="APP_NAME">%1$s</xliff:g> so privzeto prikazani v oblačkih."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Zadrži vašo pozornost z lebdečo bližnjico do te vsebine."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Prikaz na vrhu razdelka s pogovorom in v plavajočem oblačku, prikaz profilne slike na zaklenjenem zaslonu"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Nastavitve"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prednost"</string> <string name="no_shortcut" msgid="7176375126961212514">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> ne podpira posebnih nastavitev za pogovore"</string> diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml index 5d10a71f1c5e..140264668eb2 100644 --- a/packages/SystemUI/res/values-sq/strings.xml +++ b/packages/SystemUI/res/values-sq/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Shkyçe telefonin për më shumë opsione"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Shkyçe tabletin për më shumë opsione"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Shkyçe pajisjen për më shumë opsione"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Vendndodhja është caktuar nga GPS-ja"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Kërkesat për vendodhje janë aktive"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Çaktivizimi i sensorëve aktiv"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media është aktive"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Pastro të gjitha njoftimet."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Menaxho"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historiku"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hyrëse"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Në heshtje"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Njoftimet"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Bisedat"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Pastro të gjitha njoftimet në heshtje"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Njoftimet janë vendosur në pauzë nga modaliteti \"Mos shqetëso\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Çaktivizo njoftimet"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Do të vazhdosh t\'i shfaqësh njoftimet nga ky aplikacion?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Në heshtje"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"E parazgjedhur"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Flluskë"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Asnjë tingull ose dridhje"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Asnjë tingull ose dridhje dhe shfaqet më poshtë në seksionin e bisedave"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të telefonit"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Mund të bjerë zilja ose të dridhet në bazë të cilësimeve të telefonit. Bisedat nga flluska e <xliff:g id="APP_NAME">%1$s</xliff:g> si parazgjedhje."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Mban vëmendjen tënde me një shkurtore pluskuese te kjo përmbajtje."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Shfaqet në krye të seksionit të bisedës dhe shfaqet si flluskë pluskuese, shfaq fotografinë e profilit në ekranin e kyçjes"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cilësimet"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Përparësia"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> nuk i mbështet cilësimet specifike të bisedës"</string> diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml index f24c5d4a8453..4b6de24a2ba4 100644 --- a/packages/SystemUI/res/values-sr/strings.xml +++ b/packages/SystemUI/res/values-sr/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Зумирај на целом екрану"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Развуци на цео екран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Снимак екрана"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Откључајте телефон за још опција"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Откључајте таблет за још опција"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Откључајте уређај за још опција"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"је послао/ла слику"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Чување снимка екрана..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Чување снимка екрана..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Локацију је подесио GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Има активних захтева за локацију"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Сензори су искључени"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Медијум је активан"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Обриши сва обавештења."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"и још <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -522,10 +518,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Управљајте"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Историја"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Долазно"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Нечујно"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Обавештења"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Конверзације"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Обришите сва нечујна обавештења"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Обавештења су паузирана режимом Не узнемиравај"</string> @@ -720,20 +714,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Искључи обавештења"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Желите ли да се обавештења из ове апликације и даље приказују?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Нечујно"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Подразумевано"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Облачић"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звука и вибрирања"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звука и вибрирања и приказује се у наставку одељка за конверзације"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може да звони или вибрира у зависности од подешавања телефона"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може да звони или вибрира у зависности од подешавања телефона. Конверзације из апликације <xliff:g id="APP_NAME">%1$s</xliff:g> се подразумевано приказују у облачићима."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Привлачи вам пажњу помоћу плутајуће пречице до овог садржаја."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Приказује се у врху одељка за конверзације као плутајући облачић, приказује слику профила на закључаном екрану"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Подешавања"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Приоритет"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не подржава подешавања за конверзације"</string> diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml index e289a167b5f9..7c4962ebfca3 100644 --- a/packages/SystemUI/res/values-sv/strings.xml +++ b/packages/SystemUI/res/values-sv/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Zooma för att fylla skärm"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Dra för att fylla skärmen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skärmdump"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Lås upp telefonen för fler alternativ"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Lås upp surfplattan för fler alternativ"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Lås upp enheten för fler alternativ"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"har skickat en bild"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skärmdumpen sparas ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skärmdumpen sparas ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Platsen har identifierats av GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Det finns aktiva platsbegäranden"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensorer har inaktiverats"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Media har aktiverats"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Ta bort alla meddelanden."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> till"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Hantera"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historik"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Inkommande"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Ljudlöst"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Aviseringar"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Konversationer"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Rensa alla ljudlösa aviseringar"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Aviseringar har pausats via Stör ej"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Inaktivera aviseringar"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Vill du fortsätta visa aviseringar för den här appen?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Tyst"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Standard"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubbla"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Inga ljud eller vibrationer"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Inga ljud eller vibrationer och visas längre ned bland konversationerna"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Kan ringa eller vibrera beroende på inställningarna på telefonen"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Kan ringa eller vibrera beroende på inställningarna på telefonen. Konversationer från <xliff:g id="APP_NAME">%1$s</xliff:g> visas i bubblor som standard."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Behåller din uppmärksamhet med en flytande genväg till innehållet."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Visas högst upp bland konversationerna som en flytande bubbla, visar profilbilden på låsskärmen"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Inställningar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Prioritet"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> har inte stöd för konversationsspecifika inställningar"</string> diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml index 49e7a8ec30a3..fd3194aaa878 100644 --- a/packages/SystemUI/res/values-sw/strings.xml +++ b/packages/SystemUI/res/values-sw/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Kuza ili kujaza skrini"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Tanua ili kujaza skrini"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Picha ya skrini"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Fungua simu yako ili upate chaguo zaidi"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Fungua kompyuta yako kibao ili upate chaguo zaidi"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Fungua kifaa chako ili upate chaguo zaidi"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"imetuma picha"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Inahifadhi picha ya skrini..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Inahifadhi picha ya skrini..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Mahali pamewekwa na GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Maombi ya eneo yanatumika"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Kipengele cha kuzima vitambuzi kimewashwa"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Maudhui yanachezwa"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Futa arifa zote."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Dhibiti"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Historia"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Simu inayoingia"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Kimya"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Arifa"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Mazungumzo"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Futa arifa zote zisizo na sauti"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Kipengele cha Usinisumbue kimesitisha arifa"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Zima arifa"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Ungependa kuendelea kuonyesha arifa kutoka programu hii?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Kimya"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Chaguomsingi"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Kiputo"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Hakuna sauti wala mtetemo"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Hakuna sauti wala mtetemo na huonekana upande wa chini katika sehemu ya mazungumzo"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Huenda ikalia au kutetema kulingana na mipangilio ya simu"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Huenda ikalia au kutetema kulingana na mipangilio ya simu. Mazungumzo kutoka kiputo cha <xliff:g id="APP_NAME">%1$s</xliff:g> kwa chaguomsingi."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Huweka umakinifu wako kwenye maudhui haya kwa kutumia njia ya mkato ya kuelea."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Huonyeshwa kwenye sehemu ya juu ya mazungumzo, huonekana kama kiputo, huonyesha picha ya wasifu kwenye skrini iliyofungwa"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mipangilio"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Kipaumbele"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> haitumii mipangilio mahususi ya mazungumzo"</string> diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml index 4c0118207410..8e9370aaa7d2 100644 --- a/packages/SystemUI/res/values-ta/strings.xml +++ b/packages/SystemUI/res/values-ta/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"திரையை நிரப்ப அளவை மாற்று"</string> <string name="compat_mode_off" msgid="7682459748279487945">"திரையை நிரப்ப இழு"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ஸ்கிரீன்ஷாட்"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"மேலும் விருப்பங்களுக்கு மொபைலை அன்லாக் செய்யவும்"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"மேலும் விருப்பங்களுக்கு டேப்லெட்டை அன்லாக் செய்யவும்"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"மேலும் விருப்பங்களுக்குச் சாதனத்தை அன்லாக் செய்யவும்"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"படம் அனுப்பப்பட்டது"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"ஸ்க்ரீன் ஷாட்டைச் சேமிக்கிறது…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS அமைத்த இருப்பிடம்"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"இருப்பிடக் கோரிக்கைகள் இயக்கப்பட்டன"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"’சென்சார்கள் ஆஃப்’ செயலில் உள்ளது"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"மீடியா பிளே ஆகிறது"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"எல்லா அறிவிப்புகளையும் அழி."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"அறிவிப்புகளை நிர்வகி"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"வரலாறு"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"உள்வருவது"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"நிசப்தம்"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"அறிவிப்புகள்"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"உரையாடல்கள்"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ஒலியில்லாத அழைப்புகள் அனைத்தையும் அழிக்கும்"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'தொந்தரவு செய்ய வேண்டாம்\' அம்சத்தின் மூலம் அறிவிப்புகள் இடைநிறுத்தப்பட்டுள்ளன"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"அறிவிப்புகளை முடக்கு"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"இந்த ஆப்ஸின் அறிவிப்புகளைத் தொடர்ந்து காட்டவா?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"நிசப்தம்"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"இயல்புநிலை"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"பபிள்"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ஒலி / அதிர்வு இல்லை"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ஒலி / அதிர்வு இல்லாமல் உரையாடல் பிரிவின் கீழ்ப் பகுதியில் தோன்றும்"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"மொபைல் அமைப்புகளின் அடிப்படையில் ஒலிக்கவோ அதிரவோ செய்யும்"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"மொபைல் அமைப்புகளின் அடிப்படையில் ஒலிக்கவோ அதிரவோ செய்யும். <xliff:g id="APP_NAME">%1$s</xliff:g> இலிருந்து வரும் உரையாடல்கள் இயல்பாகவே குமிழாகத் தோன்றும்."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"இந்த உள்ளடக்கத்திற்கான மிதக்கும் ஷார்ட்கட் மூலம் உங்கள் கவனத்தைப் பெற்றிருக்கும்."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"உரையாடல் பிரிவின் மேற்பகுதியில் மிதக்கும் குமிழாகத் தோன்றும். பூட்டுத் திரையின் மேல் சுயவிவரப் படத்தைக் காட்டும்"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"அமைப்புகள்"</string> <string name="notification_priority_title" msgid="2079708866333537093">"முன்னுரிமை"</string> <string name="no_shortcut" msgid="7176375126961212514">"உரையாடல் சார்ந்த குறிப்பிட்ட அமைப்புகளை <xliff:g id="APP_NAME">%1$s</xliff:g> ஆதரிக்காது"</string> diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml index ea991a37a7ca..2fe2bd8e8c1b 100644 --- a/packages/SystemUI/res/values-te/strings.xml +++ b/packages/SystemUI/res/values-te/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్కు నింపేలా జూమ్ చేయండి"</string> <string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్కు నింపేలా విస్తరించండి"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్షాట్"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"మరిన్ని ఆప్షన్ల కోసం మీ ఫోన్ను అన్లాక్ చేయండి"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"మరిన్ని ఆప్షన్ల కోసం మీ టాబ్లెట్ను అన్లాక్ చేయండి"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"మరిన్ని ఆప్షన్ల కోసం మీ పరికరాన్ని అన్లాక్ చేయండి"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్ను పంపారు"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"స్థానం GPS ద్వారా సెట్ చేయబడింది"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"స్థాన అభ్యర్థనలు సక్రియంగా ఉన్నాయి"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"సెన్సార్లు ఆఫ్ యాక్టివ్లో ఉంది"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"మీడియా యాక్టివ్గా ఉంది"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"అన్ని నోటిఫికేషన్లను క్లియర్ చేయండి."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"నిర్వహించండి"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"చరిత్ర"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"ఇన్కమింగ్"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"నిశ్శబ్దం"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"నోటిఫికేషన్లు"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"సంభాషణలు"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"అన్ని నిశ్శబ్ద నోటిఫికేషన్లను క్లియర్ చేస్తుంది"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"అంతరాయం కలిగించవద్దు ద్వారా నోటిఫికేషన్లు పాజ్ చేయబడ్డాయి"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"నోటిఫికేషన్లను ఆఫ్ చేయి"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"ఈ యాప్ నుండి నోటిఫికేషన్లను చూపిస్తూ ఉండాలా?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"నిశ్శబ్దం"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ఆటోమేటిక్ సెట్టింగ్"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"బబుల్"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"శబ్దం లేదా వైబ్రేషన్లు ఏవీ లేవు"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"శబ్దం లేదా వైబ్రేషన్ లేదు, సంభాషణ విభాగం దిగువన కనిపిస్తుంది"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"ఫోన్ సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"ఫోన్ సెట్టింగ్ల ఆధారంగా రింగ్ లేదా వైబ్రేట్ కావచ్చు. <xliff:g id="APP_NAME">%1$s</xliff:g> నుండి సంభాషణలు ఆటోమేటిక్గా బబుల్గా కనిపిస్తాయి."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ఫ్లోటింగ్ షార్ట్కట్తో మీ దృష్టిని ఈ కంటెంట్పై నిలిపి ఉంచుతుంది."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"సంభాషణ విభాగం ఎగువన ఉంటుంది, తేలుతున్న బబుల్లాగా కనిపిస్తుంది, లాక్ స్క్రీన్పై ప్రొఫైల్ ఫోటోను ప్రదర్శిస్తుంది"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"సెట్టింగ్లు"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ప్రాధాన్యత"</string> <string name="no_shortcut" msgid="7176375126961212514">"\'సంభాషణ నిర్దిష్ట సెట్టింగ్\'లకు <xliff:g id="APP_NAME">%1$s</xliff:g> సపోర్ట్ చేయదు"</string> diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml index 6f71dd59fdb7..d4aaafb2a1e1 100644 --- a/packages/SystemUI/res/values-th/strings.xml +++ b/packages/SystemUI/res/values-th/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"ขยายจนเต็มหน้าจอ"</string> <string name="compat_mode_off" msgid="7682459748279487945">"ยืดจนเต็มหน้าจอ"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"ภาพหน้าจอ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"ปลดล็อกโทรศัพท์เพื่อดูตัวเลือกเพิ่มเติม"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"ปลดล็อกแท็บเล็ตเพื่อดูตัวเลือกเพิ่มเติม"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"ปลดล็อกอุปกรณ์เพื่อดูตัวเลือกเพิ่มเติม"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ส่งรูปภาพ"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"กำลังบันทึกภาพหน้าจอ..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"กำลังบันทึกภาพหน้าจอ..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"ตำแหน่งที่กำหนดโดย GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"คำขอตำแหน่งที่มีการใช้งาน"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"\"ปิดเซ็นเซอร์\" เปิดใช้งานอยู่"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"กำลังเล่นสื่ออยู่"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"ล้างการแจ้งเตือนทั้งหมด"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"จัดการ"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"ประวัติ"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"เข้ามาใหม่"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"เงียบ"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"การแจ้งเตือน"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"การสนทนา"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"ล้างการแจ้งเตือนแบบไม่มีเสียงทั้งหมด"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"หยุดการแจ้งเตือนชั่วคราวโดย \"ห้ามรบกวน\""</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"ปิดการแจ้งเตือน"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"แสดงการแจ้งเตือนจากแอปนี้ต่อไปไหม"</string> <string name="notification_silence_title" msgid="8608090968400832335">"เงียบ"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ค่าเริ่มต้น"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"บับเบิล"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"ไม่มีเสียงหรือการสั่น"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"ไม่มีเสียงหรือการสั่น และปรากฏต่ำลงมาในส่วนการสนทนา"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"อาจส่งเสียงหรือสั่นโดยขึ้นอยู่กับการตั้งค่าโทรศัพท์ การสนทนาจาก <xliff:g id="APP_NAME">%1$s</xliff:g> จะแสดงเป็นบับเบิลโดยค่าเริ่มต้น"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"ดึงดูดความสนใจของคุณไว้เสมอด้วยทางลัดแบบลอยที่มายังเนื้อหานี้"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"แสดงที่ด้านบนของส่วนการสนทนา ปรากฏเป็นบับเบิลแบบลอย แสดงรูปโปรไฟล์บนหน้าจอล็อก"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"การตั้งค่า"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ลำดับความสำคัญ"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> ไม่รองรับการตั้งค่าเฉพาะสำหรับการสนทนา"</string> diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml index 2b19d1c0a525..417ec5cd8f5a 100644 --- a/packages/SystemUI/res/values-tl/strings.xml +++ b/packages/SystemUI/res/values-tl/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"I-zoom upang punan screen"</string> <string name="compat_mode_off" msgid="7682459748279487945">"I-stretch upang mapuno screen"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Screenshot"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"I-unlock ang iyong telepono para sa higit pang opsyon"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"I-unlock ang iyong tablet para sa higit pang opsyon"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"I-unlock ang iyong device para sa higit pang opsyon"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"nagpadala ng larawan"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Sine-save ang screenshot…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Sine-save ang screenshot…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Lokasyong itinatakda ng GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Aktibo ang mga kahilingan ng lokasyon"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Aktibo ang i-off ang mga sensor"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Aktibo ang media"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"I-clear ang lahat ng notification."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Pamahalaan"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"History"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Papasok"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Naka-silent"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Mga Notification"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Mga Pag-uusap"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"I-clear ang lahat ng silent na notification"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Mga notification na na-pause ng Huwag Istorbohin"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"I-off ang mga notification"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Patuloy na ipakita ang mga notification mula sa app na ito?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Naka-silent"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Default"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bubble"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Walang tunog o pag-vibrate"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Walang tunog o pag-vibrate at lumalabas nang mas mababa sa seksyon ng pag-uusap"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng telepono"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Puwedeng mag-ring o mag-vibrate batay sa mga setting ng telepono. Mga pag-uusap mula sa <xliff:g id="APP_NAME">%1$s</xliff:g> bubble bilang default."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Pinapanatili ang iyong atensyon sa pamamagitan ng lumulutang na shortcut sa content na ito."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Makikita sa itaas ng seksyon ng pag-uusap, lumalabas bilang floating bubble, ipinapakita sa lock screen ang larawan sa profile"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Mga Setting"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Priyoridad"</string> <string name="no_shortcut" msgid="7176375126961212514">"Hindi sinusuportahan ng <xliff:g id="APP_NAME">%1$s</xliff:g> ang mga setting na partikular sa pag-uusap"</string> diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml index be32390302ae..3a5cc3ad9ed4 100644 --- a/packages/SystemUI/res/values-tr/strings.xml +++ b/packages/SystemUI/res/values-tr/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Yakınlaştır (ekranı kaplasın)"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Genişlet (ekran kapansın)"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Ekran görüntüsü"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Diğer seçenekler için telefonunuzun kilidini açın"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Diğer seçenekler için tabletinizin kilidini açın"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Diğer seçenekler için cihazınızın kilidini açın"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"bir resim gönderildi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ekran görüntüsü kaydediliyor..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ekran görüntüsü kaydediliyor..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Konum GPS ile belirlendi"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Konum bilgisi istekleri etkin"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Sensörler kapalı ayarı etkin"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Medya etkin durumda"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Tüm bildirimleri temizle"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Yönet"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Geçmiş"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Gelen"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Sessiz"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Bildirimler"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Görüşmeler"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sessiz bildirimlerin tümünü temizle"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Bildirimler, Rahatsız Etmeyin özelliği tarafından duraklatıldı"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Bildirimleri kapat"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Bu uygulamadan gelen bildirimler gösterilmeye devam edilsin mi?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Sessiz"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Varsayılan"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Baloncuk"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Sessiz veya titreşim yok"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Sessizdir veya titreşim yoktur ve görüşme bölümünün altında görünür"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Telefon ayarlarına bağlı olarak zili çalabilir veya titreyebilir <xliff:g id="APP_NAME">%1$s</xliff:g> adlı uygulamadan görüşmeler varsayılan olarak baloncukla gösterilir."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Kayan kısayolla dikkatinizi bu içerik üzerinde tutar."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Görüşme bölümünün üstünde gösterilir, kayan baloncuk olarak görünür, kilit ekranında profil resmini görüntüler"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Ayarlar"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Öncelik"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>, görüşmeye özgü ayarları desteklemiyor"</string> diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml index 27645407751f..d1944055b212 100644 --- a/packages/SystemUI/res/values-uk/strings.xml +++ b/packages/SystemUI/res/values-uk/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Масштабув. на весь екран"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Розтягнути на весь екран"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Знімок екрана"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Розблокуйте телефон, щоб переглянути інші параметри"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Розблокуйте планшет, щоб переглянути інші параметри"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Розблокуйте пристрій, щоб переглянути інші параметри"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"надіслане зображення"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Збереження знімка екрана..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Збереження знімка екрана..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Місцезнаходження встановлено за допомогою GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Запити про місцезнаходження активні"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Активовано вимкнення датчиків"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Відтворюються медіафайли"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Очистити всі сповіщення."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -525,10 +521,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Керувати"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Історія"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Нові"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Без звуку"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Сповіщення"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Розмови"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Очистити всі беззвучні сповіщення"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Режим \"Не турбувати\" призупинив сповіщення"</string> @@ -723,20 +717,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Вимкнути сповіщення"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Чи показувати сповіщення з цього додатка надалі?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Без звуку"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"За умовчанням"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Спливаюче сповіщення"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Без звуку чи вібрації"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Без звуку чи вібрації, з\'являється нижче в розділі розмов"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Може дзвонити або вібрувати залежно від налаштувань телефона"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Може дзвонити або вібрувати залежно від налаштувань телефона. Показує спливаючі розмови з додатка <xliff:g id="APP_NAME">%1$s</xliff:g> за умовчанням."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Привертає увагу до контенту плаваючим ярликом."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"З\'являється вгорі розділу розмов у спливаючому сповіщенні та показує зображення профілю на заблокованому екрані"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Налаштування"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Пріоритет"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> не підтримує налаштування для чату"</string> diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml index c2e8ea91a6b3..0da2928ea0ee 100644 --- a/packages/SystemUI/res/values-ur/strings.xml +++ b/packages/SystemUI/res/values-ur/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"پوری سکرین پر زوم کریں"</string> <string name="compat_mode_off" msgid="7682459748279487945">"پوری سکرین پر پھیلائیں"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"اسکرین شاٹ"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"مزید اختیارات کے لیے اپنا فون غیر مقفل کریں"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"مزید اختیارات کے لیے اپنا ٹیبلیٹ غیر مقفل کریں"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"مزید اختیارات کے لیے اپنا آلہ غیر مقفل کریں"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ایک تصویر بھیجی"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"اسکرین شاٹ محفوظ ہو رہا ہے…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"مقام متعین کیا گیا بذریعہ GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"مقام کی درخواستیں فعال ہیں"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"سینسرز آف فعال ہے"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"میڈیا سرگرم ہے"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"سبھی اطلاعات صاف کریں۔"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"<xliff:g id="NUMBER">%s</xliff:g> +"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"نظم کریں"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"سرگزشت"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"اِن کمنگ"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"خاموش"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"اطلاعات"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"گفتگوئیں"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"سبھی خاموش اطلاعات کو صاف کریں"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"\'ڈسٹرب نہ کریں\' کے ذریعے اطلاعات کو موقوف کیا گیا"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"اطلاعات کو آف کریں"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"اس ایپ کی طرف سے اطلاعات دکھانا جاری رکھیں؟"</string> <string name="notification_silence_title" msgid="8608090968400832335">"خاموش"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"ڈیفالٹ"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"بلبلہ"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"کوئی آواز یا وائبریشن نہیں"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"کوئی آواز یا وائبریشن نہیں اور گفتگو کے سیکشن میں نیچے ظاہر ہوتا ہے"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"آپ کے آلہ کی ترتیبات کے مطابق وائبریٹ یا گھنٹی بج سکتی ہے"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"فون کی ترتیبات کے مطابق وائبریٹ یا گھنٹی بج سکتی ہے۔ بذریعہ ڈیفالٹ <xliff:g id="APP_NAME">%1$s</xliff:g> بلبلہ سے گفتگوئیں۔"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"اس مواد کے فلوٹنگ شارٹ کٹ کے ساتھ آپ کی توجہ دیتی ہے۔"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"گفتگو کے سیکشن کے اوپری حصے پر دکھاتا ہے، تیرتے بلبلے کی طرح ظاہر ہوتا ہے، لاک اسکرین پر پروفائل تصویر دکھاتا ہے"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"ترتیبات"</string> <string name="notification_priority_title" msgid="2079708866333537093">"ترجیح"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g> گفتگو سے متعلق مخصوص ترتیبات کو سپورٹ نہیں کرتی"</string> diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml index a32fdb22c6bf..ed3001e0f76d 100644 --- a/packages/SystemUI/res/values-uz/strings.xml +++ b/packages/SystemUI/res/values-uz/strings.xml @@ -77,9 +77,6 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Ekranga moslashtirish"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Ekran hajmida cho‘zish"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Skrinshot"</string> - <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Boshqa parametrlar uchun telefoningiz qulfini oching"</string> - <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Boshqa parametrlar uchun planshetingiz qulfini oching"</string> - <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Boshqa parametrlar uchun qurilmangiz qulfini oching"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"rasm yuborildi"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Skrinshot saqlanmoqda…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Skrinshot saqlanmoqda…"</string> diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml index 800b73187052..6c3e17c788d6 100644 --- a/packages/SystemUI/res/values-vi/strings.xml +++ b/packages/SystemUI/res/values-vi/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"T.phóng để lấp đầy m.hình"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Giãn ra để lấp đầy m.hình"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Chụp ảnh màn hình"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Mở khóa điện thoại của bạn để xem thêm tùy chọn"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Mở khóa máy tính bảng của bạn để xem thêm tùy chọn"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Mở khóa thiết bị của bạn để xem thêm tùy chọn"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"đã gửi hình ảnh"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Đang lưu ảnh chụp màn hình..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Đang lưu ảnh chụp màn hình..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Vị trí đặt bởi GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Yêu cầu về thông tin vị trí đang hoạt động"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Tùy chọn tắt cảm biến đang hoạt động"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Nội dung nghe nhìn đang hoạt động"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Xóa tất cả thông báo."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Quản lý"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Lịch sử"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Hiển thị gần đây"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Im lặng"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Thông báo"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Cuộc trò chuyện"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Xóa tất cả thông báo im lặng"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Chế độ Không làm phiền đã tạm dừng thông báo"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Tắt thông báo"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Tiếp tục hiển thị các thông báo từ ứng dụng này?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Im lặng"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Mặc định"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Bong bóng"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Không phát âm thanh hoặc rung"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Không phát âm thanh hoặc rung và xuất hiện phía dưới trong phần cuộc trò chuyện"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Có thể đổ chuông hoặc rung tùy theo phần cài đặt trên điện thoại"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Có thể đổ chuông hoặc rung tùy theo phần cài đặt trên điện thoại. Theo mặc định, các cuộc trò chuyện từ <xliff:g id="APP_NAME">%1$s</xliff:g> được phép hiển thị dưới dạng bong bóng."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Luôn chú ý vào nội dung này bằng phím tắt nổi."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Hiển thị cuộc trò chuyện ở đầu phần cuộc trò chuyện và dưới dạng bong bóng nổi, hiển thị ảnh hồ sơ trên màn hình khóa"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Cài đặt"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Mức độ ưu tiên"</string> <string name="no_shortcut" msgid="7176375126961212514">"Ứng dụng <xliff:g id="APP_NAME">%1$s</xliff:g> không hỗ trợ tùy chọn cài đặt dành riêng cho cuộc trò chuyện"</string> diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml index 97be514b06f4..cfa8e859b3dc 100644 --- a/packages/SystemUI/res/values-zh-rCN/strings.xml +++ b/packages/SystemUI/res/values-zh-rCN/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"缩放以填满屏幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"拉伸以填满屏幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"屏幕截图"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解锁手机即可查看更多选项"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解锁平板电脑即可查看更多选项"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解锁设备即可查看更多选项"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"发送了一张图片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在保存屏幕截图..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在保存屏幕截图..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"已通过GPS确定位置"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"应用发出了有效位置信息请求"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"传感器已关闭"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"正在播放媒体内容"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"清除所有通知。"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"历史记录"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"静音"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"对话"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有无声通知"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"勿扰模式暂停的通知"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"关闭通知"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"要继续显示来自此应用的通知吗?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"静音"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"默认"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"气泡"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"不发出提示音也不振动"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"不发出提示音也不振动,显示在对话部分的靠下位置"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"可能会响铃或振动(取决于手机设置)"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能会响铃或振动(取决于手机设置)。默认情况下,来自<xliff:g id="APP_NAME">%1$s</xliff:g>的对话会以对话泡的形式显示。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"通过可链接到这项内容的浮动快捷方式吸引您的注意。"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"以悬浮对话泡形式显示在对话部分顶部,如果设备处于锁定状态,在锁定屏幕上显示个人资料照片"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"设置"</string> <string name="notification_priority_title" msgid="2079708866333537093">"优先"</string> <string name="no_shortcut" msgid="7176375126961212514">"<xliff:g id="APP_NAME">%1$s</xliff:g>不支持对话专用设置"</string> diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml index a8c6c52ff2a8..e3e7d3702389 100644 --- a/packages/SystemUI/res/values-zh-rHK/strings.xml +++ b/packages/SystemUI/res/values-zh-rHK/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"螢幕截圖"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機以存取更多選項"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦以存取更多選項"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置以存取更多選項"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"已傳送圖片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕擷取畫面..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕擷取畫面..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS 已定位"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"位置要求啟動中"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"已啟用「感應器關閉」"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"播緊媒體"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"清除所有通知。"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"靜音"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「請勿騷擾」模式已將通知暫停"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"關閉通知"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"要繼續顯示此應用程式的通知嗎?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"預設"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"氣泡"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"無音效或震動"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"無音效或震動,並在對話部分的較低位置顯示"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"可能會根據手機設定發出鈴聲或震動"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能會根據手機設定發出鈴聲或震動。「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會預設以對話氣泡顯示。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"為此內容建立浮動捷徑以保持注意力。"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"在對話部分的頂部以浮動對話氣泡顯示,並在上鎖畫面顯示個人檔案相片"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string> <string name="notification_priority_title" msgid="2079708866333537093">"重要"</string> <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string> diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml index 0e8e13312b6b..382ce68a1df8 100644 --- a/packages/SystemUI/res/values-zh-rTW/strings.xml +++ b/packages/SystemUI/res/values-zh-rTW/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"放大為全螢幕"</string> <string name="compat_mode_off" msgid="7682459748279487945">"放大為全螢幕"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"擷取螢幕畫面"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"解鎖手機可查看更多選項"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"解鎖平板電腦可查看更多選項"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"解鎖裝置可查看更多選項"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"傳送了一張圖片"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"正在儲存螢幕截圖…"</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"正在儲存螢幕截圖…"</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"GPS 已定位"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"有位置資訊要求"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"感應器已關閉"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"正在播放媒體"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"清除所有通知。"</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"管理"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"記錄"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"收到的通知"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"靜音"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"通知"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"對話"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"清除所有靜音通知"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"「零打擾」模式已將通知設為暫停"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"關閉通知"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"要繼續顯示這個應用程式的通知嗎?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"靜音"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"預設"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"泡泡"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"不震動或發出聲音"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"不震動或發出聲音,並顯示在對話部分的下方"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"可能會根據手機的設定響鈴或震動"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"可能會根據手機的設定響鈴或震動。根據預設,來自「<xliff:g id="APP_NAME">%1$s</xliff:g>」的對話會以對話框形式顯示。"</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"利用浮動式捷徑快速存取這項內容。"</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"以浮動對話框的形式顯示在對話部分的頂端。如果裝置處於鎖定狀態,則在螢幕鎖定畫面上顯示個人資料相片"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"設定"</string> <string name="notification_priority_title" msgid="2079708866333537093">"優先"</string> <string name="no_shortcut" msgid="7176375126961212514">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」不支援對話專用設定"</string> diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml index 5a19f62bbb2c..01a057ef51c8 100644 --- a/packages/SystemUI/res/values-zu/strings.xml +++ b/packages/SystemUI/res/values-zu/strings.xml @@ -77,12 +77,9 @@ <string name="compat_mode_on" msgid="4963711187149440884">"Sondeza ukugcwalisa isikrini"</string> <string name="compat_mode_off" msgid="7682459748279487945">"Nweba ukugcwalisa isikrini"</string> <string name="global_action_screenshot" msgid="2760267567509131654">"Isithombe-skrini"</string> - <!-- no translation found for global_action_lock_message (4466026255205186456) --> - <skip /> - <!-- no translation found for global_action_lock_message (7621167597240332986) --> - <skip /> - <!-- no translation found for global_action_lock_message (538790401275363781) --> - <skip /> + <string name="global_action_lock_message" product="default" msgid="4466026255205186456">"Vula ifoni yakho ukuthola izinketho ezengeziwe"</string> + <string name="global_action_lock_message" product="tablet" msgid="7621167597240332986">"Vula ithebulethi yakho ukuthola izinketho ezengeziwe"</string> + <string name="global_action_lock_message" product="device" msgid="538790401275363781">"Vula idivayisi yakho ukuthola izinketho ezengeziwe"</string> <string name="remote_input_image_insertion_text" msgid="4850791636452521123">"uthumele isithombe"</string> <string name="screenshot_saving_ticker" msgid="6519186952674544916">"Ilondoloz umfanekiso weskrini..."</string> <string name="screenshot_saving_title" msgid="2298349784913287333">"Ilondoloz umfanekiso weskrini..."</string> @@ -329,8 +326,7 @@ <string name="gps_notification_found_text" msgid="3145873880174658526">"Indawo ihlelwe i-GPS"</string> <string name="accessibility_location_active" msgid="2845747916764660369">"Izicelo zendawo ziyasebenza"</string> <string name="accessibility_sensors_off_active" msgid="2619725434618911551">"Izinzwa zivalwe kokusebenzayo"</string> - <!-- no translation found for accessibility_media_active (4942087422908239969) --> - <skip /> + <string name="accessibility_media_active" msgid="4942087422908239969">"Imidiya iyasebenza"</string> <string name="accessibility_clear_all" msgid="970525598287244592">"Susa zonke izaziso."</string> <string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string> <plurals name="notification_group_overflow_description" formatted="false" msgid="91483442850649192"> @@ -519,10 +515,8 @@ <string name="manage_notifications_text" msgid="6885645344647733116">"Phatha"</string> <string name="manage_notifications_history_text" msgid="57055985396576230">"Umlando"</string> <string name="notification_section_header_incoming" msgid="5295312809341711367">"Okungenayo"</string> - <!-- no translation found for notification_section_header_gentle (6804099527336337197) --> - <skip /> - <!-- no translation found for notification_section_header_alerting (5581175033680477651) --> - <skip /> + <string name="notification_section_header_gentle" msgid="6804099527336337197">"Kuthulile"</string> + <string name="notification_section_header_alerting" msgid="5581175033680477651">"Izaziso"</string> <string name="notification_section_header_conversations" msgid="821834744538345661">"Izingxoxo"</string> <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"Sula zonke izaziso ezithulile"</string> <string name="dnd_suppressing_shade_text" msgid="5588252250634464042">"Izaziso zimiswe okwesikhashana ukungaphazamisi"</string> @@ -717,20 +711,14 @@ <string name="inline_turn_off_notifications" msgid="8543989584403106071">"Vala izaziso"</string> <string name="inline_keep_showing_app" msgid="4393429060390649757">"Qhubeka nokubonisa izaziso kusuka kulolu hlelo lokusebenza?"</string> <string name="notification_silence_title" msgid="8608090968400832335">"Kuthulile"</string> - <!-- no translation found for notification_alert_title (3656229781017543655) --> - <skip /> + <string name="notification_alert_title" msgid="3656229781017543655">"Okuzenzekelayo"</string> <string name="notification_bubble_title" msgid="8330481035191903164">"Ibhamuza"</string> - <!-- no translation found for notification_channel_summary_low (4860617986908931158) --> - <skip /> - <!-- no translation found for notification_conversation_summary_low (1734433426085468009) --> - <skip /> - <!-- no translation found for notification_channel_summary_default (3282930979307248890) --> - <skip /> - <!-- no translation found for notification_channel_summary_default_with_bubbles (1782419896613644568) --> - <skip /> + <string name="notification_channel_summary_low" msgid="4860617986908931158">"Awukho umsindo noma ukudlidliza"</string> + <string name="notification_conversation_summary_low" msgid="1734433426085468009">"Awukho umsindo noma ukudlidliza futhi ivela ngezansi esigabeni sengxoxo"</string> + <string name="notification_channel_summary_default" msgid="3282930979307248890">"Ingase ikhale noma idlidlize kuya ngamasethingi wefoni yakho"</string> + <string name="notification_channel_summary_default_with_bubbles" msgid="1782419896613644568">"Ingase ikhale noma idlidlize kuya ngamasethingi wefoni yakho. Izingxoxo ezivela ku-<xliff:g id="APP_NAME">%1$s</xliff:g> ziba yibhamuza ngokuzenzakalela."</string> <string name="notification_channel_summary_bubble" msgid="7235935211580860537">"Igcina ukunaka kwakho ngesinqamuleli esintantayo kulokhu okuqukethwe."</string> - <!-- no translation found for notification_channel_summary_priority (7952654515769021553) --> - <skip /> + <string name="notification_channel_summary_priority" msgid="7952654515769021553">"Iboniswa ngenhla kwesigaba sengxoxo, ivela njengebhamuza elintantayo, ibonisa isithombe sephrofayela kukukhiya isikrini"</string> <string name="notification_conversation_channel_settings" msgid="2409977688430606835">"Izilungiselelo"</string> <string name="notification_priority_title" msgid="2079708866333537093">"Okubalulekile"</string> <string name="no_shortcut" msgid="7176375126961212514">"I-<xliff:g id="APP_NAME">%1$s</xliff:g> ayisekeli amasethingi athile engxoxo"</string> diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 07de70152b2a..7f1763d2dec1 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -221,7 +221,7 @@ <dimen name="notification_guts_button_horizontal_spacing">8dp</dimen> <dimen name="notification_guts_conversation_header_height">84dp</dimen> - <dimen name="notification_guts_conversation_icon_size">52dp</dimen> + <dimen name="notification_guts_conversation_icon_size">56dp</dimen> <dimen name="notification_guts_conversation_action_height">56dp</dimen> <dimen name="notification_guts_conversation_action_text_padding_start">32dp</dimen> @@ -907,6 +907,8 @@ <dimen name="screen_pinning_nav_highlight_size">56dp</dimen> <!-- Screen pinning inner nav bar outer circle size --> <dimen name="screen_pinning_nav_highlight_outer_size">84dp</dimen> + <!-- Screen pinning description bullet gap width --> + <dimen name="screen_pinning_description_bullet_gap_width">6sp</dimen> <!-- Padding to be used on the bottom of the fingerprint icon on Keyguard so it better aligns with the other icons. --> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index f7f1ef6f3746..e567b518f7f8 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -212,13 +212,6 @@ <!-- Power menu item for taking a screenshot [CHAR LIMIT=20]--> <string name="global_action_screenshot">Screenshot</string> - <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> - <string name="global_action_lock_message" product="default">Unlock your phone for more options</string> - <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> - <string name="global_action_lock_message" product="tablet">Unlock your tablet for more options</string> - <!-- Text shown when viewing global actions while phone is locked and additional controls are hidden [CHAR LIMIT=NONE] --> - <string name="global_action_lock_message" product="device">Unlock your device for more options</string> - <!-- text to show in place of RemoteInput images when they cannot be shown. [CHAR LIMIT=50] --> <string name="remote_input_image_insertion_text">sent an image</string> @@ -797,9 +790,6 @@ <!-- Accessibility text describing sensors off active. [CHAR LIMIT=NONE] --> <string name="accessibility_sensors_off_active">Sensors off active</string> - <!-- Accessibility text describing that media is playing. [CHAR LIMIT=NONE] --> - <string name="accessibility_media_active">Media is active</string> - <!-- Content description of the clear button in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] --> <string name="accessibility_clear_all">Clear all notifications.</string> @@ -1522,7 +1512,7 @@ <string name="accessibility_output_chooser">Switch output device</string> <!-- Screen pinning dialog title. --> - <string name="screen_pinning_title">Screen is pinned</string> + <string name="screen_pinning_title">App is pinned</string> <!-- Screen pinning dialog description. --> <string name="screen_pinning_description">This keeps it in view until you unpin. Touch & hold Back and Overview to unpin.</string> <string name="screen_pinning_description_recents_invisible">This keeps it in view until you unpin. Touch & hold Back and Home to unpin.</string> @@ -1530,20 +1520,24 @@ <!-- Screen pinning dialog description. --> <string name="screen_pinning_description_accessible">This keeps it in view until you unpin. Touch & hold Overview to unpin.</string> <string name="screen_pinning_description_recents_invisible_accessible">This keeps it in view until you unpin. Touch & hold Home to unpin.</string> + <!-- Screen pinning security warning: personal data, email, contacts may be exposed while screen is pinned. [CHAR LIMIT=NONE] --> + <string name="screen_pinning_exposes_personal_data">Personal data may be accessible (such as contacts and email content).</string> + <!-- Screen pinning security warning: a pinned app can still launch other apps. [CHAR LIMIT=NONE] --> + <string name="screen_pinning_can_open_other_apps">Pinned app may open other apps.</string> <!-- Notify use that they are in Lock-to-app --> - <string name="screen_pinning_toast">To unpin this screen, touch & hold Back and Overview + <string name="screen_pinning_toast">To unpin this app, touch & hold Back and Overview buttons</string> - <string name="screen_pinning_toast_recents_invisible">To unpin this screen, touch & hold Back + <string name="screen_pinning_toast_recents_invisible">To unpin this app, touch & hold Back and Home buttons</string> <!-- Notify (in toast) user how to unpin screen in gesture navigation mode [CHAR LIMIT=NONE] --> - <string name="screen_pinning_toast_gesture_nav">To unpin this screen, swipe up & hold</string> + <string name="screen_pinning_toast_gesture_nav">To unpin this app, swipe up & hold</string> <!-- Screen pinning positive response. --> <string name="screen_pinning_positive">Got it</string> <!-- Screen pinning negative response. --> <string name="screen_pinning_negative">No thanks</string> <!-- Enter/Exiting screen pinning indication. --> - <string name="screen_pinning_start">Screen pinned</string> - <string name="screen_pinning_exit">Screen unpinned</string> + <string name="screen_pinning_start">App pinned</string> + <string name="screen_pinning_exit">App unpinned</string> <!-- Hide quick settings tile confirmation title --> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 52ace2bd409b..07ba5eb1802d 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -396,6 +396,7 @@ <style name="Theme.SystemUI.Dialog.Alert" parent="@*android:style/Theme.DeviceDefault.Light.Dialog.Alert" /> <style name="Theme.SystemUI.Dialog.GlobalActions" parent="@android:style/Theme.DeviceDefault.Light.NoActionBar.Fullscreen"> + <item name="android:colorError">@*android:color/error_color_material_dark</item> <item name="android:windowIsFloating">true</item> </style> @@ -573,6 +574,7 @@ <item name="android:textColor">?attr/wallpaperTextColor</item> <item name="android:textAllCaps">false</item> <item name="android:textSize">14sp</item> + <item name="android:minWidth">0dp</item> </style> <style name="TextAppearance.HeadsUpStatusBarText" diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java index f1b401e77fbc..15eda0689101 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/Bubble.java @@ -15,7 +15,7 @@ */ package com.android.systemui.bubbles; - +import static android.app.Notification.FLAG_BUBBLE; import static android.os.AsyncTask.Status.FINISHED; import static android.view.Display.INVALID_DISPLAY; @@ -27,6 +27,7 @@ import android.app.Notification; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; +import android.content.pm.ApplicationInfo; import android.content.pm.LauncherApps; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; @@ -55,9 +56,13 @@ import java.util.Objects; class Bubble implements BubbleViewProvider { private static final String TAG = "Bubble"; + /** + * NotificationEntry associated with the bubble. A null value implies this bubble is loaded + * from disk. + */ + @Nullable private NotificationEntry mEntry; private final String mKey; - private final String mGroupId; private long mLastUpdated; private long mLastAccessed; @@ -69,6 +74,8 @@ class Bubble implements BubbleViewProvider { /** Whether flyout text should be suppressed, regardless of any other flags or state. */ private boolean mSuppressFlyout; + /** Whether this bubble should auto expand regardless of the normal flag, used for overflow. */ + private boolean mShouldAutoExpand; // Items that are typically loaded later private String mAppName; @@ -95,18 +102,18 @@ class Bubble implements BubbleViewProvider { private Bitmap mBadgedImage; private int mDotColor; private Path mDotPath; + private int mFlags; - - public static String groupId(NotificationEntry entry) { - UserHandle user = entry.getSbn().getUser(); - return user.getIdentifier() + "|" + entry.getSbn().getPackageName(); - } - - // TODO: Decouple Bubble from NotificationEntry and transform ShortcutInfo into Bubble - Bubble(ShortcutInfo shortcutInfo) { + /** + * Create a bubble with limited information based on given {@link ShortcutInfo}. + * Note: Currently this is only being used when the bubble is persisted to disk. + */ + Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo) { + Objects.requireNonNull(key); + Objects.requireNonNull(shortcutInfo); mShortcutInfo = shortcutInfo; - mKey = shortcutInfo.getId(); - mGroupId = shortcutInfo.getId(); + mKey = key; + mFlags = 0; } /** Used in tests when no UI is required. */ @@ -116,8 +123,8 @@ class Bubble implements BubbleViewProvider { mEntry = e; mKey = e.getKey(); mLastUpdated = e.getSbn().getPostTime(); - mGroupId = groupId(e); mSuppressionListener = listener; + mFlags = e.getSbn().getNotification().flags; } @Override @@ -125,16 +132,22 @@ class Bubble implements BubbleViewProvider { return mKey; } + @Nullable public NotificationEntry getEntry() { return mEntry; } - public String getGroupId() { - return mGroupId; + @Nullable + public UserHandle getUser() { + if (mEntry != null) return mEntry.getSbn().getUser(); + if (mShortcutInfo != null) return mShortcutInfo.getUserHandle(); + return null; } public String getPackageName() { - return mEntry.getSbn().getPackageName(); + return mEntry == null + ? mShortcutInfo == null ? null : mShortcutInfo.getPackage() + : mEntry.getSbn().getPackageName(); } @Override @@ -178,6 +191,18 @@ class Bubble implements BubbleViewProvider { return mExpandedView; } + @Nullable + public String getTitle() { + final CharSequence titleCharSeq; + if (mEntry == null) { + titleCharSeq = null; + } else { + titleCharSeq = mEntry.getSbn().getNotification().extras.getCharSequence( + Notification.EXTRA_TITLE); + } + return titleCharSeq != null ? titleCharSeq.toString() : null; + } + /** * Call when the views should be removed, ensure this is called to clean up ActivityView * content. @@ -218,7 +243,8 @@ class Bubble implements BubbleViewProvider { void inflate(BubbleViewInfoTask.Callback callback, Context context, BubbleStackView stackView, - BubbleIconFactory iconFactory) { + BubbleIconFactory iconFactory, + boolean skipInflation) { if (isBubbleLoading()) { mInflationTask.cancel(true /* mayInterruptIfRunning */); } @@ -226,6 +252,7 @@ class Bubble implements BubbleViewProvider { context, stackView, iconFactory, + skipInflation, callback); if (mInflateSynchronously) { mInflationTask.onPostExecute(mInflationTask.doInBackground()); @@ -297,20 +324,13 @@ class Bubble implements BubbleViewProvider { } /** - * @return the newer of {@link #getLastUpdateTime()} and {@link #getLastAccessTime()} + * @return the last time this bubble was updated or accessed, whichever is most recent. */ long getLastActivity() { return Math.max(mLastUpdated, mLastAccessed); } /** - * @return the timestamp in milliseconds of the most recent notification entry for this bubble - */ - long getLastUpdateTime() { - return mLastUpdated; - } - - /** * @return if the bubble was ever expanded */ boolean getWasAccessed() { @@ -345,6 +365,7 @@ class Bubble implements BubbleViewProvider { * Whether this notification should be shown in the shade. */ boolean showInShade() { + if (mEntry == null) return false; return !shouldSuppressNotification() || !mEntry.isClearable(); } @@ -352,8 +373,8 @@ class Bubble implements BubbleViewProvider { * Sets whether this notification should be suppressed in the shade. */ void setSuppressNotification(boolean suppressNotification) { + if (mEntry == null) return; boolean prevShowInShade = showInShade(); - Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); int flags = data.getFlags(); if (suppressNotification) { @@ -384,6 +405,7 @@ class Bubble implements BubbleViewProvider { */ @Override public boolean showDot() { + if (mEntry == null) return false; return mShowBubbleUpdateDot && !mEntry.shouldSuppressNotificationDot() && !shouldSuppressNotification(); @@ -393,6 +415,7 @@ class Bubble implements BubbleViewProvider { * Whether the flyout for the bubble should be shown. */ boolean showFlyout() { + if (mEntry == null) return false; return !mSuppressFlyout && !mEntry.shouldSuppressPeek() && !shouldSuppressNotification() && !mEntry.shouldSuppressNotificationList(); @@ -411,16 +434,8 @@ class Bubble implements BubbleViewProvider { return mFlyoutMessage; } - /** - * Returns whether the notification for this bubble is a foreground service. It shows that this - * is an ongoing bubble. - */ - boolean isOngoing() { - int flags = mEntry.getSbn().getNotification().flags; - return (flags & Notification.FLAG_FOREGROUND_SERVICE) != 0; - } - float getDesiredHeight(Context context) { + if (mEntry == null) return 0; Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); boolean useRes = data.getDesiredHeightResId() != 0; if (useRes) { @@ -434,6 +449,7 @@ class Bubble implements BubbleViewProvider { } String getDesiredHeightString() { + if (mEntry == null) return String.valueOf(0); Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); boolean useRes = data.getDesiredHeightResId() != 0; if (useRes) { @@ -450,11 +466,13 @@ class Bubble implements BubbleViewProvider { * To populate the icon use {@link LauncherApps#getShortcutIconDrawable(ShortcutInfo, int)}. */ boolean usingShortcutInfo() { - return mEntry.getBubbleMetadata().getShortcutId() != null; + return mEntry != null && mEntry.getBubbleMetadata().getShortcutId() != null + || mShortcutInfo != null; } @Nullable PendingIntent getBubbleIntent() { + if (mEntry == null) return null; Notification.BubbleMetadata data = mEntry.getBubbleMetadata(); if (data != null) { return data.getIntent(); @@ -462,16 +480,32 @@ class Bubble implements BubbleViewProvider { return null; } - Intent getSettingsIntent() { + Intent getSettingsIntent(final Context context) { final Intent intent = new Intent(Settings.ACTION_APP_NOTIFICATION_BUBBLE_SETTINGS); intent.putExtra(Settings.EXTRA_APP_PACKAGE, getPackageName()); - intent.putExtra(Settings.EXTRA_APP_UID, mEntry.getSbn().getUid()); + final int uid = getUid(context); + if (uid != -1) { + intent.putExtra(Settings.EXTRA_APP_UID, uid); + } intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP); return intent; } + private int getUid(final Context context) { + if (mEntry != null) return mEntry.getSbn().getUid(); + final PackageManager pm = context.getPackageManager(); + if (pm == null) return -1; + try { + final ApplicationInfo info = pm.getApplicationInfo(mShortcutInfo.getPackage(), 0); + return info.uid; + } catch (PackageManager.NameNotFoundException e) { + Log.e(TAG, "cannot find uid", e); + } + return -1; + } + private int getDimenForPackageUser(Context context, int resId, String pkg, int userId) { PackageManager pm = context.getPackageManager(); Resources r; @@ -493,13 +527,32 @@ class Bubble implements BubbleViewProvider { } private boolean shouldSuppressNotification() { + if (mEntry == null) return false; return mEntry.getBubbleMetadata() != null && mEntry.getBubbleMetadata().isNotificationSuppressed(); } boolean shouldAutoExpand() { + if (mEntry == null) return false; Notification.BubbleMetadata metadata = mEntry.getBubbleMetadata(); - return metadata != null && metadata.getAutoExpandBubble(); + return (metadata != null && metadata.getAutoExpandBubble()) || mShouldAutoExpand; + } + + void setShouldAutoExpand(boolean shouldAutoExpand) { + mShouldAutoExpand = shouldAutoExpand; + } + + public boolean isBubble() { + if (mEntry == null) return (mFlags & FLAG_BUBBLE) != 0; + return (mEntry.getSbn().getNotification().flags & FLAG_BUBBLE) != 0; + } + + public void enable(int option) { + mFlags |= option; + } + + public void disable(int option) { + mFlags &= ~option; } @Override @@ -562,7 +615,7 @@ class Bubble implements BubbleViewProvider { normalX, normalY, this.showInShade(), - this.isOngoing(), + false /* isOngoing (unused) */, false /* isAppForeground (unused) */); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java index eb4ba6f682af..f05d547edd0c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java @@ -42,6 +42,7 @@ import static java.lang.annotation.ElementType.LOCAL_VARIABLE; import static java.lang.annotation.ElementType.PARAMETER; import static java.lang.annotation.RetentionPolicy.SOURCE; +import android.annotation.NonNull; import android.annotation.UserIdInt; import android.app.ActivityManager.RunningTaskInfo; import android.app.INotificationManager; @@ -113,6 +114,7 @@ import java.lang.annotation.Retention; import java.lang.annotation.Target; import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * Bubbles are a special type of content that can "float" on top of other apps or System UI. @@ -243,13 +245,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * This can happen when an app cancels a bubbled notification or when the user dismisses a * bubble. */ - void removeNotification(NotificationEntry entry, int reason); + void removeNotification(@NonNull NotificationEntry entry, int reason); /** * Called when a bubbled notification has changed whether it should be * filtered from the shade. */ - void invalidateNotifications(String reason); + void invalidateNotifications(@NonNull String reason); /** * Called on a bubbled entry that has been removed when there are no longer @@ -259,7 +261,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * removes all remnants of the group's summary from the notification pipeline. * TODO: (b/145659174) Only old pipeline needs this - delete post-migration. */ - void maybeCancelSummary(NotificationEntry entry); + void maybeCancelSummary(@NonNull NotificationEntry entry); } /** @@ -655,7 +657,13 @@ public class BubbleController implements ConfigurationController.ConfigurationLi try { mAddedToWindowManager = false; - mWindowManager.removeView(mStackView); + if (mStackView != null) { + mWindowManager.removeView(mStackView); + mStackView.removeView(mBubbleScrim); + mStackView = null; + } else { + Log.w(TAG, "StackView added to WindowManager, but was null when removing!"); + } } catch (IllegalArgumentException e) { // This means the stack has already been removed - it shouldn't happen, but ignore if it // does, since we wanted it removed anyway. @@ -729,8 +737,9 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mNotificationEntryManager.getActiveNotificationsForCurrentUser()) { if (savedBubbleKeys.contains(e.getKey()) && mNotificationInterruptStateProvider.shouldBubbleUp(e) + && e.isBubble() && canLaunchInActivityView(mContext, e)) { - updateBubble(e, /* suppressFlyout= */ true); + updateBubble(e, true /* suppressFlyout */, false /* showInShade */); } } // Finally, remove the entries for this user now that bubbles are restored. @@ -754,10 +763,12 @@ public class BubbleController implements ConfigurationController.ConfigurationLi mBubbleIconFactory = new BubbleIconFactory(mContext); // Reload each bubble for (Bubble b: mBubbleData.getBubbles()) { - b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory); + b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory, + false /* skipInflation */); } for (Bubble b: mBubbleData.getOverflowBubbles()) { - b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory); + b.inflate(null /* callback */, mContext, mStackView, mBubbleIconFactory, + false /* skipInflation */); } } @@ -850,19 +861,28 @@ public class BubbleController implements ConfigurationController.ConfigurationLi /** * Request the stack expand if needed, then select the specified Bubble as current. + * If no bubble exists for this entry, one is created. * - * @param notificationKey the notification key for the bubble to be selected + * @param entry the notification for the bubble to be selected */ - public void expandStackAndSelectBubble(String notificationKey) { - Bubble bubble = mBubbleData.getBubbleInStackWithKey(notificationKey); - if (bubble == null) { - bubble = mBubbleData.getOverflowBubbleWithKey(notificationKey); + public void expandStackAndSelectBubble(NotificationEntry entry) { + String key = entry.getKey(); + Bubble bubble = mBubbleData.getBubbleInStackWithKey(key); + if (bubble != null) { + mBubbleData.setSelectedBubble(bubble); + } else { + bubble = mBubbleData.getOverflowBubbleWithKey(key); if (bubble != null) { - mBubbleData.promoteBubbleFromOverflow(bubble, mStackView, mBubbleIconFactory); + 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 */); } - } else if (bubble.getEntry().isBubble()){ - mBubbleData.setSelectedBubble(bubble); } + mBubbleData.setExpanded(true); } @@ -882,17 +902,33 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * @param notif the notification associated with this bubble. */ void updateBubble(NotificationEntry notif) { - updateBubble(notif, false /* suppressFlyout */); + updateBubble(notif, false /* suppressFlyout */, true /* showInShade */); } - void updateBubble(NotificationEntry notif, boolean suppressFlyout) { - updateBubble(notif, suppressFlyout, true /* showInShade */); + /** + * Fills the overflow bubbles by loading them from disk. + */ + void loadOverflowBubblesFromDisk() { + if (!mBubbleData.getOverflowBubbles().isEmpty()) { + // we don't need to load overflow bubbles from disk if it is already in memory + return; + } + mDataRepository.loadBubbles((bubbles) -> { + bubbles.forEach(bubble -> { + if (mBubbleData.getBubbles().contains(bubble)) { + // if the bubble is already active, there's no need to push it to overflow + return; + } + bubble.inflate((b) -> mBubbleData.overflowBubble(DISMISS_AGED, bubble), + mContext, mStackView, mBubbleIconFactory, true /* skipInflation */); + }); + return null; + }); } 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(); @@ -901,7 +937,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi bubble.setInflateSynchronously(mInflateSynchronously); bubble.inflate( b -> { - mBubbleData.notificationEntryUpdated(b, suppressFlyout, showInShade); + mBubbleData.notificationEntryUpdated(b, suppressFlyout, + showInShade); if (bubble.getBubbleIntent() == null) { return; } @@ -911,11 +948,11 @@ public class BubbleController implements ConfigurationController.ConfigurationLi return; } mHandler.post( - () -> removeBubble(bubble.getEntry(), + () -> removeBubble(bubble.getKey(), BubbleController.DISMISS_INVALID_INTENT)); }); }, - mContext, mStackView, mBubbleIconFactory); + mContext, mStackView, mBubbleIconFactory, false /* skipInflation */); } /** @@ -927,7 +964,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi * @param entry the notification to change bubble state for. * @param shouldBubble whether the notification should show as a bubble or not. */ - public void onUserChangedBubble(NotificationEntry entry, boolean shouldBubble) { + public void onUserChangedBubble(@Nullable final NotificationEntry entry, boolean shouldBubble) { + if (entry == null) { + return; + } NotificationChannel channel = entry.getChannel(); final String appPkg = entry.getSbn().getPackageName(); final int appUid = entry.getSbn().getUid(); @@ -966,31 +1006,33 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } /** - * Removes the bubble with the given NotificationEntry. + * Removes the bubble with the given key. * <p> * Must be called from the main thread. */ @MainThread - void removeBubble(NotificationEntry entry, int reason) { - if (mBubbleData.hasAnyBubbleWithKey(entry.getKey())) { - mBubbleData.notificationEntryRemoved(entry, reason); + void removeBubble(String key, int reason) { + if (mBubbleData.hasAnyBubbleWithKey(key)) { + mBubbleData.notificationEntryRemoved(key, reason); } } private void onEntryAdded(NotificationEntry entry) { if (mNotificationInterruptStateProvider.shouldBubbleUp(entry) + && entry.isBubble() && canLaunchInActivityView(mContext, entry)) { updateBubble(entry); } } private void onEntryUpdated(NotificationEntry entry) { + // shouldBubbleUp checks canBubble & for bubble metadata boolean shouldBubble = mNotificationInterruptStateProvider.shouldBubbleUp(entry) && canLaunchInActivityView(mContext, entry); if (!shouldBubble && mBubbleData.hasAnyBubbleWithKey(entry.getKey())) { // It was previously a bubble but no longer a bubble -- lets remove it - removeBubble(entry, DISMISS_NO_LONGER_BUBBLE); - } else if (shouldBubble) { + removeBubble(entry.getKey(), DISMISS_NO_LONGER_BUBBLE); + } else if (shouldBubble && entry.isBubble()) { updateBubble(entry); } } @@ -1003,10 +1045,10 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // Remove any associated bubble children with the summary final List<Bubble> bubbleChildren = mBubbleData.getBubblesInGroup(groupKey); for (int i = 0; i < bubbleChildren.size(); i++) { - removeBubble(bubbleChildren.get(i).getEntry(), DISMISS_GROUP_CANCELLED); + removeBubble(bubbleChildren.get(i).getKey(), DISMISS_GROUP_CANCELLED); } } else { - removeBubble(entry, DISMISS_NOTIF_CANCEL); + removeBubble(entry.getKey(), DISMISS_NOTIF_CANCEL); } } @@ -1028,7 +1070,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi rankingMap.getRanking(key, mTmpRanking); boolean isActiveBubble = mBubbleData.hasAnyBubbleWithKey(key); if (isActiveBubble && !mTmpRanking.canBubble()) { - mBubbleData.notificationEntryRemoved(entry, BubbleController.DISMISS_BLOCKED); + mBubbleData.notificationEntryRemoved(entry.getKey(), + BubbleController.DISMISS_BLOCKED); } else if (entry != null && mTmpRanking.isBubble() && !isActiveBubble) { entry.setFlagBubble(true); onEntryUpdated(entry); @@ -1036,24 +1079,45 @@ public class BubbleController implements ConfigurationController.ConfigurationLi } } - private void setIsBubble(Bubble b, boolean isBubble) { + private void setIsBubble(@NonNull final NotificationEntry entry, final boolean isBubble) { + Objects.requireNonNull(entry); if (isBubble) { - b.getEntry().getSbn().getNotification().flags |= FLAG_BUBBLE; + entry.getSbn().getNotification().flags |= FLAG_BUBBLE; } else { - b.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE; + entry.getSbn().getNotification().flags &= ~FLAG_BUBBLE; } try { - mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0); + mBarService.onNotificationBubbleChanged(entry.getKey(), isBubble, 0); } catch (RemoteException e) { // Bad things have happened } } + private void setIsBubble(@NonNull final Bubble b, final boolean isBubble) { + Objects.requireNonNull(b); + if (isBubble) { + b.enable(FLAG_BUBBLE); + } else { + b.disable(FLAG_BUBBLE); + } + if (b.getEntry() != null) { + setIsBubble(b.getEntry(), isBubble); + } else { + try { + mBarService.onNotificationBubbleChanged(b.getKey(), isBubble, 0); + } catch (RemoteException e) { + // Bad things have happened + } + } + } + @SuppressWarnings("FieldCanBeLocal") private final BubbleData.Listener mBubbleDataListener = new BubbleData.Listener() { @Override public void applyUpdate(BubbleData.Update update) { + // Lazy load overflow bubbles from disk + loadOverflowBubblesFromDisk(); // Update bubbles in overflow. if (mOverflowCallback != null) { mOverflowCallback.run(); @@ -1088,23 +1152,27 @@ public class BubbleController implements ConfigurationController.ConfigurationLi // The bubble is now gone & the notification is hidden from the shade, so // time to actually remove it for (NotifCallback cb : mCallbacks) { - cb.removeNotification(bubble.getEntry(), REASON_CANCEL); + if (bubble.getEntry() != null) { + cb.removeNotification(bubble.getEntry(), REASON_CANCEL); + } } } else { - if (bubble.getEntry().isBubble() && bubble.showInShade()) { - setIsBubble(bubble, /* isBubble */ false); + if (bubble.isBubble() && bubble.showInShade()) { + setIsBubble(bubble, false /* isBubble */); } - if (bubble.getEntry().getRow() != null) { + if (bubble.getEntry() != null && bubble.getEntry().getRow() != null) { bubble.getEntry().getRow().updateBubbleButton(); } } } - final String groupKey = bubble.getEntry().getSbn().getGroupKey(); - if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) { - // Time to potentially remove the summary - for (NotifCallback cb : mCallbacks) { - cb.maybeCancelSummary(bubble.getEntry()); + if (bubble.getEntry() != null) { + final String groupKey = bubble.getEntry().getSbn().getGroupKey(); + if (mBubbleData.getBubblesInGroup(groupKey).isEmpty()) { + // Time to potentially remove the summary + for (NotifCallback cb : mCallbacks) { + cb.maybeCancelSummary(bubble.getEntry()); + } } } } @@ -1129,7 +1197,7 @@ public class BubbleController implements ConfigurationController.ConfigurationLi if (update.selectionChanged) { mStackView.setSelectedBubble(update.selectedBubble); - if (update.selectedBubble != null) { + if (update.selectedBubble != null && update.selectedBubble.getEntry() != null) { mNotificationGroupManager.updateSuppression( update.selectedBubble.getEntry()); } @@ -1327,7 +1395,8 @@ public class BubbleController implements ConfigurationController.ConfigurationLi boolean clearedTask, boolean wasVisible) { for (Bubble b : mBubbleData.getBubbles()) { if (b.getDisplayId() == task.displayId) { - expandStackAndSelectBubble(b.getKey()); + mBubbleData.setSelectedBubble(b); + mBubbleData.setExpanded(true); return; } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java index 65d5bebc625d..857f1dd3533c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleData.java @@ -21,12 +21,10 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_DATA; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; -import static java.util.stream.Collectors.toList; - +import android.annotation.NonNull; import android.app.Notification; import android.app.PendingIntent; import android.content.Context; -import android.service.notification.NotificationListenerService; import android.util.Log; import android.util.Pair; import android.view.View; @@ -45,7 +43,6 @@ import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; -import java.util.Map; import java.util.Objects; import javax.inject.Inject; @@ -62,9 +59,6 @@ public class BubbleData { private static final Comparator<Bubble> BUBBLES_BY_SORT_KEY_DESCENDING = Comparator.comparing(BubbleData::sortKey).reversed(); - private static final Comparator<Map.Entry<String, Long>> GROUPS_BY_MAX_SORT_KEY_DESCENDING = - Comparator.<Map.Entry<String, Long>, Long>comparing(Map.Entry::getValue).reversed(); - /** Contains information about changes that have been made to the state of bubbles. */ static final class Update { boolean expandedChanged; @@ -129,8 +123,6 @@ public class BubbleData { // State tracked during an operation -- keeps track of what listener events to dispatch. private Update mStateChange; - private NotificationListenerService.Ranking mTmpRanking; - private TimeSource mTimeSource = System::currentTimeMillis; @Nullable @@ -216,15 +208,14 @@ public class BubbleData { } moveOverflowBubbleToPending(bubble); // Preserve new order for next repack, which sorts by last updated time. - bubble.markUpdatedAt(mTimeSource.currentTimeMillis()); bubble.inflate( b -> { - notificationEntryUpdated(bubble, /* suppressFlyout */ - false, /* showInShade */ true); - setSelectedBubble(bubble); + b.setShouldAutoExpand(true); + b.markUpdatedAt(mTimeSource.currentTimeMillis()); + notificationEntryUpdated(bubble, false /* suppressFlyout */, + true /* showInShade */); }, - mContext, stack, factory); - dispatchPendingChanges(); + mContext, stack, factory, false /* skipInflation */); } void setShowingOverflow(boolean showingOverflow) { @@ -278,7 +269,8 @@ public class BubbleData { } mPendingBubbles.remove(bubble); // No longer pending once we're here Bubble prevBubble = getBubbleInStackWithKey(bubble.getKey()); - suppressFlyout |= !bubble.getEntry().getRanking().visuallyInterruptive(); + suppressFlyout |= bubble.getEntry() == null + || !bubble.getEntry().getRanking().visuallyInterruptive(); if (prevBubble == null) { // Create a new bubble @@ -290,13 +282,13 @@ public class BubbleData { bubble.setSuppressFlyout(suppressFlyout); doUpdate(bubble); } + if (bubble.shouldAutoExpand()) { + bubble.setShouldAutoExpand(false); setSelectedBubbleInternal(bubble); if (!mExpanded) { setExpandedInternal(true); } - } else if (mSelectedBubble == null) { - setSelectedBubbleInternal(bubble); } boolean isBubbleExpandedAndSelected = mExpanded && mSelectedBubble == bubble; @@ -307,11 +299,14 @@ public class BubbleData { dispatchPendingChanges(); } - public void notificationEntryRemoved(NotificationEntry entry, @DismissReason int reason) { + /** + * Called when a notification associated with a bubble is removed. + */ + public void notificationEntryRemoved(String key, @DismissReason int reason) { if (DEBUG_BUBBLE_DATA) { - Log.d(TAG, "notificationEntryRemoved: entry=" + entry + " reason=" + reason); + Log.d(TAG, "notificationEntryRemoved: key=" + key + " reason=" + reason); } - doRemove(entry.getKey(), reason); + doRemove(key, reason); dispatchPendingChanges(); } @@ -359,7 +354,7 @@ public class BubbleData { return bubbleChildren; } for (Bubble b : mBubbles) { - if (groupKey.equals(b.getEntry().getSbn().getGroupKey())) { + if (b.getEntry() != null && groupKey.equals(b.getEntry().getSbn().getGroupKey())) { bubbleChildren.add(b); } } @@ -370,20 +365,11 @@ public class BubbleData { if (DEBUG_BUBBLE_DATA) { Log.d(TAG, "doAdd: " + bubble); } - int minInsertPoint = 0; - boolean newGroup = !hasBubbleWithGroupId(bubble.getGroupId()); - if (isExpanded()) { - // first bubble of a group goes to the beginning, otherwise within the existing group - minInsertPoint = newGroup ? 0 : findFirstIndexForGroup(bubble.getGroupId()); - } - if (insertBubble(minInsertPoint, bubble) < mBubbles.size() - 1) { - mStateChange.orderChanged = true; - } + mBubbles.add(0, bubble); mStateChange.addedBubble = bubble; - + // Adding the first bubble doesn't change the order + mStateChange.orderChanged = mBubbles.size() > 1; if (!isExpanded()) { - mStateChange.orderChanged |= packGroup(findFirstIndexForGroup(bubble.getGroupId())); - // Top bubble becomes selected. setSelectedBubbleInternal(mBubbles.get(0)); } } @@ -406,14 +392,10 @@ public class BubbleData { } mStateChange.updatedBubble = bubble; if (!isExpanded()) { - // while collapsed, update causes re-pack int prevPos = mBubbles.indexOf(bubble); mBubbles.remove(bubble); - int newPos = insertBubble(0, bubble); - if (prevPos != newPos) { - packGroup(newPos); - mStateChange.orderChanged = true; - } + mBubbles.add(0, bubble); + mStateChange.orderChanged = prevPos != 0; setSelectedBubbleInternal(mBubbles.get(0)); } } @@ -470,7 +452,9 @@ public class BubbleData { Bubble newSelected = mBubbles.get(newIndex); setSelectedBubbleInternal(newSelected); } - maybeSendDeleteIntent(reason, bubbleToRemove.getEntry()); + if (bubbleToRemove.getEntry() != null) { + maybeSendDeleteIntent(reason, bubbleToRemove.getEntry()); + } } void overflowBubble(@DismissReason int reason, Bubble bubble) { @@ -581,7 +565,6 @@ public class BubbleData { Log.e(TAG, "Attempt to expand stack without selected bubble!"); return; } - mSelectedBubble.markUpdatedAt(mTimeSource.currentTimeMillis()); mSelectedBubble.markAsAccessedAt(mTimeSource.currentTimeMillis()); mStateChange.orderChanged |= repackAll(); } else if (!mBubbles.isEmpty()) { @@ -596,17 +579,11 @@ public class BubbleData { } if (mBubbles.indexOf(mSelectedBubble) > 0) { // Move the selected bubble to the top while collapsed. - if (!mSelectedBubble.isOngoing() && mBubbles.get(0).isOngoing()) { - // The selected bubble cannot be raised to the first position because - // there is an ongoing bubble there. Instead, force the top ongoing bubble - // to become selected. - setSelectedBubbleInternal(mBubbles.get(0)); - } else { - // Raise the selected bubble (and it's group) up to the front so the selected - // bubble remains on top. + int index = mBubbles.indexOf(mSelectedBubble); + if (index != 0) { mBubbles.remove(mSelectedBubble); mBubbles.add(0, mSelectedBubble); - mStateChange.orderChanged |= packGroup(0); + mStateChange.orderChanged = true; } } } @@ -616,91 +593,12 @@ public class BubbleData { } private static long sortKey(Bubble bubble) { - long key = bubble.getLastUpdateTime(); - if (bubble.isOngoing()) { - // Set 2nd highest bit (signed long int), to partition between ongoing and regular - key |= 0x4000000000000000L; - } - return key; - } - - /** - * Locates and inserts the bubble into a sorted position. The is inserted - * based on sort key, groupId is not considered. A call to {@link #packGroup(int)} may be - * required to keep grouping intact. - * - * @param minPosition the first insert point to consider - * @param newBubble the bubble to insert - * @return the position where the bubble was inserted - */ - private int insertBubble(int minPosition, Bubble newBubble) { - long newBubbleSortKey = sortKey(newBubble); - String previousGroupId = null; - - for (int pos = minPosition; pos < mBubbles.size(); pos++) { - Bubble bubbleAtPos = mBubbles.get(pos); - String groupIdAtPos = bubbleAtPos.getGroupId(); - boolean atStartOfGroup = !groupIdAtPos.equals(previousGroupId); - - if (atStartOfGroup && newBubbleSortKey > sortKey(bubbleAtPos)) { - // Insert before the start of first group which has older bubbles. - mBubbles.add(pos, newBubble); - return pos; - } - previousGroupId = groupIdAtPos; - } - mBubbles.add(newBubble); - return mBubbles.size() - 1; - } - - private boolean hasBubbleWithGroupId(String groupId) { - return mBubbles.stream().anyMatch(b -> b.getGroupId().equals(groupId)); - } - - private int findFirstIndexForGroup(String appId) { - for (int i = 0; i < mBubbles.size(); i++) { - Bubble bubbleAtPos = mBubbles.get(i); - if (bubbleAtPos.getGroupId().equals(appId)) { - return i; - } - } - return 0; - } - - /** - * Starting at the given position, moves all bubbles with the same group id to follow. Bubbles - * at positions lower than {@code position} are unchanged. Relative order within the group - * unchanged. Relative order of any other bubbles are also unchanged. - * - * @param position the position of the first bubble for the group - * @return true if the position of any bubbles has changed as a result - */ - private boolean packGroup(int position) { - if (DEBUG_BUBBLE_DATA) { - Log.d(TAG, "packGroup: position=" + position); - } - Bubble groupStart = mBubbles.get(position); - final String groupAppId = groupStart.getGroupId(); - List<Bubble> moving = new ArrayList<>(); - - // Walk backward, collect bubbles within the group - for (int i = mBubbles.size() - 1; i > position; i--) { - if (mBubbles.get(i).getGroupId().equals(groupAppId)) { - moving.add(0, mBubbles.get(i)); - } - } - if (moving.isEmpty()) { - return false; - } - mBubbles.removeAll(moving); - mBubbles.addAll(position + 1, moving); - return true; + return bubble.getLastActivity(); } /** - * This applies a full sort and group pass to all existing bubbles. The bubbles are grouped - * by groupId. Each group is then sorted by the max(lastUpdated) time of its bubbles. Bubbles - * within each group are then sorted by lastUpdated descending. + * This applies a full sort and group pass to all existing bubbles. + * Bubbles are sorted by lastUpdated descending. * * @return true if the position of any bubbles changed as a result */ @@ -711,31 +609,11 @@ public class BubbleData { if (mBubbles.isEmpty()) { return false; } - Map<String, Long> groupLastActivity = new HashMap<>(); - for (Bubble bubble : mBubbles) { - long maxSortKeyForGroup = groupLastActivity.getOrDefault(bubble.getGroupId(), 0L); - long sortKeyForBubble = sortKey(bubble); - if (sortKeyForBubble > maxSortKeyForGroup) { - groupLastActivity.put(bubble.getGroupId(), sortKeyForBubble); - } - } - - // Sort groups by their most recently active bubble - List<String> groupsByMostRecentActivity = - groupLastActivity.entrySet().stream() - .sorted(GROUPS_BY_MAX_SORT_KEY_DESCENDING) - .map(Map.Entry::getKey) - .collect(toList()); - List<Bubble> repacked = new ArrayList<>(mBubbles.size()); - - // For each group, add bubbles, freshest to oldest - for (String appId : groupsByMostRecentActivity) { - mBubbles.stream() - .filter((b) -> b.getGroupId().equals(appId)) - .sorted(BUBBLES_BY_SORT_KEY_DESCENDING) - .forEachOrdered(repacked::add); - } + // Add bubbles, freshest to oldest + mBubbles.stream() + .sorted(BUBBLES_BY_SORT_KEY_DESCENDING) + .forEachOrdered(repacked::add); if (repacked.equals(mBubbles)) { return false; } @@ -744,7 +622,8 @@ public class BubbleData { return true; } - private void maybeSendDeleteIntent(@DismissReason int reason, NotificationEntry entry) { + private void maybeSendDeleteIntent(@DismissReason int reason, + @NonNull final NotificationEntry entry) { if (reason == BubbleController.DISMISS_USER_GESTURE) { Notification.BubbleMetadata bubbleMetadata = entry.getBubbleMetadata(); PendingIntent deleteIntent = bubbleMetadata != null @@ -778,11 +657,12 @@ public class BubbleData { public List<Bubble> getBubbles() { return Collections.unmodifiableList(mBubbles); } + /** * The set of bubbles in overflow. */ @VisibleForTesting(visibility = PRIVATE) - public List<Bubble> getOverflowBubbles() { + List<Bubble> getOverflowBubbles() { return Collections.unmodifiableList(mOverflowBubbles); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt index ba93f4125ea5..c2b9195c8ba3 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDataRepository.kt @@ -74,8 +74,10 @@ internal class BubbleDataRepository @Inject constructor( private fun transform(userId: Int, bubbles: List<Bubble>): List<BubbleEntity> { return bubbles.mapNotNull { b -> - val shortcutId = b.shortcutInfo?.id ?: return@mapNotNull null - BubbleEntity(userId, b.packageName, shortcutId) + var shortcutId = b.shortcutInfo?.id + if (shortcutId == null) shortcutId = b.entry?.bubbleMetadata?.shortcutId + if (shortcutId == null) return@mapNotNull null + BubbleEntity(userId, b.packageName, shortcutId, b.key) } } @@ -108,7 +110,6 @@ internal class BubbleDataRepository @Inject constructor( /** * Load bubbles from disk. */ - // TODO: call this method from BubbleController and update UI @SuppressLint("WrongConstant") fun loadBubbles(cb: (List<Bubble>) -> Unit) = ioScope.launch { /** @@ -132,17 +133,17 @@ internal class BubbleDataRepository @Inject constructor( val shortcutKeys = entities.map { ShortcutKey(it.userId, it.packageName) }.toSet() /** * Retrieve shortcuts with given userId/packageName combination, then construct a mapping - * between BubbleEntity and ShortcutInfo. + * from the userId/packageName pair to a list of associated ShortcutInfo. * e.g. * { - * BubbleEntity(0, "com.example.messenger", "id-0") -> + * ShortcutKey(0, "com.example.messenger") -> [ * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-0"), - * BubbleEntity(0, "com.example.messenger", "id-2") -> - * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2"), - * BubbleEntity(10, "com.example.chat", "id-1") -> + * ShortcutInfo(userId=0, pkg="com.example.messenger", id="id-2") + * ] + * ShortcutKey(10, "com.example.chat") -> [ * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-1"), - * BubbleEntity(10, "com.example.chat", "id-3") -> * ShortcutInfo(userId=10, pkg="com.example.chat", id="id-3") + * ] * } */ val shortcutMap = shortcutKeys.flatMap { key -> @@ -150,17 +151,21 @@ internal class BubbleDataRepository @Inject constructor( LauncherApps.ShortcutQuery() .setPackage(key.pkg) .setQueryFlags(SHORTCUT_QUERY_FLAG), UserHandle.of(key.userId)) - ?.map { BubbleEntity(key.userId, key.pkg, it.id) to it } ?: emptyList() - }.toMap() + ?: emptyList() + }.groupBy { ShortcutKey(it.userId, it.`package`) } // For each entity loaded from xml, find the corresponding ShortcutInfo then convert them // into Bubble. - val bubbles = entities.mapNotNull { entity -> shortcutMap[entity]?.let { Bubble(it) } } + val bubbles = entities.mapNotNull { entity -> + shortcutMap[ShortcutKey(entity.userId, entity.packageName)] + ?.first { shortcutInfo -> entity.shortcutId == shortcutInfo.id } + ?.let { shortcutInfo -> Bubble(entity.key, shortcutInfo) } + } uiScope.launch { cb(bubbles) } } - - private data class ShortcutKey(val userId: Int, val pkg: String) } +data class ShortcutKey(val userId: Int, val pkg: String) + private const val TAG = "BubbleDataRepository" private const val DEBUG = false private const val SHORTCUT_QUERY_FLAG = diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java index 19733a5f895c..d98fee399470 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleDebugConfig.java @@ -69,10 +69,10 @@ public class BubbleDebugConfig { && selected.getKey() != BubbleOverflow.KEY && bubble == selected); String arrow = isSelected ? "=>" : " "; - sb.append(String.format("%s Bubble{act=%12d, ongoing=%d, key=%s}\n", + sb.append(String.format("%s Bubble{act=%12d, showInShade=%d, key=%s}\n", arrow, bubble.getLastActivity(), - (bubble.isOngoing() ? 1 : 0), + (bubble.showInShade() ? 1 : 0), bubble.getKey())); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java index 769740032509..64dc2ccc8b52 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleExpandedView.java @@ -65,7 +65,6 @@ import com.android.systemui.Dependency; import com.android.systemui.R; import com.android.systemui.recents.TriangleShape; import com.android.systemui.statusbar.AlphaOptimizedButton; -import com.android.systemui.statusbar.notification.collection.NotificationEntry; /** * Container for the expanded bubble view, handles rendering the caret and settings icon. @@ -161,7 +160,7 @@ public class BubbleExpandedView extends LinearLayout { // the bubble again so we'll just remove it. Log.w(TAG, "Exception while displaying bubble: " + getBubbleKey() + ", " + e.getMessage() + "; removing bubble"); - mBubbleController.removeBubble(getBubbleEntry(), + mBubbleController.removeBubble(getBubbleKey(), BubbleController.DISMISS_INVALID_INTENT); } }); @@ -205,7 +204,7 @@ public class BubbleExpandedView extends LinearLayout { } if (mBubble != null) { // Must post because this is called from a binder thread. - post(() -> mBubbleController.removeBubble(mBubble.getEntry(), + post(() -> mBubbleController.removeBubble(mBubble.getKey(), BubbleController.DISMISS_TASK_FINISHED)); } } @@ -226,8 +225,12 @@ public class BubbleExpandedView extends LinearLayout { public BubbleExpandedView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { super(context, attrs, defStyleAttr, defStyleRes); + updateDimensions(); + } + + void updateDimensions() { mDisplaySize = new Point(); - mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); + mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); // Get the real size -- this includes screen decorations (notches, statusbar, navbar). mWindowManager.getDefaultDisplay().getRealSize(mDisplaySize); Resources res = getResources(); @@ -293,10 +296,6 @@ public class BubbleExpandedView extends LinearLayout { return mBubble != null ? mBubble.getKey() : "null"; } - private NotificationEntry getBubbleEntry() { - return mBubble != null ? mBubble.getEntry() : null; - } - void setManageClickListener(OnClickListener manageClickListener) { findViewById(R.id.settings_button).setOnClickListener(manageClickListener); } @@ -307,7 +306,9 @@ public class BubbleExpandedView extends LinearLayout { * if a view has been added or removed from on top of the ActivityView, such as the manage menu. */ void updateObscuredTouchableRegion() { - mActivityView.onLocationChanged(); + if (mActivityView != null) { + mActivityView.onLocationChanged(); + } } void applyThemeAttrs() { diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java index f4eb580d70ff..b77e2261e39b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflow.java @@ -61,9 +61,7 @@ public class BubbleOverflow implements BubbleViewProvider { } void setUpOverflow(ViewGroup parentViewGroup, BubbleStackView stackView) { - mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size); - mIconBitmapSize = mContext.getResources().getDimensionPixelSize( - R.dimen.bubble_overflow_icon_bitmap_size); + updateDimensions(); mExpandedView = (BubbleExpandedView) mInflater.inflate( R.layout.bubble_expanded_view, parentViewGroup /* root */, @@ -74,6 +72,15 @@ public class BubbleOverflow implements BubbleViewProvider { updateIcon(mContext, parentViewGroup); } + void updateDimensions() { + mBitmapSize = mContext.getResources().getDimensionPixelSize(R.dimen.bubble_bitmap_size); + mIconBitmapSize = mContext.getResources().getDimensionPixelSize( + R.dimen.bubble_overflow_icon_bitmap_size); + if (mExpandedView != null) { + mExpandedView.updateDimensions(); + } + } + void updateIcon(Context context, ViewGroup parentViewGroup) { mContext = context; mInflater = LayoutInflater.from(context); @@ -122,7 +129,7 @@ public class BubbleOverflow implements BubbleViewProvider { return mOverflowBtn; } - void setBtnVisible(int visible) { + void setVisible(int visible) { mOverflowBtn.setVisibility(visible); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java index 61e8ecfb3625..bea4ba776beb 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleOverflowActivity.java @@ -21,7 +21,6 @@ import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_BUBBLES; import static com.android.systemui.bubbles.BubbleDebugConfig.TAG_WITH_CLASS_NAME; import android.app.Activity; -import android.app.Notification; import android.content.Context; import android.content.res.Configuration; import android.content.res.Resources; @@ -92,6 +91,14 @@ public class BubbleOverflowActivity extends Activity { mRecyclerView = findViewById(R.id.bubble_overflow_recycler); mEmptyStateImage = findViewById(R.id.bubble_overflow_empty_state_image); + updateDimensions(); + onDataChanged(mBubbleController.getOverflowBubbles()); + mBubbleController.setOverflowCallback(() -> { + onDataChanged(mBubbleController.getOverflowBubbles()); + }); + } + + void updateDimensions() { Resources res = getResources(); final int columns = res.getInteger(R.integer.bubbles_overflow_columns); mRecyclerView.setLayoutManager( @@ -99,8 +106,9 @@ public class BubbleOverflowActivity extends Activity { DisplayMetrics displayMetrics = new DisplayMetrics(); getWindowManager().getDefaultDisplay().getMetrics(displayMetrics); - final int recyclerViewWidth = (displayMetrics.widthPixels - - res.getDimensionPixelSize(R.dimen.bubble_overflow_padding)); + + final int overflowPadding = res.getDimensionPixelSize(R.dimen.bubble_overflow_padding); + final int recyclerViewWidth = displayMetrics.widthPixels - (overflowPadding * 2); final int viewWidth = recyclerViewWidth / columns; final int maxOverflowBubbles = res.getInteger(R.integer.bubbles_max_overflow); @@ -112,17 +120,12 @@ public class BubbleOverflowActivity extends Activity { mAdapter = new BubbleOverflowAdapter(getApplicationContext(), mOverflowBubbles, mBubbleController::promoteBubbleFromOverflow, viewWidth, viewHeight); mRecyclerView.setAdapter(mAdapter); - onDataChanged(mBubbleController.getOverflowBubbles()); - mBubbleController.setOverflowCallback(() -> { - onDataChanged(mBubbleController.getOverflowBubbles()); - }); - onThemeChanged(); } /** * Handle theme changes. */ - void onThemeChanged() { + void updateTheme() { final int mode = getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK; switch (mode) { @@ -181,7 +184,8 @@ public class BubbleOverflowActivity extends Activity { @Override public void onResume() { super.onResume(); - onThemeChanged(); + updateDimensions(); + updateTheme(); } @Override @@ -255,12 +259,9 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V mPromoteBubbleFromOverflow.accept(b); }); - final CharSequence titleCharSeq = - b.getEntry().getSbn().getNotification().extras.getCharSequence( - Notification.EXTRA_TITLE); - String titleStr = mContext.getResources().getString(R.string.notification_bubble_title); - if (titleCharSeq != null) { - titleStr = titleCharSeq.toString(); + String titleStr = b.getTitle(); + if (titleStr == null) { + titleStr = mContext.getResources().getString(R.string.notification_bubble_title); } vh.iconView.setContentDescription(mContext.getResources().getString( R.string.bubble_content_description_single, titleStr, b.getAppName())); @@ -283,7 +284,7 @@ class BubbleOverflowAdapter extends RecyclerView.Adapter<BubbleOverflowAdapter.V Bubble.FlyoutMessage message = b.getFlyoutMessage(); if (message != null && message.senderName != null) { - vh.textView.setText(message.senderName); + vh.textView.setText(message.senderName.toString()); } else { vh.textView.setText(b.getAppName()); } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index c9f362b871e1..239132ea292b 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -31,7 +31,6 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; import android.annotation.SuppressLint; -import android.app.Notification; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -49,9 +48,7 @@ import android.graphics.Rect; import android.graphics.RectF; import android.graphics.Region; import android.os.Bundle; -import android.os.Vibrator; import android.provider.Settings; -import android.service.notification.StatusBarNotification; import android.util.Log; import android.view.Choreographer; import android.view.DisplayCutout; @@ -188,7 +185,6 @@ public class BubbleStackView extends FrameLayout private final SpringAnimation mExpandedViewYAnim; private final BubbleData mBubbleData; - private final Vibrator mVibrator; private final ValueAnimator mDesaturateAndDarkenAnimator; private final Paint mDesaturateAndDarkenPaint = new Paint(); @@ -701,8 +697,6 @@ public class BubbleStackView extends FrameLayout // We use the real size & subtract screen decorations / window insets ourselves when needed wm.getDefaultDisplay().getRealSize(mDisplaySize); - mVibrator = (Vibrator) context.getSystemService(Context.VIBRATOR_SERVICE); - mExpandedViewPadding = res.getDimensionPixelSize(R.dimen.bubble_expanded_view_padding); int elevation = res.getDimensionPixelSize(R.dimen.bubble_elevation); @@ -945,10 +939,10 @@ public class BubbleStackView extends FrameLayout showManageMenu(false /* show */); final Bubble bubble = mBubbleData.getSelectedBubble(); if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { - final Intent intent = bubble.getSettingsIntent(); + final Intent intent = bubble.getSettingsIntent(mContext); collapseStack(() -> { - mContext.startActivityAsUser( - intent, bubble.getEntry().getSbn().getUser()); + + mContext.startActivityAsUser(intent, bubble.getUser()); logBubbleClickEvent( bubble, SysUiStatsLog.BUBBLE_UICHANGED__ACTION__HEADER_GO_TO_SETTINGS); @@ -1033,6 +1027,7 @@ public class BubbleStackView extends FrameLayout mBubbleOverflow.setUpOverflow(mBubbleContainer, this); } else { mBubbleContainer.removeView(mBubbleOverflow.getBtn()); + mBubbleOverflow.updateDimensions(); mBubbleOverflow.updateIcon(mContext,this); overflowBtnIndex = mBubbleContainer.getChildCount(); } @@ -1122,6 +1117,9 @@ public class BubbleStackView extends FrameLayout super.onDetachedFromWindow(); getViewTreeObserver().removeOnPreDrawListener(mViewUpdater); getViewTreeObserver().removeOnComputeInternalInsetsListener(this); + if (mBubbleOverflow != null && mBubbleOverflow.getExpandedView() != null) { + mBubbleOverflow.getExpandedView().cleanUpExpandedState(); + } } @Override @@ -1205,13 +1203,10 @@ public class BubbleStackView extends FrameLayout for (int i = 0; i < mBubbleData.getBubbles().size(); i++) { final Bubble bubble = mBubbleData.getBubbles().get(i); final String appName = bubble.getAppName(); - final Notification notification = bubble.getEntry().getSbn().getNotification(); - final CharSequence titleCharSeq = - notification.extras.getCharSequence(Notification.EXTRA_TITLE); - String titleStr = getResources().getString(R.string.notification_bubble_title); - if (titleCharSeq != null) { - titleStr = titleCharSeq.toString(); + String titleStr = bubble.getTitle(); + if (titleStr == null) { + titleStr = getResources().getString(R.string.notification_bubble_title); } if (bubble.getIconView() != null) { @@ -1342,21 +1337,12 @@ public class BubbleStackView extends FrameLayout Log.d(TAG, "was asked to remove Bubble, but didn't find the view! " + bubble); } - private void updateOverflowBtnVisibility() { - if (!BubbleExperimentConfig.allowBubbleOverflow(mContext)) { + private void updateOverflowVisibility() { + if (!BubbleExperimentConfig.allowBubbleOverflow(mContext) + || mBubbleOverflow == null) { return; } - if (mIsExpanded) { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "Show overflow button."); - } - mBubbleOverflow.setBtnVisible(VISIBLE); - } else { - if (DEBUG_BUBBLE_STACK_VIEW) { - Log.d(TAG, "Collapsed. Hide overflow button."); - } - mBubbleOverflow.setBtnVisible(GONE); - } + mBubbleOverflow.setVisible(mIsExpanded ? VISIBLE : GONE); } // via BubbleData.Listener @@ -1610,7 +1596,7 @@ public class BubbleStackView extends FrameLayout Log.d(TAG, BubbleDebugConfig.formatBubblesString(getBubblesOnScreen(), mExpandedBubble)); } - updateOverflowBtnVisibility(); + updateOverflowVisibility(); mBubbleContainer.cancelAllAnimations(); mExpandedAnimationController.collapseBackToStack( mStackAnimationController.getStackPositionAlongNearestHorizontalEdge() @@ -1634,7 +1620,7 @@ public class BubbleStackView extends FrameLayout beforeExpandedViewAnimation(); mBubbleContainer.setActiveController(mExpandedAnimationController); - updateOverflowBtnVisibility(); + updateOverflowVisibility(); mExpandedAnimationController.expandFromStack(() -> { updatePointerPosition(); afterExpandedViewAnimation(); @@ -1824,7 +1810,7 @@ public class BubbleStackView extends FrameLayout private void dismissBubbleIfExists(@Nullable Bubble bubble) { if (bubble != null && mBubbleData.hasBubbleInStackWithKey(bubble.getKey())) { mBubbleData.notificationEntryRemoved( - bubble.getEntry(), BubbleController.DISMISS_USER_GESTURE); + bubble.getKey(), BubbleController.DISMISS_USER_GESTURE); } } @@ -2322,18 +2308,12 @@ public class BubbleStackView extends FrameLayout * @param action the user interaction enum. */ private void logBubbleClickEvent(Bubble bubble, int action) { - StatusBarNotification notification = bubble.getEntry().getSbn(); - SysUiStatsLog.write(SysUiStatsLog.BUBBLE_UI_CHANGED, - notification.getPackageName(), - notification.getNotification().getChannelId(), - notification.getId(), - getBubbleIndex(getExpandedBubble()), + bubble.logUIEvent( getBubbleCount(), action, getNormalizedXPosition(), getNormalizedYPosition(), - bubble.showInShade(), - bubble.isOngoing(), - false /* isAppForeground (unused) */); + getBubbleIndex(getExpandedBubble()) + ); } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java index 8a57a735f6cb..525d5b56cc8e 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleViewInfoTask.java @@ -37,6 +37,7 @@ import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; import android.os.AsyncTask; import android.os.Parcelable; +import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.text.TextUtils; import android.util.Log; @@ -74,6 +75,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask private WeakReference<Context> mContext; private WeakReference<BubbleStackView> mStackView; private BubbleIconFactory mIconFactory; + private boolean mSkipInflation; private Callback mCallback; /** @@ -84,17 +86,20 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask Context context, BubbleStackView stackView, BubbleIconFactory factory, + boolean skipInflation, Callback c) { mBubble = b; mContext = new WeakReference<>(context); mStackView = new WeakReference<>(stackView); mIconFactory = factory; + mSkipInflation = skipInflation; mCallback = c; } @Override protected BubbleViewInfo doInBackground(Void... voids) { - return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble); + return BubbleViewInfo.populate(mContext.get(), mStackView.get(), mIconFactory, mBubble, + mSkipInflation); } @Override @@ -123,11 +128,36 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask @Nullable static BubbleViewInfo populate(Context c, BubbleStackView stackView, - BubbleIconFactory iconFactory, Bubble b) { + BubbleIconFactory iconFactory, Bubble b, boolean skipInflation) { + final NotificationEntry entry = b.getEntry(); + if (entry == null) { + // populate from ShortcutInfo when NotificationEntry is not available + final ShortcutInfo s = b.getShortcutInfo(); + return populate(c, stackView, iconFactory, skipInflation || b.isInflated(), + s.getPackage(), s.getUserHandle(), s, null); + } + final StatusBarNotification sbn = entry.getSbn(); + final String bubbleShortcutId = entry.getBubbleMetadata().getShortcutId(); + final ShortcutInfo si = bubbleShortcutId == null + ? null : entry.getRanking().getShortcutInfo(); + return populate( + c, stackView, iconFactory, skipInflation || b.isInflated(), + sbn.getPackageName(), sbn.getUser(), si, entry); + } + + private static BubbleViewInfo populate( + @NonNull final Context c, + @NonNull final BubbleStackView stackView, + @NonNull final BubbleIconFactory iconFactory, + final boolean isInflated, + @NonNull final String packageName, + @NonNull final UserHandle user, + @Nullable final ShortcutInfo shortcutInfo, + @Nullable final NotificationEntry entry) { BubbleViewInfo info = new BubbleViewInfo(); // View inflation: only should do this once per bubble - if (!b.isInflated()) { + if (!isInflated) { LayoutInflater inflater = LayoutInflater.from(c); info.imageView = (BadgedImageView) inflater.inflate( R.layout.bubble_view, stackView, false /* attachToRoot */); @@ -137,12 +167,8 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask info.expandedView.setStackView(stackView); } - StatusBarNotification sbn = b.getEntry().getSbn(); - String packageName = sbn.getPackageName(); - - String bubbleShortcutId = b.getEntry().getBubbleMetadata().getShortcutId(); - if (bubbleShortcutId != null) { - info.shortcutInfo = b.getEntry().getRanking().getShortcutInfo(); + if (shortcutInfo != null) { + info.shortcutInfo = shortcutInfo; } // App name & app icon @@ -161,7 +187,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask info.appName = String.valueOf(pm.getApplicationLabel(appInfo)); } appIcon = pm.getApplicationIcon(packageName); - badgedIcon = pm.getUserBadgedIcon(appIcon, sbn.getUser()); + badgedIcon = pm.getUserBadgedIcon(appIcon, user); } catch (PackageManager.NameNotFoundException exception) { // If we can't find package... don't think we should show the bubble. Log.w(TAG, "Unable to find package: " + packageName); @@ -170,7 +196,7 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask // Badged bubble image Drawable bubbleDrawable = iconFactory.getBubbleDrawable(c, info.shortcutInfo, - b.getEntry().getBubbleMetadata()); + entry == null ? null : entry.getBubbleMetadata()); if (bubbleDrawable == null) { // Default to app icon bubbleDrawable = appIcon; @@ -196,7 +222,9 @@ public class BubbleViewInfoTask extends AsyncTask<Void, Void, BubbleViewInfoTask Color.WHITE, WHITE_SCRIM_ALPHA); // Flyout - info.flyoutMessage = extractFlyoutMessage(c, b.getEntry()); + if (entry != null) { + info.flyoutMessage = extractFlyoutMessage(c, entry); + } return info; } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt index 4690a8e14072..43482616da2c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleEntity.kt @@ -20,5 +20,6 @@ import android.annotation.UserIdInt data class BubbleEntity( @UserIdInt val userId: Int, val packageName: String, - val shortcutId: String + val shortcutId: String, + val key: String ) diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt index d1eee2f69b63..bdeb714b568c 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleVolatileRepository.kt @@ -15,6 +15,10 @@ */ package com.android.systemui.bubbles.storage +import android.content.pm.LauncherApps +import android.os.UserHandle +import com.android.internal.annotations.VisibleForTesting +import com.android.systemui.bubbles.ShortcutKey import javax.inject.Inject import javax.inject.Singleton @@ -25,11 +29,19 @@ private const val CAPACITY = 16 * manipulation. */ @Singleton -class BubbleVolatileRepository @Inject constructor() { +class BubbleVolatileRepository @Inject constructor( + private val launcherApps: LauncherApps +) { /** * An ordered set of bubbles based on their natural ordering. */ - private val entities = mutableSetOf<BubbleEntity>() + private var entities = mutableSetOf<BubbleEntity>() + + /** + * The capacity of the cache. + */ + @VisibleForTesting + var capacity = CAPACITY /** * Returns a snapshot of all the bubbles. @@ -45,15 +57,34 @@ class BubbleVolatileRepository @Inject constructor() { @Synchronized fun addBubbles(bubbles: List<BubbleEntity>) { if (bubbles.isEmpty()) return - bubbles.forEach { entities.remove(it) } - if (entities.size + bubbles.size >= CAPACITY) { - entities.drop(entities.size + bubbles.size - CAPACITY) + // Verify the size of given bubbles is within capacity, otherwise trim down to capacity + val bubblesInRange = bubbles.takeLast(capacity) + // To ensure natural ordering of the bubbles, removes bubbles which already exist + val uniqueBubbles = bubblesInRange.filterNot { entities.remove(it) } + val overflowCount = entities.size + bubblesInRange.size - capacity + if (overflowCount > 0) { + // Uncache ShortcutInfo of bubbles that will be removed due to capacity + uncache(entities.take(overflowCount)) + entities = entities.drop(overflowCount).toMutableSet() } - entities.addAll(bubbles) + entities.addAll(bubblesInRange) + cache(uniqueBubbles) } @Synchronized - fun removeBubbles(bubbles: List<BubbleEntity>) { - bubbles.forEach { entities.remove(it) } + fun removeBubbles(bubbles: List<BubbleEntity>) = uncache(bubbles.filter { entities.remove(it) }) + + private fun cache(bubbles: List<BubbleEntity>) { + bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) -> + launcherApps.cacheShortcuts(key.pkg, bubbles.map { it.shortcutId }, + UserHandle.of(key.userId), LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS) + } + } + + private fun uncache(bubbles: List<BubbleEntity>) { + bubbles.groupBy { ShortcutKey(it.userId, it.packageName) }.forEach { (key, bubbles) -> + launcherApps.uncacheShortcuts(key.pkg, bubbles.map { it.shortcutId }, + UserHandle.of(key.userId), LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS) + } } } diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt index 821b64ce5e6e..1df9f72022f0 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt +++ b/packages/SystemUI/src/com/android/systemui/bubbles/storage/BubbleXmlHelper.kt @@ -30,6 +30,7 @@ private const val TAG_BUBBLE = "bb" private const val ATTR_USER_ID = "uid" private const val ATTR_PACKAGE = "pkg" private const val ATTR_SHORTCUT_ID = "sid" +private const val ATTR_KEY = "key" /** * Writes the bubbles in xml format into given output stream. @@ -48,7 +49,7 @@ fun writeXml(stream: OutputStream, bubbles: List<BubbleEntity>) { /** * Creates a xml entry for given bubble in following format: * ``` - * <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" /> + * <bb uid="0" pkg="com.example.messenger" sid="my-shortcut" key="my-key" /> * ``` */ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) { @@ -57,6 +58,7 @@ private fun writeXmlEntry(serializer: XmlSerializer, bubble: BubbleEntity) { serializer.attribute(null, ATTR_USER_ID, bubble.userId.toString()) serializer.attribute(null, ATTR_PACKAGE, bubble.packageName) serializer.attribute(null, ATTR_SHORTCUT_ID, bubble.shortcutId) + serializer.attribute(null, ATTR_KEY, bubble.key) serializer.endTag(null, TAG_BUBBLE) } catch (e: IOException) { throw RuntimeException(e) @@ -83,7 +85,8 @@ private fun readXmlEntry(parser: XmlPullParser): BubbleEntity? { return BubbleEntity( parser.getAttributeWithName(ATTR_USER_ID)?.toInt() ?: return null, parser.getAttributeWithName(ATTR_PACKAGE) ?: return null, - parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null + parser.getAttributeWithName(ATTR_SHORTCUT_ID) ?: return null, + parser.getAttributeWithName(ATTR_KEY) ?: return null ) } diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt new file mode 100644 index 000000000000..9a5b96078e95 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsComponent.kt @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.dagger + +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.management.ControlsListingController +import com.android.systemui.controls.ui.ControlsUiController +import dagger.Lazy +import java.util.Optional +import javax.inject.Inject +import javax.inject.Singleton + +/** + * Pseudo-component to inject into classes outside `com.android.systemui.controls`. + * + * If `featureEnabled` is false, all the optionals should be empty. The controllers will only be + * instantiated if `featureEnabled` is true. + */ +@Singleton +class ControlsComponent @Inject constructor( + @ControlsFeatureEnabled private val featureEnabled: Boolean, + private val lazyControlsController: Lazy<ControlsController>, + private val lazyControlsUiController: Lazy<ControlsUiController>, + private val lazyControlsListingController: Lazy<ControlsListingController> +) { + fun getControlsController(): Optional<ControlsController> { + return if (featureEnabled) Optional.of(lazyControlsController.get()) else Optional.empty() + } + + fun getControlsUiController(): Optional<ControlsUiController> { + return if (featureEnabled) Optional.of(lazyControlsUiController.get()) else Optional.empty() + } + + fun getControlsListingController(): Optional<ControlsListingController> { + return if (featureEnabled) { + Optional.of(lazyControlsListingController.get()) + } else { + Optional.empty() + } + } +}
\ No newline at end of file diff --git a/apex/sdkextensions/derive_sdk/sdk.proto b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsFeatureEnabled.kt index d15b93552ff4..dd061c526c40 100644 --- a/apex/sdkextensions/derive_sdk/sdk.proto +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsFeatureEnabled.kt @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 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. @@ -14,12 +14,11 @@ * limitations under the License. */ -syntax = "proto3"; -package com.android.sdkext.proto; +package com.android.systemui.controls.dagger -option java_outer_classname = "SdkProto"; -option optimize_for = LITE_RUNTIME; +import javax.inject.Qualifier -message SdkVersion { - int32 version = 1; -} +@Qualifier +@MustBeDocumented +@Retention(AnnotationRetention.RUNTIME) +annotation class ControlsFeatureEnabled
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt index 5765be57b5b0..4760d291072e 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -17,6 +17,7 @@ package com.android.systemui.controls.dagger import android.app.Activity +import android.content.pm.PackageManager import com.android.systemui.controls.controller.ControlsBindingController import com.android.systemui.controls.controller.ControlsBindingControllerImpl import com.android.systemui.controls.controller.ControlsController @@ -28,19 +29,39 @@ import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingControllerImpl import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.controls.management.ControlsRequestDialog -import com.android.systemui.controls.ui.ControlsUiController -import com.android.systemui.controls.ui.ControlsUiControllerImpl import com.android.systemui.controls.ui.ControlActionCoordinator import com.android.systemui.controls.ui.ControlActionCoordinatorImpl +import com.android.systemui.controls.ui.ControlsUiController +import com.android.systemui.controls.ui.ControlsUiControllerImpl import dagger.Binds import dagger.BindsOptionalOf import dagger.Module +import dagger.Provides import dagger.multibindings.ClassKey import dagger.multibindings.IntoMap +import javax.inject.Singleton +/** + * Module for injecting classes in `com.android.systemui.controls`- + * + * Classes provided by this module should only be injected directly into other classes in this + * module. For injecting outside of this module (for example, [GlobalActionsDialog], inject + * [ControlsComponent] and obtain the corresponding optionals from it. + */ @Module abstract class ControlsModule { + @Module + companion object { + @JvmStatic + @Provides + @Singleton + @ControlsFeatureEnabled + fun providesControlsFeatureEnabled(pm: PackageManager): Boolean { + return pm.hasSystemFeature(PackageManager.FEATURE_CONTROLS) + } + } + @Binds abstract fun provideControlsListingController( controller: ControlsListingControllerImpl diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt index 0d23557ffa9e..bf84d77224b1 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsRequestReceiver.kt @@ -55,6 +55,9 @@ class ControlsRequestReceiver : BroadcastReceiver() { } override fun onReceive(context: Context, intent: Intent) { + if (!context.packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)) { + return + } val packageName = intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME) ?.packageName 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 ab3329122edc..606e94760946 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -60,7 +60,6 @@ import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.globalactions.GlobalActionsPopupMenu import com.android.systemui.plugins.ActivityStarter import com.android.systemui.statusbar.phone.ShadeController -import com.android.systemui.statusbar.policy.KeyguardStateController import com.android.systemui.util.concurrency.DelayableExecutor import dagger.Lazy import java.text.Collator @@ -80,7 +79,6 @@ class ControlsUiControllerImpl @Inject constructor ( @Main val sharedPreferences: SharedPreferences, val controlActionCoordinator: ControlActionCoordinator, private val activityStarter: ActivityStarter, - private val keyguardStateController: KeyguardStateController, private val shadeController: ShadeController ) : ControlsUiController { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java index 23bcb29923d8..8368b2c1ae86 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java @@ -96,12 +96,6 @@ public class DependencyProvider { return new AmbientDisplayConfiguration(context); } - /** */ - @Provides - public Handler provideHandler() { - return new Handler(); - } - @Singleton @Provides public DataSaverController provideDataSaverController(NetworkController networkController) { diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java index 3a8212cd733e..58aad8673172 100644 --- a/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java +++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemServicesModule.java @@ -28,6 +28,7 @@ import android.app.KeyguardManager; import android.app.NotificationManager; import android.app.WallpaperManager; import android.app.admin.DevicePolicyManager; +import android.app.role.RoleManager; import android.app.trust.TrustManager; import android.content.ContentResolver; import android.content.Context; @@ -314,4 +315,9 @@ public class SystemServicesModule { return context.getSystemService(WindowManager.class); } + @Provides + @Singleton + static RoleManager provideRoleManager(Context context) { + return context.getSystemService(RoleManager.class); + } } diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java index 65729372363a..95a9006c854a 100644 --- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java +++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java @@ -28,6 +28,7 @@ import android.os.Handler; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.systemui.R; import com.android.systemui.broadcast.BroadcastDispatcher; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dock.DockManager; import com.android.systemui.keyguard.WakefulnessLifecycle; import com.android.systemui.plugins.FalsingManager; @@ -69,7 +70,7 @@ public class DozeFactory { WakefulnessLifecycle wakefulnessLifecycle, KeyguardUpdateMonitor keyguardUpdateMonitor, DockManager dockManager, @Nullable IWallpaperManager wallpaperManager, ProximitySensor proximitySensor, - DelayedWakeLock.Builder delayedWakeLockBuilder, Handler handler, + DelayedWakeLock.Builder delayedWakeLockBuilder, @Main Handler handler, DelayableExecutor delayableExecutor, BiometricUnlockController biometricUnlockController, BroadcastDispatcher broadcastDispatcher, DozeHost dozeHost) { diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index ac289cb5f822..0f3a94b74342 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -120,8 +120,8 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.controls.ControlsServiceInfo; import com.android.systemui.controls.controller.ControlsController; +import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.controls.management.ControlsAnimations; -import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; @@ -129,6 +129,7 @@ import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions.GlobalActionsManager; import com.android.systemui.plugins.GlobalActionsPanelPlugin; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -139,6 +140,7 @@ import com.android.systemui.util.leak.RotationUtils; import java.util.ArrayList; import java.util.List; +import java.util.Optional; import java.util.concurrent.Executor; import javax.inject.Inject; @@ -233,15 +235,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private final IStatusBarService mStatusBarService; private final NotificationShadeWindowController mNotificationShadeWindowController; private GlobalActionsPanelPlugin mWalletPlugin; - private ControlsUiController mControlsUiController; + private Optional<ControlsUiController> mControlsUiControllerOptional; private final IWindowManager mIWindowManager; private final Executor mBackgroundExecutor; private List<ControlsServiceInfo> mControlsServiceInfos = new ArrayList<>(); - private ControlsController mControlsController; + private Optional<ControlsController> mControlsControllerOptional; private SharedPreferences mControlsPreferences; private final RingerModeTracker mRingerModeTracker; private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms private Handler mMainHandler; + private CurrentUserContextTracker mCurrentUserContextTracker; @VisibleForTesting boolean mShowLockScreenCardsAndControls = false; @@ -297,12 +300,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, NotificationShadeDepthController depthController, SysuiColorExtractor colorExtractor, IStatusBarService statusBarService, NotificationShadeWindowController notificationShadeWindowController, - ControlsUiController controlsUiController, IWindowManager iWindowManager, + IWindowManager iWindowManager, @Background Executor backgroundExecutor, - ControlsListingController controlsListingController, - ControlsController controlsController, UiEventLogger uiEventLogger, - RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler) { - mContext = new ContextThemeWrapper(context, com.android.systemui.R.style.qs_theme); + UiEventLogger uiEventLogger, + RingerModeTracker ringerModeTracker, SysUiState sysUiState, @Main Handler handler, + ControlsComponent controlsComponent, + CurrentUserContextTracker currentUserContextTracker) { + mContext = context; mWindowManagerFuncs = windowManagerFuncs; mAudioManager = audioManager; mDreamManager = iDreamManager; @@ -323,13 +327,14 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mSysuiColorExtractor = colorExtractor; mStatusBarService = statusBarService; mNotificationShadeWindowController = notificationShadeWindowController; - mControlsUiController = controlsUiController; + mControlsUiControllerOptional = controlsComponent.getControlsUiController(); mIWindowManager = iWindowManager; mBackgroundExecutor = backgroundExecutor; mRingerModeTracker = ringerModeTracker; - mControlsController = controlsController; + mControlsControllerOptional = controlsComponent.getControlsController(); mSysUiState = sysUiState; mMainHandler = handler; + mCurrentUserContextTracker = currentUserContextTracker; // receive broadcasts IntentFilter filter = new IntentFilter(); @@ -371,7 +376,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mDialog.mWalletViewController.onDeviceLockStateChanged(!unlocked); } if (!mDialog.isShowingControls() && shouldShowControls()) { - mDialog.showControls(mControlsUiController); + mDialog.showControls(mControlsUiControllerOptional.get()); } if (unlocked) { mDialog.hideLockMessage(); @@ -380,7 +385,10 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } }); - controlsListingController.addCallback(list -> mControlsServiceInfos = list); + if (controlsComponent.getControlsListingController().isPresent()) { + controlsComponent.getControlsListingController().get() + .addCallback(list -> mControlsServiceInfos = list); + } // Need to be user-specific with the context to make sure we read the correct prefs Context userContext = context.createContextAsUser( @@ -402,9 +410,16 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private void seedFavorites() { + if (!mControlsControllerOptional.isPresent()) return; if (mControlsServiceInfos.isEmpty() - || mControlsController.getFavorites().size() > 0 - || mControlsPreferences.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) { + || mControlsControllerOptional.get().getFavorites().size() > 0) { + return; + } + + // Need to be user-specific with the context to make sure we read the correct prefs + SharedPreferences prefs = mCurrentUserContextTracker.getCurrentUserContext() + .getSharedPreferences(PREFS_CONTROLS_FILE, Context.MODE_PRIVATE); + if (prefs.getBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, false)) { return; } @@ -426,16 +441,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, if (preferredComponent == null) { Log.i(TAG, "Controls seeding: No preferred component has been set, will not seed"); - mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply(); + prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, true).apply(); return; } - mControlsController.seedFavoritesForComponent( + mControlsControllerOptional.get().seedFavoritesForComponent( preferredComponent, (accepted) -> { Log.i(TAG, "Controls seeded: " + accepted); - mControlsPreferences.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, - accepted).apply(); + prefs.edit().putBoolean(PREFS_CONTROLS_SEEDING_COMPLETED, accepted).apply(); }); } @@ -550,8 +564,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mItems.clear(); mOverflowItems.clear(); - String[] defaultActions = getDefaultActions(); + String[] defaultActions = getDefaultActions(); // make sure emergency affordance action is first, if needed if (mEmergencyAffordanceManager.needsEmergencyAffordance()) { addActionItem(new EmergencyAffordanceAction()); @@ -634,10 +648,14 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, mDepthController.setShowingHomeControls(true); GlobalActionsPanelPlugin.PanelViewController walletViewController = getWalletViewController(); + ControlsUiController uiController = null; + if (mControlsUiControllerOptional.isPresent() && shouldShowControls()) { + uiController = mControlsUiControllerOptional.get(); + } ActionsDialog dialog = new ActionsDialog(mContext, mAdapter, mOverflowAdapter, walletViewController, mDepthController, mSysuiColorExtractor, mStatusBarService, mNotificationShadeWindowController, - controlsAvailable(), shouldShowControls() ? mControlsUiController : null, + controlsAvailable(), uiController, mSysUiState, this::onRotate, mKeyguardShowing); boolean walletViewAvailable = walletViewController != null && walletViewController.getPanelContent() != null; @@ -1323,18 +1341,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, View view = convertView != null ? convertView : LayoutInflater.from(mContext).inflate(viewLayoutResource, parent, false); TextView textView = (TextView) view; - textView.setOnClickListener(v -> onClickItem(position)); if (action.getMessageResId() != 0) { textView.setText(action.getMessageResId()); } else { textView.setText(action.getMessage()); } - - if (action instanceof LongPressAction) { - textView.setOnLongClickListener(v -> onLongClickItem(position)); - } else { - textView.setOnLongClickListener(null); - } return textView; } @@ -2046,11 +2057,15 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } private ListPopupWindow createPowerOverflowPopup() { - ListPopupWindow popup = new GlobalActionsPopupMenu( + GlobalActionsPopupMenu popup = new GlobalActionsPopupMenu( new ContextThemeWrapper( - mContext, - com.android.systemui.R.style.Control_ListPopupWindow + mContext, + com.android.systemui.R.style.Control_ListPopupWindow ), false /* isDropDownMode */); + popup.setOnItemClickListener( + (parent, view, position, id) -> mOverflowAdapter.onClickItem(position)); + popup.setOnItemLongClickListener( + (parent, view, position, id) -> mOverflowAdapter.onLongClickItem(position)); View overflowButton = findViewById(com.android.systemui.R.id.global_actions_overflow_button); popup.setAnchorView(overflowButton); @@ -2401,7 +2416,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private boolean controlsAvailable() { return mDeviceProvisioned - && mControlsUiController.getAvailable() + && mControlsUiControllerOptional.isPresent() + && mControlsUiControllerOptional.get().getAvailable() && !mControlsServiceInfos.isEmpty(); } diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java index a5ced7b574b7..6b71f1e9d86f 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsPopupMenu.java @@ -22,6 +22,7 @@ import android.content.res.Resources; import android.view.View; import android.view.View.MeasureSpec; import android.view.WindowManager; +import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListPopupWindow; import android.widget.ListView; @@ -37,10 +38,10 @@ import com.android.systemui.R; public class GlobalActionsPopupMenu extends ListPopupWindow { private Context mContext; private boolean mIsDropDownMode; - private int mMenuHorizontalPadding = 0; private int mMenuVerticalPadding = 0; private int mGlobalActionsSidePadding = 0; private ListAdapter mAdapter; + private AdapterView.OnItemLongClickListener mOnItemLongClickListener; public GlobalActionsPopupMenu(@NonNull Context context, boolean isDropDownMode) { super(context); @@ -57,8 +58,6 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { mGlobalActionsSidePadding = res.getDimensionPixelSize(R.dimen.global_actions_side_margin); if (!isDropDownMode) { mMenuVerticalPadding = res.getDimensionPixelSize(R.dimen.control_menu_vertical_padding); - mMenuHorizontalPadding = - res.getDimensionPixelSize(R.dimen.control_menu_horizontal_padding); } } @@ -76,6 +75,9 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { public void show() { // need to call show() first in order to construct the listView super.show(); + if (mOnItemLongClickListener != null) { + getListView().setOnItemLongClickListener(mOnItemLongClickListener); + } ListView listView = getListView(); Resources res = mContext.getResources(); @@ -92,7 +94,7 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { // width should be between [.5, .9] of screen int parentWidth = res.getSystem().getDisplayMetrics().widthPixels; int widthSpec = MeasureSpec.makeMeasureSpec( - (int) (parentWidth * 0.9) - 2 * mMenuHorizontalPadding, MeasureSpec.AT_MOST); + (int) (parentWidth * 0.9), MeasureSpec.AT_MOST); int maxWidth = 0; for (int i = 0; i < mAdapter.getCount(); i++) { View child = mAdapter.getView(i, null, listView); @@ -100,10 +102,8 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { int w = child.getMeasuredWidth(); maxWidth = Math.max(w, maxWidth); } - int width = Math.max(maxWidth, (int) (parentWidth * 0.5) - 2 * mMenuHorizontalPadding) - + 2 * mMenuHorizontalPadding; - listView.setPadding(mMenuHorizontalPadding, mMenuVerticalPadding, - mMenuHorizontalPadding, mMenuVerticalPadding); + int width = Math.max(maxWidth, (int) (parentWidth * 0.5)); + listView.setPadding(0, mMenuVerticalPadding, 0, mMenuVerticalPadding); setWidth(width); setHorizontalOffset(getAnchorView().getWidth() - mGlobalActionsSidePadding - width); @@ -111,4 +111,8 @@ public class GlobalActionsPopupMenu extends ListPopupWindow { super.show(); } + + public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) { + mOnItemLongClickListener = listener; + } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt index 009f5494cefe..cf7fbfa9461e 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDataManager.kt @@ -36,6 +36,7 @@ import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.statusbar.notification.MediaNotificationProcessor import com.android.systemui.statusbar.notification.row.HybridGroupManager +import com.android.systemui.util.Assert import com.android.systemui.util.Utils import java.io.IOException import java.util.concurrent.Executor @@ -85,6 +86,7 @@ class MediaDataManager @Inject constructor( fun onNotificationAdded(key: String, sbn: StatusBarNotification) { if (Utils.useQsMediaPlayer(context) && isMediaNotification(sbn)) { + Assert.isMainThread() if (!mediaEntries.containsKey(key)) { mediaEntries.put(key, LOADING) } @@ -269,19 +271,23 @@ class MediaDataManager @Inject constructor( } fun onMediaDataLoaded(key: String, data: MediaData) { + Assert.isMainThread() if (mediaEntries.containsKey(key)) { // Otherwise this was removed already mediaEntries.put(key, data) - listeners.forEach { + val listenersCopy = listeners.toSet() + listenersCopy.forEach { it.onMediaDataLoaded(key, data) } } } fun onNotificationRemoved(key: String) { + Assert.isMainThread() val removed = mediaEntries.remove(key) if (removed != null) { - listeners.forEach { + val listenersCopy = listeners.toSet() + listenersCopy.forEach { it.onMediaDataRemoved(key) } } diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt index 0b04fd060766..552fea63a278 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt +++ b/packages/SystemUI/src/com/android/systemui/media/MediaDeviceManager.kt @@ -81,7 +81,7 @@ class MediaDeviceManager @Inject constructor( private fun processDevice(key: String, device: MediaDevice?) { val enabled = device != null - val data = MediaDeviceData(enabled, device?.icon, device?.name) + val data = MediaDeviceData(enabled, device?.iconWithoutBackground, device?.name) listeners.forEach { it.onMediaDeviceChanged(key, data) } diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java index b9b8a25c6d31..a10972e8721b 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipBoundsHandler.java @@ -36,10 +36,11 @@ import android.util.Size; import android.util.TypedValue; import android.view.DisplayInfo; import android.view.Gravity; -import android.view.IWindowManager; -import android.view.WindowManagerGlobal; import android.window.WindowContainerTransaction; +import com.android.systemui.wm.DisplayController; +import com.android.systemui.wm.DisplayLayout; + import java.io.PrintWriter; import javax.inject.Inject; @@ -56,10 +57,10 @@ public class PipBoundsHandler { private static final float INVALID_SNAP_FRACTION = -1f; private final Context mContext; - private final IWindowManager mWindowManager; private final PipSnapAlgorithm mSnapAlgorithm; private final DisplayInfo mDisplayInfo = new DisplayInfo(); - private final Rect mTmpInsets = new Rect(); + private final DisplayController mDisplayController; + private final DisplayLayout mDisplayLayout; private ComponentName mLastPipComponentName; private float mReentrySnapFraction = INVALID_SNAP_FRACTION; @@ -80,11 +81,24 @@ public class PipBoundsHandler { private boolean mIsShelfShowing; private int mShelfHeight; + private final DisplayController.OnDisplaysChangedListener mDisplaysChangedListener = + new DisplayController.OnDisplaysChangedListener() { + @Override + public void onDisplayAdded(int displayId) { + if (displayId == mContext.getDisplayId()) { + mDisplayLayout.set(mDisplayController.getDisplayLayout(displayId)); + } + } + }; + @Inject - public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm) { + public PipBoundsHandler(Context context, PipSnapAlgorithm pipSnapAlgorithm, + DisplayController displayController) { mContext = context; mSnapAlgorithm = pipSnapAlgorithm; - mWindowManager = WindowManagerGlobal.getWindowManagerService(); + mDisplayLayout = new DisplayLayout(); + mDisplayController = displayController; + mDisplayController.addDisplayWindowListener(mDisplaysChangedListener); reloadResources(); // Initialize the aspect ratio to the default aspect ratio. Don't do this in reload // resources as it would clobber mAspectRatio when entering PiP from fullscreen which @@ -272,8 +286,8 @@ public class PipBoundsHandler { * * @return {@code true} if internal {@link DisplayInfo} is rotated, {@code false} otherwise. */ - public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, int displayId, - int fromRotation, int toRotation, WindowContainerTransaction t) { + public boolean onDisplayRotationChanged(Rect outBounds, Rect oldBounds, Rect outInsetBounds, + int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) { // Bail early if the event is not sent to current {@link #mDisplayInfo} if ((displayId != mDisplayInfo.displayId) || (fromRotation == toRotation)) { return false; @@ -294,6 +308,9 @@ public class PipBoundsHandler { 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. @@ -308,6 +325,7 @@ public class PipBoundsHandler { mSnapAlgorithm.applySnapFraction(postChangeStackBounds, postChangeMovementBounds, snapFraction); + getInsetBounds(outInsetBounds); outBounds.set(postChangeStackBounds); t.setBounds(pinnedStackInfo.stackToken, outBounds); return true; @@ -425,15 +443,11 @@ public class PipBoundsHandler { * Populates the bounds on the screen that the PIP can be visible in. */ protected void getInsetBounds(Rect outRect) { - try { - mWindowManager.getStableInsets(mContext.getDisplayId(), mTmpInsets); - outRect.set(mTmpInsets.left + mScreenEdgeInsets.x, - mTmpInsets.top + mScreenEdgeInsets.y, - mDisplayInfo.logicalWidth - mTmpInsets.right - mScreenEdgeInsets.x, - mDisplayInfo.logicalHeight - mTmpInsets.bottom - mScreenEdgeInsets.y); - } catch (RemoteException e) { - Log.e(TAG, "Failed to get stable insets from WM", e); - } + Rect insets = mDisplayLayout.stableInsets(); + outRect.set(insets.left + mScreenEdgeInsets.x, + insets.top + mScreenEdgeInsets.y, + mDisplayInfo.logicalWidth - insets.right - mScreenEdgeInsets.x, + mDisplayInfo.logicalHeight - insets.bottom - mScreenEdgeInsets.y); } /** diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index c2f8cb9800d0..3a8476729645 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -204,6 +204,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements private WindowContainerToken mToken; private SurfaceControl mLeash; private boolean mInPip; + private boolean mExitingPip; private @PipAnimationController.AnimationType int mOneShotAnimationType = ANIM_TYPE_BOUNDS; private PipSurfaceTransactionHelper.SurfaceControlTransactionFactory mSurfaceControlTransactionFactory; @@ -270,9 +271,9 @@ public class PipTaskOrganizer extends TaskOrganizer implements * @param animationDurationMs duration in millisecond for the exiting PiP transition */ public void exitPip(int animationDurationMs) { - if (!mInPip || mToken == null) { + if (!mInPip || mExitingPip || mToken == null) { Log.wtf(TAG, "Not allowed to exitPip in current state" - + " mInPip=" + mInPip + " mToken=" + mToken); + + " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken); return; } @@ -312,15 +313,16 @@ public class PipTaskOrganizer extends TaskOrganizer implements } }); } + mExitingPip = true; } /** * Removes PiP immediately. */ public void removePip() { - if (!mInPip || mToken == null) { + if (!mInPip || mExitingPip || mToken == null) { Log.wtf(TAG, "Not allowed to removePip in current state" - + " mInPip=" + mInPip + " mToken=" + mToken); + + " mInPip=" + mInPip + " mExitingPip=" + mExitingPip + " mToken=" + mToken); return; } getUpdateHandler().post(() -> { @@ -332,6 +334,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements } }); mInitialState.remove(mToken.asBinder()); + mExitingPip = true; } @Override @@ -340,6 +343,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements mTaskInfo = info; mToken = mTaskInfo.token; mInPip = true; + mExitingPip = false; mLeash = leash; mInitialState.put(mToken.asBinder(), new Configuration(mTaskInfo.configuration)); mPictureInPictureParams = mTaskInfo.pictureInPictureParams; @@ -420,6 +424,7 @@ public class PipTaskOrganizer extends TaskOrganizer implements mShouldDeferEnteringPip = false; mPictureInPictureParams = null; mInPip = false; + mExitingPip = false; } @Override diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java index 64df2ffee1c6..02bf74577407 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -95,8 +95,21 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio private final DisplayChangeController.OnDisplayChangingListener mRotationController = ( int displayId, int fromRotation, int toRotation, WindowContainerTransaction t) -> { final boolean changed = mPipBoundsHandler.onDisplayRotationChanged(mTmpNormalBounds, - mPipTaskOrganizer.getLastReportedBounds(), displayId, fromRotation, toRotation, t); + mPipTaskOrganizer.getLastReportedBounds(), mTmpInsetBounds, displayId, fromRotation, + toRotation, t); if (changed) { + // If the pip was in the offset zone earlier, adjust the new bounds to the bottom of the + // movement bounds + mTouchHandler.adjustBoundsForRotation(mTmpNormalBounds, + mPipTaskOrganizer.getLastReportedBounds(), mTmpInsetBounds); + + // The bounds are being applied to a specific snap fraction, so reset any known offsets + // for the previous orientation before updating the movement bounds + mPipBoundsHandler.setShelfHeight(false , 0); + mPipBoundsHandler.onImeVisibilityChanged(false, 0); + mTouchHandler.onShelfVisibilityChanged(false, 0); + mTouchHandler.onImeVisibilityChanged(false, 0); + updateMovementBounds(mTmpNormalBounds, true /* fromRotation */, false /* fromImeAdjustment */, false /* fromShelfAdjustment */); } @@ -290,9 +303,10 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio @Override public void setShelfHeight(boolean visible, int height) { mHandler.post(() -> { - final boolean changed = mPipBoundsHandler.setShelfHeight(visible, height); + final int shelfHeight = visible ? height : 0; + final boolean changed = mPipBoundsHandler.setShelfHeight(visible, shelfHeight); if (changed) { - mTouchHandler.onShelfVisibilityChanged(visible, height); + mTouchHandler.onShelfVisibilityChanged(visible, shelfHeight); updateMovementBounds(mPipTaskOrganizer.getLastReportedBounds(), false /* fromRotation */, false /* fromImeAdjustment */, true /* fromShelfAdjustment */); diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java index 3396f7097ce0..a3185a2ad796 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java @@ -99,6 +99,7 @@ public class PipMenuActivity extends Activity { public static final int MESSAGE_ANIMATION_ENDED = 6; public static final int MESSAGE_POINTER_EVENT = 7; public static final int MESSAGE_MENU_EXPANDED = 8; + public static final int MESSAGE_FADE_OUT_MENU = 9; private static final int INITIAL_DISMISS_DELAY = 3500; private static final int POST_INTERACTION_DISMISS_DELAY = 2000; @@ -182,6 +183,10 @@ public class PipMenuActivity extends Activity { mMenuContainerAnimator.start(); break; } + case MESSAGE_FADE_OUT_MENU: { + fadeOutMenu(); + break; + } } } }; @@ -409,6 +414,18 @@ public class PipMenuActivity extends Activity { } } + /** + * Different from {@link #hideMenu()}, this function does not try to finish this menu activity + * and instead, it fades out the controls by setting the alpha to 0 directly without menu + * visibility callbacks invoked. + */ + private void fadeOutMenu() { + mMenuContainer.setAlpha(0f); + mSettingsButton.setAlpha(0f); + mDismissButton.setAlpha(0f); + mResizeHandle.setAlpha(0f); + } + private void hideMenu() { hideMenu(null); } diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java index bf2c3e9d0d6e..8b4d932619a9 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java @@ -262,6 +262,9 @@ public class PipMenuActivityController { */ public void showMenuWithDelay(int menuState, Rect stackBounds, boolean allowMenuTimeout, boolean willResizeMenu, boolean showResizeHandle) { + // hide all visible controls including close button and etc. first, this is to ensure + // menu is totally invisible during the transition to eliminate unpleasant artifacts + fadeOutMenu(); showMenuInternal(menuState, stackBounds, allowMenuTimeout, willResizeMenu, true /* withDelay */, showResizeHandle); } @@ -347,6 +350,23 @@ public class PipMenuActivityController { } } + private void fadeOutMenu() { + if (DEBUG) { + Log.d(TAG, "fadeOutMenu() state=" + mMenuState + + " hasActivity=" + (mToActivityMessenger != null) + + " callers=\n" + Debug.getCallers(5, " ")); + } + if (mToActivityMessenger != null) { + Message m = Message.obtain(); + m.what = PipMenuActivity.MESSAGE_FADE_OUT_MENU; + try { + mToActivityMessenger.send(m); + } catch (RemoteException e) { + Log.e(TAG, "Could not notify menu to fade out", e); + } + } + } + /** * Hides the menu activity. */ @@ -513,7 +533,8 @@ public class PipMenuActivityController { private void onMenuStateChanged(int menuState, boolean resize, Runnable callback) { if (DEBUG) { Log.d(TAG, "onMenuStateChanged() mMenuState=" + mMenuState - + " menuState=" + menuState + " resize=" + resize); + + " menuState=" + menuState + " resize=" + resize + + " callers=\n" + Debug.getCallers(5, " ")); } if (menuState != mMenuState) { diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java index cc3ab29daed3..4b23e678b15d 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipResizeGestureHandler.java @@ -37,6 +37,7 @@ import android.view.InputEvent; import android.view.InputEventReceiver; import android.view.InputMonitor; import android.view.MotionEvent; +import android.view.ViewConfiguration; import com.android.internal.policy.TaskResizingAlgorithm; import com.android.systemui.R; @@ -77,10 +78,12 @@ public class PipResizeGestureHandler { private final Runnable mUpdateMovementBoundsRunnable; private int mDelta; + private float mTouchSlop; private boolean mAllowGesture; private boolean mIsAttached; private boolean mIsEnabled; private boolean mEnableUserResize; + private boolean mThresholdCrossed; private InputMonitor mInputMonitor; private InputEventReceiver mInputEventReceiver; @@ -100,6 +103,7 @@ public class PipResizeGestureHandler { mPipTaskOrganizer = pipTaskOrganizer; mMovementBoundsSupplier = movementBoundsSupplier; mUpdateMovementBoundsRunnable = updateMovementBoundsRunnable; + context.getDisplay().getRealSize(mMaxSize); reloadResources(); @@ -126,6 +130,7 @@ public class PipResizeGestureHandler { private void reloadResources() { final Resources res = mContext.getResources(); mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size); + mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop(); } private void resetDragCorners() { @@ -270,7 +275,12 @@ public class PipResizeGestureHandler { break; case MotionEvent.ACTION_MOVE: // Capture inputs - mInputMonitor.pilferPointers(); + float dx = Math.abs(ev.getX() - mDownPoint.x); + float dy = Math.abs(ev.getY() - mDownPoint.y); + if (!mThresholdCrossed && dx > mTouchSlop && dy > mTouchSlop) { + mThresholdCrossed = true; + mInputMonitor.pilferPointers(); + } final Rect currentPipBounds = mMotionHelper.getBounds(); mLastResizeBounds.set(TaskResizingAlgorithm.resizeDrag(ev.getX(), ev.getY(), mDownPoint.x, mDownPoint.y, currentPipBounds, mCtrlType, mMinSize.x, @@ -288,6 +298,7 @@ public class PipResizeGestureHandler { mUpdateMovementBoundsRunnable.run(); mCtrlType = CTRL_NONE; mAllowGesture = false; + mThresholdCrossed = false; }); }); break; 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 c408caaccbfb..c274ee96b170 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -397,6 +397,15 @@ public class PipTouchHandler { mShelfHeight = shelfHeight; } + public void adjustBoundsForRotation(Rect outBounds, Rect curBounds, Rect insetBounds) { + final Rect toMovementBounds = new Rect(); + mSnapAlgorithm.getMovementBounds(outBounds, insetBounds, toMovementBounds, 0); + final int prevBottom = mMovementBounds.bottom - mMovementBoundsExtraOffsets; + if ((prevBottom - mBottomOffsetBufferPx) <= curBounds.top) { + outBounds.offsetTo(outBounds.left, toMovementBounds.bottom); + } + } + public void onMovementBoundsChanged(Rect insetBounds, Rect normalBounds, Rect curBounds, boolean fromImeAdjustment, boolean fromShelfAdjustment, int displayRotation) { final int bottomOffset = mIsImeShowing ? mImeHeight : 0; diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java index fe84d81836e8..387490311644 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java +++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java @@ -31,6 +31,8 @@ import android.graphics.PixelFormat; import android.graphics.drawable.ColorDrawable; import android.os.Binder; import android.os.RemoteException; +import android.text.SpannableStringBuilder; +import android.text.style.BulletSpan; import android.util.DisplayMetrics; import android.view.Gravity; import android.view.View; @@ -293,8 +295,20 @@ public class ScreenPinningRequest implements View.OnClickListener, .setImageDrawable(navigationBarView.getHomeDrawable()); } - ((TextView) mLayout.findViewById(R.id.screen_pinning_description)) - .setText(descriptionStringResId); + // Create a bulleted list of the default description plus the two security notes. + int gapWidth = getResources().getDimensionPixelSize( + R.dimen.screen_pinning_description_bullet_gap_width); + SpannableStringBuilder description = new SpannableStringBuilder(); + description.append(getContext().getText(descriptionStringResId), + new BulletSpan(gapWidth), /* flags */ 0); + description.append(System.lineSeparator()); + description.append(getContext().getText(R.string.screen_pinning_exposes_personal_data), + new BulletSpan(gapWidth), /* flags */ 0); + description.append(System.lineSeparator()); + description.append(getContext().getText(R.string.screen_pinning_can_open_other_apps), + new BulletSpan(gapWidth), /* flags */ 0); + ((TextView) mLayout.findViewById(R.id.screen_pinning_description)).setText(description); + final int backBgVisibility = touchExplorationEnabled ? View.INVISIBLE : View.VISIBLE; mLayout.findViewById(R.id.screen_pinning_back_bg).setVisibility(backBgVisibility); mLayout.findViewById(R.id.screen_pinning_back_bg_light).setVisibility(backBgVisibility); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java index f2d2eb3a0836..33d692f8e1e5 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java @@ -431,7 +431,13 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset data.createDeleteAction = false; if (mSaveInBgTask != null) { - mSaveInBgTask.ignoreResult(); + // just log success/failure for the pre-existing screenshot + mSaveInBgTask.setActionsReadyListener(new ActionsReadyListener() { + @Override + void onActionsReady(SavedImageData imageData) { + logSuccessOnActionsReady(imageData); + } + }); } mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data); @@ -637,6 +643,52 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset } /** + * Sets up the action shade and its entrance animation, once we get the screenshot URI. + */ + private void showUiOnActionsReady(SavedImageData imageData) { + logSuccessOnActionsReady(imageData); + if (imageData.uri != null) { + mScreenshotHandler.post(() -> { + if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) { + mScreenshotAnimation.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + super.onAnimationEnd(animation); + createScreenshotActionsShadeAnimation(imageData).start(); + } + }); + } else { + createScreenshotActionsShadeAnimation(imageData).start(); + } + + AccessibilityManager accessibilityManager = (AccessibilityManager) + mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); + long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis( + SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS, + AccessibilityManager.FLAG_CONTENT_CONTROLS); + + mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); + mScreenshotHandler.sendMessageDelayed( + mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT), + timeoutMs); + }); + } + } + + /** + * Logs success/failure of the screenshot saving task, and shows an error if it failed. + */ + private void logSuccessOnActionsReady(SavedImageData imageData) { + if (imageData.uri == null) { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED); + mNotificationsController.notifyScreenshotError( + R.string.screenshot_failed_to_capture_text); + } else { + mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED); + } + } + + /** * Starts the animation after taking the screenshot */ private void startAnimation(final Consumer<Uri> finisher, int w, int h, @@ -651,43 +703,11 @@ public class GlobalScreenshot implements ViewTreeObserver.OnComputeInternalInset mScreenshotAnimation = createScreenshotDropInAnimation(w, h, screenRect); saveScreenshotInWorkerThread(finisher, new ActionsReadyListener() { - @Override - void onActionsReady(SavedImageData imageData) { - finisher.accept(imageData.uri); - if (imageData.uri == null) { - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_NOT_SAVED); - mNotificationsController.notifyScreenshotError( - R.string.screenshot_failed_to_capture_text); - } else { - mUiEventLogger.log(ScreenshotEvent.SCREENSHOT_SAVED); - mScreenshotHandler.post(() -> { - if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) { - mScreenshotAnimation.addListener( - new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - super.onAnimationEnd(animation); - createScreenshotActionsShadeAnimation(imageData) - .start(); - } - }); - } else { - createScreenshotActionsShadeAnimation(imageData).start(); - } - AccessibilityManager accessibilityManager = (AccessibilityManager) - mContext.getSystemService(Context.ACCESSIBILITY_SERVICE); - long timeoutMs = accessibilityManager.getRecommendedTimeoutMillis( - SCREENSHOT_CORNER_DEFAULT_TIMEOUT_MILLIS, - AccessibilityManager.FLAG_CONTENT_CONTROLS); - - mScreenshotHandler.removeMessages(MESSAGE_CORNER_TIMEOUT); - mScreenshotHandler.sendMessageDelayed( - mScreenshotHandler.obtainMessage(MESSAGE_CORNER_TIMEOUT), - timeoutMs); - }); - } - } - }); + @Override + void onActionsReady(SavedImageData imageData) { + showUiOnActionsReady(imageData); + } + }); mScreenshotHandler.post(() -> { if (!mScreenshotLayout.isAttachedToWindow()) { mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams); diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java index e88ce5a96f87..a5bab212e6b7 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java @@ -26,7 +26,6 @@ import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; -import android.content.pm.UserInfo; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.drawable.Icon; @@ -146,7 +145,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { CompletableFuture<List<Notification.Action>> smartActionsFuture = ScreenshotSmartActions.getSmartActionsFuture( mScreenshotId, uri, image, mSmartActionsProvider, - mSmartActionsEnabled, isManagedProfile(mContext)); + mSmartActionsEnabled, getUserHandle(mContext)); try { // First, write the actual data for our screenshot @@ -215,6 +214,7 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mImageData.deleteAction = createDeleteAction(mContext, mContext.getResources(), uri); mParams.mActionsReadyListener.onActionsReady(mImageData); + mParams.finisher.accept(mImageData.uri); mParams.image = null; mParams.errorMsgResId = 0; } catch (Exception e) { @@ -225,22 +225,18 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { mParams.errorMsgResId = R.string.screenshot_failed_to_save_text; mImageData.reset(); mParams.mActionsReadyListener.onActionsReady(mImageData); + mParams.finisher.accept(null); } return null; } /** - * If we get a new screenshot request while this one is saving, we want to continue saving in - * the background but not return anything. + * Update the listener run when the saving task completes. Used to avoid showing UI for the + * first screenshot when a second one is taken. */ - void ignoreResult() { - mParams.mActionsReadyListener = new GlobalScreenshot.ActionsReadyListener() { - @Override - void onActionsReady(GlobalScreenshot.SavedImageData imageData) { - // do nothing - } - }; + void setActionsReadyListener(GlobalScreenshot.ActionsReadyListener listener) { + mParams.mActionsReadyListener = listener; } @Override @@ -382,10 +378,9 @@ class SaveImageInBackgroundTask extends AsyncTask<Void, Void, Void> { } } - private boolean isManagedProfile(Context context) { + private UserHandle getUserHandle(Context context) { UserManager manager = UserManager.get(context); - UserInfo info = manager.getUserInfo(getUserHandleOfForegroundApplication(context)); - return info.isManagedProfile(); + return manager.getUserInfo(getUserHandleOfForegroundApplication(context)).getUserHandle(); } private List<Notification.Action> buildSmartActions( diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java index 3edb33da9cd0..63f323ed2768 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsProvider.java @@ -20,6 +20,7 @@ import android.app.Notification; import android.content.ComponentName; import android.graphics.Bitmap; import android.net.Uri; +import android.os.UserHandle; import android.util.Log; import java.util.Collections; @@ -64,14 +65,14 @@ public class ScreenshotNotificationSmartActionsProvider { * @param componentName Contains package and activity class names where the screenshot was * taken. This is used as an additional signal to generate and rank * more relevant actions. - * @param isManagedProfile The screenshot was taken for a work profile app. + * @param userHandle The user handle of the app where the screenshot was taken. */ public CompletableFuture<List<Notification.Action>> getActions( String screenshotId, Uri screenshotUri, Bitmap bitmap, ComponentName componentName, - boolean isManagedProfile) { + UserHandle userHandle) { Log.d(TAG, "Returning empty smart action list."); return CompletableFuture.completedFuture(Collections.emptyList()); } diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java index c228fe2c4334..442b373b31be 100644 --- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java +++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotSmartActions.java @@ -26,6 +26,7 @@ import android.graphics.Bitmap; import android.net.Uri; import android.os.Handler; import android.os.SystemClock; +import android.os.UserHandle; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -48,7 +49,7 @@ public class ScreenshotSmartActions { static CompletableFuture<List<Notification.Action>> getSmartActionsFuture( String screenshotId, Uri screenshotUri, Bitmap image, ScreenshotNotificationSmartActionsProvider smartActionsProvider, - boolean smartActionsEnabled, boolean isManagedProfile) { + boolean smartActionsEnabled, UserHandle userHandle) { if (!smartActionsEnabled) { Slog.i(TAG, "Screenshot Intelligence not enabled, returning empty list."); return CompletableFuture.completedFuture(Collections.emptyList()); @@ -60,7 +61,7 @@ public class ScreenshotSmartActions { return CompletableFuture.completedFuture(Collections.emptyList()); } - Slog.d(TAG, "Screenshot from a managed profile: " + isManagedProfile); + Slog.d(TAG, "Screenshot from user profile: " + userHandle.getIdentifier()); CompletableFuture<List<Notification.Action>> smartActionsFuture; long startTimeMs = SystemClock.uptimeMillis(); try { @@ -71,7 +72,7 @@ public class ScreenshotSmartActions { ? runningTask.topActivity : new ComponentName("", ""); smartActionsFuture = smartActionsProvider.getActions( - screenshotId, screenshotUri, image, componentName, isManagedProfile); + screenshotId, screenshotUri, image, componentName, userHandle); } catch (Throwable e) { long waitTimeMs = SystemClock.uptimeMillis() - startTimeMs; smartActionsFuture = CompletableFuture.completedFuture(Collections.emptyList()); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt index 2ed04eb088a3..9dbec1037aa5 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInteractionTracker.kt @@ -22,7 +22,9 @@ class NotificationInteractionTracker @Inject constructor( entryManager.addCollectionListener(this) } - fun hasUserInteractedWith(key: String): Boolean = key in interactions + fun hasUserInteractedWith(key: String): Boolean { + return interactions[key] ?: false + } override fun onEntryAdded(entry: NotificationEntry) { interactions[entry.key] = false diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java index 85560fefd952..6aef6b407f37 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimator.java @@ -19,7 +19,6 @@ package com.android.systemui.statusbar.notification; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ValueAnimator; -import android.annotation.Nullable; import android.app.ActivityManager; import android.graphics.Matrix; import android.graphics.Rect; @@ -42,8 +41,6 @@ import com.android.systemui.statusbar.phone.CollapsedStatusBarFragment; import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController; -import java.util.concurrent.Executor; - /** * A class that allows activities to be launched in a seamless way where the notification * transforms nicely into the starting window. @@ -62,7 +59,6 @@ public class ActivityLaunchAnimator { private final float mWindowCornerRadius; private final NotificationShadeWindowViewController mNotificationShadeWindowViewController; private final NotificationShadeDepthController mDepthController; - private final Executor mMainExecutor; private Callback mCallback; private final Runnable mTimeoutRunnable = () -> { setAnimationPending(false); @@ -77,14 +73,12 @@ public class ActivityLaunchAnimator { Callback callback, NotificationPanelViewController notificationPanel, NotificationShadeDepthController depthController, - NotificationListContainer container, - Executor mainExecutor) { + NotificationListContainer container) { mNotificationPanel = notificationPanel; mNotificationContainer = container; mDepthController = depthController; mNotificationShadeWindowViewController = notificationShadeWindowViewController; mCallback = callback; - mMainExecutor = mainExecutor; mWindowCornerRadius = ScreenDecorationsUtils .getWindowCornerRadius(mNotificationShadeWindowViewController.getView() .getResources()); @@ -97,7 +91,7 @@ public class ActivityLaunchAnimator { return null; } AnimationRunner animationRunner = new AnimationRunner( - (ExpandableNotificationRow) sourceView, mMainExecutor); + (ExpandableNotificationRow) sourceView); return new RemoteAnimationAdapter(animationRunner, ANIMATION_DURATION, ANIMATION_DURATION - 150 /* statusBarTransitionDelay */); } @@ -140,18 +134,17 @@ public class ActivityLaunchAnimator { class AnimationRunner extends IRemoteAnimationRunner.Stub { - private final ExpandAnimationParameters mParams = new ExpandAnimationParameters(); + private final ExpandableNotificationRow mSourceNotification; + private final ExpandAnimationParameters mParams; private final Rect mWindowCrop = new Rect(); private final float mNotificationCornerRadius; - private final Executor mMainExecutor; - @Nullable private ExpandableNotificationRow mSourceNotification; - @Nullable private SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier; private float mCornerRadius; private boolean mIsFullScreenLaunch = true; + private final SyncRtSurfaceTransactionApplier mSyncRtTransactionApplier; - AnimationRunner(ExpandableNotificationRow sourceNotification, Executor mainExecutor) { - mMainExecutor = mainExecutor; - mSourceNotification = sourceNotification; + public AnimationRunner(ExpandableNotificationRow sourceNofitication) { + mSourceNotification = sourceNofitication; + mParams = new ExpandAnimationParameters(); mSyncRtTransactionApplier = new SyncRtSurfaceTransactionApplier(mSourceNotification); mNotificationCornerRadius = Math.max(mSourceNotification.getCurrentTopRoundness(), mSourceNotification.getCurrentBottomRoundness()); @@ -162,15 +155,13 @@ public class ActivityLaunchAnimator { RemoteAnimationTarget[] remoteAnimationWallpaperTargets, IRemoteAnimationFinishedCallback iRemoteAnimationFinishedCallback) throws RemoteException { - mMainExecutor.execute(() -> { + mSourceNotification.post(() -> { RemoteAnimationTarget primary = getPrimaryRemoteAnimationTarget( remoteAnimationTargets); - if (primary == null || mSourceNotification == null) { + if (primary == null) { setAnimationPending(false); invokeCallback(iRemoteAnimationFinishedCallback); mNotificationPanel.collapse(false /* delayed */, 1.0f /* speedUpFactor */); - mSourceNotification = null; - mSyncRtTransactionApplier = null; return; } @@ -181,14 +172,28 @@ public class ActivityLaunchAnimator { if (!mIsFullScreenLaunch) { mNotificationPanel.collapseWithDuration(ANIMATION_DURATION); } - mParams.initFrom(mSourceNotification); - final int targetWidth = primary.sourceContainerBounds.width(); - final int notificationHeight; - final int notificationWidth; - notificationHeight = mSourceNotification.getActualHeight() - - mSourceNotification.getClipBottomAmount(); - notificationWidth = mSourceNotification.getWidth(); ValueAnimator anim = ValueAnimator.ofFloat(0, 1); + mParams.startPosition = mSourceNotification.getLocationOnScreen(); + mParams.startTranslationZ = mSourceNotification.getTranslationZ(); + mParams.startClipTopAmount = mSourceNotification.getClipTopAmount(); + if (mSourceNotification.isChildInGroup()) { + int parentClip = mSourceNotification + .getNotificationParent().getClipTopAmount(); + mParams.parentStartClipTopAmount = parentClip; + // We need to calculate how much the child is clipped by the parent + // because children always have 0 clipTopAmount + if (parentClip != 0) { + float childClip = parentClip + - mSourceNotification.getTranslationY(); + if (childClip > 0.0f) { + mParams.startClipTopAmount = (int) Math.ceil(childClip); + } + } + } + int targetWidth = primary.sourceContainerBounds.width(); + int notificationHeight = mSourceNotification.getActualHeight() + - mSourceNotification.getClipBottomAmount(); + int notificationWidth = mSourceNotification.getWidth(); anim.setDuration(ANIMATION_DURATION); anim.setInterpolator(Interpolators.LINEAR); anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @@ -226,11 +231,6 @@ public class ActivityLaunchAnimator { }); } - @Nullable - ExpandableNotificationRow getRow() { - return mSourceNotification; - } - private void invokeCallback(IRemoteAnimationFinishedCallback callback) { try { callback.onAnimationFinished(); @@ -253,9 +253,7 @@ public class ActivityLaunchAnimator { private void setExpandAnimationRunning(boolean running) { mNotificationPanel.setLaunchingNotification(running); - if (mSourceNotification != null) { - mSourceNotification.setExpandAnimationRunning(running); - } + mSourceNotification.setExpandAnimationRunning(running); mNotificationShadeWindowViewController.setExpandAnimationRunning(running); mNotificationContainer.setExpandingNotification(running ? mSourceNotification : null); mAnimationRunning = running; @@ -263,8 +261,6 @@ public class ActivityLaunchAnimator { mCallback.onExpandAnimationFinished(mIsFullScreenLaunch); applyParamsToNotification(null); applyParamsToNotificationShade(null); - mSourceNotification = null; - mSyncRtTransactionApplier = null; } } @@ -276,9 +272,7 @@ public class ActivityLaunchAnimator { } private void applyParamsToNotification(ExpandAnimationParameters params) { - if (mSourceNotification != null) { - mSourceNotification.applyExpandAnimationParams(params); - } + mSourceNotification.applyExpandAnimationParams(params); } private void applyParamsToWindow(RemoteAnimationTarget app) { @@ -293,18 +287,14 @@ public class ActivityLaunchAnimator { .withCornerRadius(mCornerRadius) .withVisibility(true) .build(); - if (mSyncRtTransactionApplier != null) { - mSyncRtTransactionApplier.scheduleApply(true /* earlyWakeup */, params); - } + mSyncRtTransactionApplier.scheduleApply(true /* earlyWakeup */, params); } @Override public void onAnimationCancelled() throws RemoteException { - mMainExecutor.execute(() -> { + mSourceNotification.post(() -> { setAnimationPending(false); mCallback.onLaunchAnimationCancelled(); - mSourceNotification = null; - mSyncRtTransactionApplier = null; }); } }; @@ -369,28 +359,6 @@ public class ActivityLaunchAnimator { public float getStartTranslationZ() { return startTranslationZ; } - - /** Initialize with data pulled from the row. */ - void initFrom(@Nullable ExpandableNotificationRow row) { - if (row == null) { - return; - } - startPosition = row.getLocationOnScreen(); - startTranslationZ = row.getTranslationZ(); - startClipTopAmount = row.getClipTopAmount(); - if (row.isChildInGroup()) { - int parentClip = row.getNotificationParent().getClipTopAmount(); - parentStartClipTopAmount = parentClip; - // We need to calculate how much the child is clipped by the parent - // because children always have 0 clipTopAmount - if (parentClip != 0) { - float childClip = parentClip - row.getTranslationY(); - if (childClip > 0.0f) { - startClipTopAmount = (int) Math.ceil(childClip); - } - } - } - } } public interface Callback { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java index 040dbe320711..312b2c52b42e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/InstantAppNotifier.java @@ -275,7 +275,7 @@ public class InstantAppNotifier extends SystemUI 0, new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) .setData(Uri.fromParts("package", pkg, null)), - 0, + PendingIntent.FLAG_IMMUTABLE, null, user); Notification.Action action = @@ -309,7 +309,7 @@ public class InstantAppNotifier extends SystemUI mContext, 0 /* requestCode */, browserIntent, - 0 /* flags */, + PendingIntent.FLAG_IMMUTABLE /* flags */, null, user); ComponentName aiaComponent = null; @@ -331,8 +331,8 @@ public class InstantAppNotifier extends SystemUI .putExtra(Intent.EXTRA_LONG_VERSION_CODE, appInfo.longVersionCode) .putExtra(Intent.EXTRA_INSTANT_APP_FAILURE, pendingIntent); - PendingIntent webPendingIntent = - PendingIntent.getActivityAsUser(mContext, 0, goToWebIntent, 0, null, user); + PendingIntent webPendingIntent = PendingIntent.getActivityAsUser(mContext, 0, + goToWebIntent, PendingIntent.FLAG_IMMUTABLE, null, user); Notification.Action webAction = new Notification.Action.Builder( null, mContext.getString(R.string.go_to_web), webPendingIntent) diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java index 1eadd9ebfd7f..33771449abc9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java @@ -41,6 +41,7 @@ import android.app.Notification.MessagingStyle.Message; import android.app.NotificationChannel; import android.app.NotificationManager.Policy; import android.app.Person; +import android.app.RemoteInput; import android.app.RemoteInputHistoryItem; import android.content.Context; import android.content.pm.ShortcutInfo; @@ -69,6 +70,7 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController; import com.android.systemui.statusbar.notification.row.NotificationGuts; import com.android.systemui.statusbar.notification.stack.PriorityBucket; +import com.android.systemui.statusbar.phone.NotificationGroupManager; import java.util.ArrayList; import java.util.List; @@ -132,7 +134,7 @@ public final class NotificationEntry extends ListEntry { private ShortcutInfo mShortcutInfo; /** - * If {@link android.app.RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is + * If {@link RemoteInput#getEditChoicesBeforeSending} is enabled, and the user is * currently editing a choice (smart reply), then this field contains the information about the * suggestion being edited. Otherwise <code>null</code>. */ @@ -174,6 +176,8 @@ public final class NotificationEntry extends ListEntry { private boolean mPulseSupressed; private boolean mAllowFgsDismissal; private int mBucket = BUCKET_ALERTING; + @Nullable private Long mPendingAnimationDuration; + private boolean mIsMarkedForUserTriggeredMovement; /** * @param sbn the StatusBarNotification from system server @@ -193,7 +197,7 @@ public final class NotificationEntry extends ListEntry { boolean allowFgsDismissal, long creationTime ) { - super(requireNonNull(Objects.requireNonNull(sbn).getKey())); + super(requireNonNull(requireNonNull(sbn).getKey())); requireNonNull(ranking); @@ -441,7 +445,7 @@ public final class NotificationEntry extends ListEntry { * Get the children that are actually attached to this notification's row. * * TODO: Seems like most callers here should probably be using - * {@link com.android.systemui.statusbar.phone.NotificationGroupManager#getChildren} + * {@link NotificationGroupManager#getChildren} */ public @Nullable List<NotificationEntry> getAttachedNotifChildren() { if (row == null) { @@ -809,7 +813,7 @@ public final class NotificationEntry extends ListEntry { } if ((mSbn.getNotification().flags - & Notification.FLAG_FOREGROUND_SERVICE) != 0) { + & FLAG_FOREGROUND_SERVICE) != 0) { return true; } if (mSbn.getNotification().isMediaNotification()) { @@ -942,6 +946,19 @@ public final class NotificationEntry extends ListEntry { mPulseSupressed = suppressed; } + /** Whether or not this entry has been marked for a user-triggered movement. */ + public boolean isMarkedForUserTriggeredMovement() { + return mIsMarkedForUserTriggeredMovement; + } + + /** + * Mark this entry for movement triggered by a user action (ex: changing the priorirty of a + * conversation). This can then be used for custom animations. + */ + public void markForUserTriggeredMovement(boolean marked) { + mIsMarkedForUserTriggeredMovement = marked; + } + /** Information about a suggestion that is being edited. */ public static class EditedSuggestionInfo { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java index f55ce77060a5..033a638bdd73 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java @@ -25,6 +25,7 @@ import android.view.accessibility.AccessibilityManager; import com.android.internal.logging.MetricsLogger; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -105,6 +106,7 @@ public interface NotificationsModule { VisualStabilityManager visualStabilityManager, Lazy<StatusBar> statusBarLazy, @Main Handler mainHandler, + @Background Handler bgHandler, AccessibilityManager accessibilityManager, HighPriorityProvider highPriorityProvider, INotificationManager notificationManager, @@ -118,6 +120,7 @@ public interface NotificationsModule { visualStabilityManager, statusBarLazy, mainHandler, + bgHandler, accessibilityManager, highPriorityProvider, notificationManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java index da31fe03c9e7..71f6dac4e234 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/interruption/NotificationInterruptStateProviderImpl.java @@ -146,14 +146,6 @@ public class NotificationInterruptStateProviderImpl implements NotificationInter return false; } - if (!entry.isBubble()) { - if (DEBUG) { - Log.d(TAG, "No bubble up: notification " + sbn.getKey() - + " is bubble? " + entry.isBubble()); - } - return false; - } - if (entry.getBubbleMetadata() == null || (entry.getBubbleMetadata().getShortcutId() == null && entry.getBubbleMetadata().getIntent() == null)) { 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 10fc990e2c5b..9dcc187cb0ef 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 @@ -189,6 +189,11 @@ public class AppOpsInfo extends LinearLayout implements NotificationGuts.GutsCon } @Override + public boolean needsFalsingProtection() { + return false; + } + + @Override public View getContentView() { return this; } 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 e0583be1935d..9befa313edd8 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 @@ -16,7 +16,6 @@ package com.android.systemui.statusbar.notification.row; -import static android.app.Notification.EXTRA_IS_GROUP_CONVERSATION; import static android.app.NotificationManager.BUBBLE_PREFERENCE_ALL; import static android.app.NotificationManager.BUBBLE_PREFERENCE_NONE; import static android.app.NotificationManager.BUBBLE_PREFERENCE_SELECTED; @@ -43,9 +42,7 @@ import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; -import android.graphics.drawable.Icon; import android.os.Handler; -import android.os.Parcelable; import android.os.RemoteException; import android.provider.Settings; import android.service.notification.StatusBarNotification; @@ -65,15 +62,16 @@ import android.widget.TextView; import com.android.internal.annotations.VisibleForTesting; import com.android.settingslib.notification.ConversationIconFactory; -import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; +import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.statusbar.notification.NotificationChannelHelper; import com.android.systemui.statusbar.notification.VisualStabilityManager; import com.android.systemui.statusbar.notification.collection.NotificationEntry; +import com.android.systemui.statusbar.notification.stack.StackStateAnimator; import java.lang.annotation.Retention; -import java.util.List; import javax.inject.Provider; @@ -86,10 +84,12 @@ public class NotificationConversationInfo extends LinearLayout implements private INotificationManager mINotificationManager; - ShortcutManager mShortcutManager; + private ShortcutManager mShortcutManager; private PackageManager mPm; private ConversationIconFactory mIconFactory; private VisualStabilityManager mVisualStabilityManager; + private Handler mMainHandler; + private Handler mBgHandler; private String mPackageName; private String mAppName; @@ -97,6 +97,7 @@ public class NotificationConversationInfo extends LinearLayout implements private String mDelegatePkg; private NotificationChannel mNotificationChannel; private ShortcutInfo mShortcutInfo; + private NotificationEntry mEntry; private StatusBarNotification mSbn; @Nullable private Notification.BubbleMetadata mBubbleMetadata; private Context mUserContext; @@ -213,11 +214,14 @@ public class NotificationConversationInfo extends LinearLayout implements ConversationIconFactory conversationIconFactory, Context userContext, Provider<PriorityOnboardingDialogController.Builder> builderProvider, - boolean isDeviceProvisioned) { + boolean isDeviceProvisioned, + @Main Handler mainHandler, + @Background Handler bgHandler) { mSelectedAction = -1; mINotificationManager = iNotificationManager; mVisualStabilityManager = visualStabilityManager; mPackageName = pkg; + mEntry = entry; mSbn = entry.getSbn(); mPm = pm; mAppName = mPackageName; @@ -231,7 +235,8 @@ public class NotificationConversationInfo extends LinearLayout implements mUserContext = userContext; mBubbleMetadata = bubbleMetadata; mBuilderProvider = builderProvider; - + mMainHandler = mainHandler; + mBgHandler = bgHandler; mShortcutManager = shortcutManager; mShortcutInfo = entry.getRanking().getShortcutInfo(); if (mShortcutInfo == null) { @@ -399,6 +404,11 @@ public class NotificationConversationInfo extends LinearLayout implements } @Override + public boolean needsFalsingProtection() { + return true; + } + + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); if (mGutsContainer != null && @@ -494,11 +504,13 @@ public class NotificationConversationInfo extends LinearLayout implements } private void updateChannel() { - Handler bgHandler = new Handler(Dependency.get(Dependency.BG_LOOPER)); - bgHandler.post( + mBgHandler.post( new UpdateChannelRunnable(mINotificationManager, mPackageName, mAppUid, mSelectedAction, mNotificationChannel)); - mVisualStabilityManager.temporarilyAllowReordering(); + mMainHandler.postDelayed(() -> { + mEntry.markForUserTriggeredMovement(true); + mVisualStabilityManager.temporarilyAllowReordering(); + }, StackStateAnimator.ANIMATION_DURATION_STANDARD); } private boolean shouldShowPriorityOnboarding() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java index 18d436ff7659..c762b73a1648 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGuts.java @@ -104,6 +104,12 @@ public class NotificationGuts extends FrameLayout { * Called when the guts view has finished its close animation. */ default void onFinishedClosing() {} + + /** + * Returns whether falsing protection is needed before showing the contents of this + * view on the lockscreen + */ + boolean needsFalsingProtection(); } public interface OnGutsClosedListener { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java index 3f7c7ca799d6..a64dcdffff1e 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationGutsManager.java @@ -46,6 +46,7 @@ import com.android.settingslib.notification.ConversationIconFactory; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; +import com.android.systemui.dagger.qualifiers.Background; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin; import com.android.systemui.plugins.statusbar.StatusBarStateController; @@ -111,6 +112,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx private final Lazy<StatusBar> mStatusBarLazy; private final Handler mMainHandler; + private final Handler mBgHandler; private Runnable mOpenRunnable; private final INotificationManager mNotificationManager; private final LauncherApps mLauncherApps; @@ -122,7 +124,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx * Injected constructor. See {@link NotificationsModule}. */ public NotificationGutsManager(Context context, VisualStabilityManager visualStabilityManager, - Lazy<StatusBar> statusBarLazy, @Main Handler mainHandler, + Lazy<StatusBar> statusBarLazy, @Main Handler mainHandler, @Background Handler bgHandler, AccessibilityManager accessibilityManager, HighPriorityProvider highPriorityProvider, INotificationManager notificationManager, @@ -135,6 +137,7 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx mVisualStabilityManager = visualStabilityManager; mStatusBarLazy = statusBarLazy; mMainHandler = mainHandler; + mBgHandler = bgHandler; mAccessibilityManager = accessibilityManager; mHighPriorityProvider = highPriorityProvider; mNotificationManager = notificationManager; @@ -463,7 +466,9 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx iconFactoryLoader, mContextTracker.getCurrentUserContext(), mBuilderProvider, - mDeviceProvisionedController.isDeviceProvisioned()); + mDeviceProvisionedController.isDeviceProvisioned(), + mMainHandler, + mBgHandler); } /** @@ -518,23 +523,27 @@ public class NotificationGutsManager implements Dumpable, NotificationLifetimeEx int x, int y, NotificationMenuRowPlugin.MenuItem menuItem) { - if (menuItem.getGutsView() instanceof NotificationInfo) { - if (mStatusBarStateController instanceof StatusBarStateControllerImpl) { - ((StatusBarStateControllerImpl) mStatusBarStateController) - .setLeaveOpenOnKeyguardHide(true); - } + if (menuItem.getGutsView() instanceof NotificationGuts.GutsContent) { + NotificationGuts.GutsContent gutsView = + (NotificationGuts.GutsContent) menuItem.getGutsView(); + if (gutsView.needsFalsingProtection()) { + if (mStatusBarStateController instanceof StatusBarStateControllerImpl) { + ((StatusBarStateControllerImpl) mStatusBarStateController) + .setLeaveOpenOnKeyguardHide(true); + } - Runnable r = () -> mMainHandler.post( - () -> openGutsInternal(view, x, y, menuItem)); + Runnable r = () -> mMainHandler.post( + () -> openGutsInternal(view, x, y, menuItem)); - mStatusBarLazy.get().executeRunnableDismissingKeyguard( - r, - null /* cancelAction */, - false /* dismissShade */, - true /* afterKeyguardGone */, - true /* deferred */); + mStatusBarLazy.get().executeRunnableDismissingKeyguard( + r, + null /* cancelAction */, + false /* dismissShade */, + true /* afterKeyguardGone */, + true /* deferred */); - return true; + return true; + } } return openGutsInternal(view, x, y, menuItem); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java index 91c31cf58ea0..334599930b63 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationInfo.java @@ -490,6 +490,11 @@ public class NotificationInfo extends LinearLayout implements NotificationGuts.G } @Override + public boolean needsFalsingProtection() { + return true; + } + + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); if (mGutsContainer != null && diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java index e56771c62bb5..cde3dfd66aaf 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationSnooze.java @@ -442,6 +442,11 @@ public class NotificationSnooze extends LinearLayout return true; } + @Override + public boolean needsFalsingProtection() { + return false; + } + public class NotificationSnoozeOption implements SnoozeOption { private SnoozeCriterion mCriterion; private int mMinutesToSnoozeFor; 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 1dc828bfb0b5..ea059cbcf3e1 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 @@ -301,6 +301,11 @@ public class PartialConversationInfo extends LinearLayout implements } @Override + public boolean needsFalsingProtection() { + return true; + } + + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); if (mGutsContainer != null && 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 14fbe28850d5..fc203a0d857f 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 @@ -3679,8 +3679,19 @@ public class NotificationStackScrollLayout extends ViewGroup implements ScrollAd @ShadeViewRefactor(RefactorComponent.STATE_RESOLVER) private void generatePositionChangeEvents() { for (ExpandableView child : mChildrenChangingPositions) { - mAnimationEvents.add(new AnimationEvent(child, - AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION)); + Integer duration = null; + if (child instanceof ExpandableNotificationRow) { + ExpandableNotificationRow row = (ExpandableNotificationRow) child; + if (row.getEntry().isMarkedForUserTriggeredMovement()) { + duration = StackStateAnimator.ANIMATION_DURATION_PRIORITY_CHANGE; + row.getEntry().markForUserTriggeredMovement(false); + } + } + AnimationEvent animEvent = duration == null + ? new AnimationEvent(child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION) + : new AnimationEvent( + child, AnimationEvent.ANIMATION_TYPE_CHANGE_POSITION, duration); + mAnimationEvents.add(animEvent); } mChildrenChangingPositions.clear(); if (mGenerateChildOrderChangedEvent) { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java index 6c0655e7e3b3..d7d09e05c238 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelper.java @@ -426,8 +426,8 @@ class NotificationSwipeHelper extends SwipeHelper implements NotificationSwipeAc final int height = (view instanceof ExpandableView) ? ((ExpandableView) view).getActualHeight() : view.getHeight(); - final int rx = (int) ev.getRawX(); - final int ry = (int) ev.getRawY(); + final int rx = (int) ev.getX(); + final int ry = (int) ev.getY(); int[] temp = new int[2]; view.getLocationOnScreen(temp); final int x = temp[0]; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java index 77850826a5e1..d4add958ad1f 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java @@ -56,6 +56,7 @@ public class StackStateAnimator { public static final int ANIMATION_DURATION_PULSE_APPEAR = KeyguardSliceView.DEFAULT_ANIM_DURATION; public static final int ANIMATION_DURATION_BLOCKING_HELPER_FADE = 240; + public static final int ANIMATION_DURATION_PRIORITY_CHANGE = 500; public static final int ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING = 80; public static final int ANIMATION_DELAY_PER_ELEMENT_MANUAL = 32; public static final int ANIMATION_DELAY_PER_ELEMENT_GO_TO_FULL_SHADE = 48; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java index 8bcdbfef3240..978394ca05ab 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/EdgeBackGestureHandler.java @@ -624,6 +624,7 @@ public class EdgeBackGestureHandler extends CurrentUserTracker implements Displa pw.println(" mIsBackGestureAllowed=" + mIsBackGestureAllowed); pw.println(" mAllowGesture=" + mAllowGesture); pw.println(" mDisabledForQuickstep=" + mDisabledForQuickstep); + pw.println(" mStartingQuickstepRotation=" + mStartingQuickstepRotation); pw.println(" mInRejectedExclusion" + mInRejectedExclusion); pw.println(" mExcludeRegion=" + mExcludeRegion); pw.println(" mUnrestrictedExcludeRegion=" + mUnrestrictedExcludeRegion); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java index dcc31075a2ac..67b7e979f62d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java @@ -18,10 +18,8 @@ package com.android.systemui.statusbar.phone; import static com.android.systemui.DejankUtils.whitelistIpcs; -import android.app.admin.DevicePolicyManager; import android.content.Context; import android.os.UserManager; -import android.provider.Settings; import android.text.TextUtils; import android.util.AttributeSet; import android.view.View; @@ -97,33 +95,9 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener } public boolean isMultiUserEnabled() { - // Short-circuiting from UserManager. Needs to be extracted because of SystemUI boolean flag - // qs_show_user_switcher_for_single_user - // TODO(b/138661450) Move IPC calls to background - return whitelistIpcs(() -> { - // The default in UserManager is to show the switcher. We want to not show it unless the - // user explicitly requests it in Settings - final boolean userSwitcherEnabled = Settings.Global.getInt( - mContext.getContentResolver(), - Settings.Global.USER_SWITCHER_ENABLED, 0) != 0; - - if (!userSwitcherEnabled - || !UserManager.supportsMultipleUsers() - || UserManager.isDeviceInDemoMode(mContext) - || mUserManager.hasUserRestriction(UserManager.DISALLOW_USER_SWITCH)) { - return false; - } - - final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class) - .getGuestUserDisabled(null); - return mUserSwitcherController.getSwitchableUserCount() > 1 - // If we cannot add guests even if they are enabled, do not show - || (guestEnabled && !mUserManager.hasUserRestriction( - UserManager.DISALLOW_ADD_USER)) - || mContext.getResources().getBoolean( - R.bool.qs_show_user_switcher_for_single_user); - }); + return whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled( + mContext.getResources().getBoolean(R.bool.qs_show_user_switcher_for_single_user))); } private void registerListener() { @@ -175,7 +149,7 @@ public class MultiUserSwitch extends FrameLayout implements View.OnClickListener private void refreshContentDescription() { String currentUser = null; // TODO(b/138661450) - if (whitelistIpcs(mUserManager::isUserSwitcherEnabled) + if (whitelistIpcs(() -> mUserManager.isUserSwitcherEnabled()) && mUserSwitcherController != null) { currentUser = mUserSwitcherController.getCurrentUserName(mContext); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java index 662c744f8c95..46c873db8a08 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java @@ -93,7 +93,6 @@ public class NavigationBarInflaterView extends FrameLayout private boolean mIsVertical; private boolean mAlternativeOrder; - private boolean mUsingCustomLayout; private OverviewProxyService mOverviewProxyService; private int mNavBarMode = NAV_BAR_MODE_3BUTTON; @@ -145,7 +144,6 @@ public class NavigationBarInflaterView extends FrameLayout @Override public void onNavigationModeChanged(int mode) { mNavBarMode = mode; - onLikelyDefaultLayoutChange(); } @Override @@ -154,17 +152,7 @@ public class NavigationBarInflaterView extends FrameLayout super.onDetachedFromWindow(); } - public void setNavigationBarLayout(String layoutValue) { - if (!Objects.equals(mCurrentLayout, layoutValue)) { - mUsingCustomLayout = layoutValue != null; - clearViews(); - inflateLayout(layoutValue); - } - } - public void onLikelyDefaultLayoutChange() { - // Don't override custom layouts - if (mUsingCustomLayout) return; // Reevaluate new layout final String newValue = getDefaultLayout(); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java index 06b7d1a34b5a..daefef5e826d 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationModeController.java @@ -16,19 +16,14 @@ package com.android.systemui.statusbar.phone; -import static android.content.Intent.ACTION_OVERLAY_CHANGED; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL; import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY; -import android.content.BroadcastReceiver; import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; import android.content.om.IOverlayManager; import android.content.om.OverlayInfo; import android.content.pm.PackageManager; import android.content.res.ApkAssets; -import android.os.PatternMatcher; import android.os.RemoteException; import android.os.ServiceManager; import android.os.UserHandle; @@ -39,6 +34,7 @@ import android.util.Log; import com.android.systemui.Dumpable; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.statusbar.policy.ConfigurationController; import com.android.systemui.statusbar.policy.DeviceProvisionedController; import java.io.FileDescriptor; @@ -69,16 +65,6 @@ public class NavigationModeController implements Dumpable { private ArrayList<ModeChangedListener> mListeners = new ArrayList<>(); - private BroadcastReceiver mReceiver = new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (DEBUG) { - Log.d(TAG, "ACTION_OVERLAY_CHANGED"); - } - updateCurrentInteractionMode(true /* notify */); - } - }; - private final DeviceProvisionedController.DeviceProvisionedListener mDeviceProvisionedCallback = new DeviceProvisionedController.DeviceProvisionedListener() { @Override @@ -97,6 +83,7 @@ public class NavigationModeController implements Dumpable { @Inject public NavigationModeController(Context context, DeviceProvisionedController deviceProvisionedController, + ConfigurationController configurationController, @UiBackground Executor uiBgExecutor) { mContext = context; mCurrentUserContext = context; @@ -105,10 +92,15 @@ public class NavigationModeController implements Dumpable { mUiBgExecutor = uiBgExecutor; deviceProvisionedController.addCallback(mDeviceProvisionedCallback); - IntentFilter overlayFilter = new IntentFilter(ACTION_OVERLAY_CHANGED); - overlayFilter.addDataScheme("package"); - overlayFilter.addDataSchemeSpecificPart("android", PatternMatcher.PATTERN_LITERAL); - mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, overlayFilter, null, null); + configurationController.addCallback(new ConfigurationController.ConfigurationListener() { + @Override + public void onOverlayChanged() { + if (DEBUG) { + Log.d(TAG, "onOverlayChanged"); + } + updateCurrentInteractionMode(true /* notify */); + } + }); updateCurrentInteractionMode(false /* notify */); } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java index 2a4475bbe6b5..a065b74bda99 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicy.java @@ -46,8 +46,6 @@ import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.dagger.qualifiers.DisplayId; import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; -import com.android.systemui.media.MediaData; -import com.android.systemui.media.MediaDataManager; import com.android.systemui.qs.tiles.DndTile; import com.android.systemui.qs.tiles.RotationLockTile; import com.android.systemui.screenrecord.RecordingController; @@ -82,14 +80,14 @@ import javax.inject.Inject; */ public class PhoneStatusBarPolicy implements BluetoothController.Callback, - CommandQueue.Callbacks, - RotationLockControllerCallback, - Listener, - ZenModeController.Callback, - DeviceProvisionedListener, - KeyguardStateController.Callback, - LocationController.LocationChangeCallback, - RecordingController.RecordingStateChangeCallback, MediaDataManager.Listener { + CommandQueue.Callbacks, + RotationLockControllerCallback, + Listener, + ZenModeController.Callback, + DeviceProvisionedListener, + KeyguardStateController.Callback, + LocationController.LocationChangeCallback, + RecordingController.RecordingStateChangeCallback { private static final String TAG = "PhoneStatusBarPolicy"; private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG); @@ -110,7 +108,6 @@ public class PhoneStatusBarPolicy private final String mSlotLocation; private final String mSlotSensorsOff; private final String mSlotScreenRecord; - private final String mSlotMedia; private final int mDisplayId; private final SharedPreferences mSharedPreferences; private final DateFormatUtil mDateFormatUtil; @@ -138,7 +135,6 @@ public class PhoneStatusBarPolicy private final SensorPrivacyController mSensorPrivacyController; private final RecordingController mRecordingController; private final RingerModeTracker mRingerModeTracker; - private final MediaDataManager mMediaDataManager; private boolean mZenVisible; private boolean mVolumeVisible; @@ -163,7 +159,6 @@ public class PhoneStatusBarPolicy SensorPrivacyController sensorPrivacyController, IActivityManager iActivityManager, AlarmManager alarmManager, UserManager userManager, RecordingController recordingController, - MediaDataManager mediaDataManager, @Nullable TelecomManager telecomManager, @DisplayId int displayId, @Main SharedPreferences sharedPreferences, DateFormatUtil dateFormatUtil, RingerModeTracker ringerModeTracker) { @@ -190,7 +185,6 @@ public class PhoneStatusBarPolicy mUiBgExecutor = uiBgExecutor; mTelecomManager = telecomManager; mRingerModeTracker = ringerModeTracker; - mMediaDataManager = mediaDataManager; mSlotCast = resources.getString(com.android.internal.R.string.status_bar_cast); mSlotHotspot = resources.getString(com.android.internal.R.string.status_bar_hotspot); @@ -208,7 +202,6 @@ public class PhoneStatusBarPolicy mSlotSensorsOff = resources.getString(com.android.internal.R.string.status_bar_sensors_off); mSlotScreenRecord = resources.getString( com.android.internal.R.string.status_bar_screen_record); - mSlotMedia = resources.getString(com.android.internal.R.string.status_bar_media); mDisplayId = displayId; mSharedPreferences = sharedPreferences; @@ -287,11 +280,6 @@ public class PhoneStatusBarPolicy mIconController.setIconVisibility(mSlotSensorsOff, mSensorPrivacyController.isSensorPrivacyEnabled()); - // play/pause icon when media is active - mIconController.setIcon(mSlotMedia, R.drawable.stat_sys_media, - mResources.getString(R.string.accessibility_media_active)); - mIconController.setIconVisibility(mSlotMedia, mMediaDataManager.hasActiveMedia()); - // screen record mIconController.setIcon(mSlotScreenRecord, R.drawable.stat_sys_screen_record, null); mIconController.setIconVisibility(mSlotScreenRecord, false); @@ -308,7 +296,6 @@ public class PhoneStatusBarPolicy mSensorPrivacyController.addCallback(mSensorPrivacyListener); mLocationController.addCallback(this); mRecordingController.addCallback(this); - mMediaDataManager.addListener(this); mCommandQueue.addCallback(this); } @@ -713,18 +700,4 @@ public class PhoneStatusBarPolicy if (DEBUG) Log.d(TAG, "screenrecord: hiding icon"); mHandler.post(() -> mIconController.setIconVisibility(mSlotScreenRecord, false)); } - - @Override - public void onMediaDataLoaded(String key, MediaData data) { - updateMediaIcon(); - } - - @Override - public void onMediaDataRemoved(String key) { - updateMediaIcon(); - } - - private void updateMediaIcon() { - mIconController.setIconVisibility(mSlotMedia, mMediaDataManager.hasActiveMedia()); - } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java index 19de191d9753..e0e52001e740 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -143,7 +143,6 @@ import com.android.systemui.bubbles.BubbleController; import com.android.systemui.charging.WirelessChargingAnimation; import com.android.systemui.classifier.FalsingLog; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.fragments.ExtensionFragmentListener; import com.android.systemui.fragments.FragmentHostManager; @@ -511,7 +510,6 @@ public class StatusBar extends SystemUI implements DemoMode, private final ScrimController mScrimController; protected DozeScrimController mDozeScrimController; private final Executor mUiBgExecutor; - private final Executor mMainExecutor; protected boolean mDozing; @@ -670,7 +668,6 @@ public class StatusBar extends SystemUI implements DemoMode, DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, - @Main Executor mainExecutor, NotificationMediaManager notificationMediaManager, NotificationLockscreenUserManager lockScreenUserManager, NotificationRemoteInputManager remoteInputManager, @@ -751,7 +748,6 @@ public class StatusBar extends SystemUI implements DemoMode, mDisplayMetrics = displayMetrics; mMetricsLogger = metricsLogger; mUiBgExecutor = uiBgExecutor; - mMainExecutor = mainExecutor; mMediaManager = notificationMediaManager; mLockscreenUserManager = lockScreenUserManager; mRemoteInputManager = remoteInputManager; @@ -1279,8 +1275,7 @@ public class StatusBar extends SystemUI implements DemoMode, mActivityLaunchAnimator = new ActivityLaunchAnimator( mNotificationShadeWindowViewController, this, mNotificationPanelViewController, mNotificationShadeDepthControllerLazy.get(), - (NotificationListContainer) mStackScroller, - mMainExecutor); + (NotificationListContainer) mStackScroller); // TODO: inject this. mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java index 64e5f0a8184e..7bcfb466d7d9 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java @@ -350,7 +350,6 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit } Intent fillInIntent = null; NotificationEntry entry = row.getEntry(); - final boolean isBubble = entry.isBubble(); CharSequence remoteInputText = null; if (!TextUtils.isEmpty(entry.remoteInputText)) { remoteInputText = entry.remoteInputText; @@ -359,14 +358,15 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit fillInIntent = new Intent().putExtra(Notification.EXTRA_REMOTE_INPUT_DRAFT, remoteInputText.toString()); } - if (isBubble) { + final boolean canBubble = entry.canBubble(); + if (canBubble) { mLogger.logExpandingBubble(notificationKey); - expandBubbleStackOnMainThread(notificationKey); + expandBubbleStackOnMainThread(entry); } else { startNotificationIntent( intent, fillInIntent, entry, row, wasOccluded, isActivityIntent); } - if (isActivityIntent || isBubble) { + if (isActivityIntent || canBubble) { mAssistManagerLazy.get().hideAssist(); } if (shouldCollapse()) { @@ -381,7 +381,7 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit rank, count, true, location); mClickNotifier.onNotificationClick(notificationKey, nv); - if (!isBubble) { + if (!canBubble) { if (parentToCancelFinal != null) { // TODO: (b/145659174) remove - this cancels the parent if the notification clicked // on will auto-cancel and is the only child in the group. This won't be @@ -398,12 +398,12 @@ public class StatusBarNotificationActivityStarter implements NotificationActivit mIsCollapsingToShowActivityOverLockscreen = false; } - private void expandBubbleStackOnMainThread(String notificationKey) { + private void expandBubbleStackOnMainThread(NotificationEntry entry) { if (Looper.getMainLooper().isCurrentThread()) { - mBubbleController.expandStackAndSelectBubble(notificationKey); + mBubbleController.expandStackAndSelectBubble(entry); } else { mMainThreadHandler.post( - () -> mBubbleController.expandStackAndSelectBubble(notificationKey)); + () -> mBubbleController.expandStackAndSelectBubble(entry)); } } diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java index 669e6a4f2138..72395e68ff07 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallback.java @@ -30,7 +30,6 @@ import android.content.IntentSender; import android.os.Handler; import android.os.RemoteException; import android.os.UserHandle; -import android.util.Log; import android.view.View; import android.view.ViewParent; @@ -49,8 +48,6 @@ import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout; import com.android.systemui.statusbar.policy.KeyguardStateController; -import java.util.concurrent.atomic.AtomicReference; - import javax.inject.Inject; import javax.inject.Singleton; @@ -58,8 +55,7 @@ import javax.inject.Singleton; */ @Singleton public class StatusBarRemoteInputCallback implements Callback, Callbacks, - StatusBarStateController.StateListener, KeyguardStateController.Callback { - private static final String TAG = StatusBarRemoteInputCallback.class.getSimpleName(); + StatusBarStateController.StateListener { private final KeyguardStateController mKeyguardStateController; private final SysuiStatusBarStateController mStatusBarStateController; @@ -78,7 +74,6 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, private int mDisabled2; protected BroadcastReceiver mChallengeReceiver = new ChallengeReceiver(); private Handler mMainHandler = new Handler(); - private final AtomicReference<Intent> mPendingConfirmCredentialIntent = new AtomicReference(); /** */ @@ -107,9 +102,6 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, mActionClickLogger = clickLogger; mActivityIntentHelper = new ActivityIntentHelper(mContext); mGroupManager = groupManager; - // Listen to onKeyguardShowingChanged in case a managed profile needs to be unlocked - // once the primary profile's keyguard is no longer shown. - mKeyguardStateController.addCallback(this); } @Override @@ -213,39 +205,12 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, // Clear pending remote view, as we do not want to trigger pending remote input view when // it's called by other code mPendingWorkRemoteInputView = null; - - final Intent newIntent = createConfirmDeviceCredentialIntent( - userId, intendSender, notificationKey); - if (newIntent == null) { - Log.w(TAG, String.format("Cannot create intent to unlock user %d", userId)); - return false; - } - - mPendingConfirmCredentialIntent.set(newIntent); - - // If the Keyguard is currently showing, starting the ConfirmDeviceCredentialActivity - // would cause it to pause, not letting the user actually unlock the managed profile. - // Instead, wait until we receive a callback indicating it is no longer showing and - // then start the pending intent. - if (mKeyguardStateController.isShowing()) { - // Do nothing, since the callback will get the pending intent and start it. - Log.w(TAG, String.format("Keyguard is showing, waiting until it's not")); - } else { - startPendingConfirmDeviceCredentialIntent(); - } - - return true; - } - - private Intent createConfirmDeviceCredentialIntent( - int userId, IntentSender intendSender, String notificationKey) { + // Begin old BaseStatusBar.startWorkChallengeIfNecessary. final Intent newIntent = mKeyguardManager.createConfirmDeviceCredentialIntent(null, null, userId); - if (newIntent == null) { - return null; + return false; } - final Intent callBackIntent = new Intent(NOTIFICATION_UNLOCKED_BY_WORK_CHALLENGE_ACTION); callBackIntent.putExtra(Intent.EXTRA_INTENT, intendSender); callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey); @@ -261,40 +226,14 @@ public class StatusBarRemoteInputCallback implements Callback, Callbacks, newIntent.putExtra( Intent.EXTRA_INTENT, callBackPendingIntent.getIntentSender()); - - return newIntent; - } - - private void startPendingConfirmDeviceCredentialIntent() { - final Intent pendingIntent = mPendingConfirmCredentialIntent.getAndSet(null); - if (pendingIntent == null) { - return; - } - try { - if (mKeyguardStateController.isShowing()) { - Log.w(TAG, "Keyguard is showing while starting confirm device credential intent."); - } - ActivityManager.getService().startConfirmDeviceCredentialIntent(pendingIntent, + ActivityManager.getService().startConfirmDeviceCredentialIntent(newIntent, null /*options*/); } catch (RemoteException ex) { // ignore } - } - - @Override - public void onKeyguardShowingChanged() { - if (mKeyguardStateController.isShowing()) { - // In order to avoid jarring UX where/ the managed profile challenge is shown and - // immediately dismissed, do not attempt to start the confirm device credential - // activity if the keyguard is still showing. - if (mPendingConfirmCredentialIntent.get() != null) { - Log.w(TAG, "There's a pending unlock intent but keyguard is still showing, abort."); - } - return; - } - - startPendingConfirmDeviceCredentialIntent(); + return true; + // End old BaseStatusBar.startWorkChallengeIfNecessary. } @Override diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java index 62a3cf040d7e..02e031217904 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.java @@ -33,7 +33,6 @@ import com.android.systemui.assist.AssistManager; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.bubbles.BubbleController; import com.android.systemui.colorextraction.SysuiColorExtractor; -import com.android.systemui.dagger.qualifiers.Main; import com.android.systemui.dagger.qualifiers.UiBackground; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.keyguard.KeyguardViewMediator; @@ -146,7 +145,6 @@ public interface StatusBarPhoneModule { DisplayMetrics displayMetrics, MetricsLogger metricsLogger, @UiBackground Executor uiBgExecutor, - @Main Executor mainExecutor, NotificationMediaManager notificationMediaManager, NotificationLockscreenUserManager lockScreenUserManager, NotificationRemoteInputManager remoteInputManager, @@ -226,7 +224,6 @@ public interface StatusBarPhoneModule { displayMetrics, metricsLogger, uiBgExecutor, - mainExecutor, notificationMediaManager, lockScreenUserManager, remoteInputManager, diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java index e65b6fe7c3f0..b4de3cd5d43b 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/MobileSignalController.java @@ -652,6 +652,8 @@ public class MobileSignalController extends SignalController< } mDataState = state; if (networkType != mTelephonyDisplayInfo.getNetworkType()) { + Log.d(mTag, "onDataConnectionStateChanged:" + + " network type change and reset displayInfo. type=" + networkType); mTelephonyDisplayInfo = new TelephonyDisplayInfo(networkType, TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE); } 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 412962cc797a..db00770f0638 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java @@ -409,18 +409,6 @@ public class UserSwitcherController implements Dumpable { Log.e(TAG, "Couldn't switch to user, id=" + userId); } - public int getSwitchableUserCount() { - int count = 0; - final int N = mUsers.size(); - for (int i = 0; i < N; ++i) { - UserRecord record = mUsers.get(i); - if (record.info != null && record.info.supportsSwitchToByUser()) { - count++; - } - } - return count; - } - protected void switchToUserId(int id) { try { pauseRefreshUsers(); diff --git a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java index 7729965b56c4..7c9ea6bd8e80 100644 --- a/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java +++ b/packages/SystemUI/src/com/android/systemui/util/concurrency/ConcurrencyModule.java @@ -92,6 +92,15 @@ public abstract class ConcurrencyModule { } /** + * @deprecated Please specify @Main or @Background when injecting a Handler or use an Executor. + */ + @Deprecated + @Provides + public static Handler provideHandler() { + return new Handler(); + } + + /** * Provide a Background-Thread Executor by default. */ @Provides 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 96e868d2a618..c89f6c2597d0 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java @@ -50,6 +50,7 @@ import android.hardware.face.FaceManager; import android.os.Handler; import android.os.PowerManager; import android.service.dreams.IDreamManager; +import android.service.notification.NotificationListenerService; import android.service.notification.ZenModeConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -68,6 +69,7 @@ import com.android.systemui.shared.system.QuickStepContract; 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; @@ -317,7 +319,7 @@ public class BubbleControllerTest extends SysuiTestCase { verify(mNotificationEntryManager).updateNotifications(any()); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey())); verify(mNotificationEntryManager, times(2)).updateNotifications(anyString()); @@ -329,7 +331,7 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.updateBubble(mRow2.getEntry()); mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); Bubble b = mBubbleData.getOverflowBubbleWithKey(mRow.getEntry().getKey()); assertThat(mBubbleData.getOverflowBubbles()).isEqualTo(ImmutableList.of(b)); @@ -350,9 +352,10 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleController.updateBubble(mRow.getEntry(), /* suppressFlyout */ false, /* showInShade */ true); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL); + mBubbleController.removeBubble( + mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL); verify(mNotificationEntryManager, times(1)).performRemoveNotification( eq(mRow.getEntry().getSbn()), anyInt()); assertThat(mBubbleData.getOverflowBubbles()).isEmpty(); @@ -365,7 +368,7 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_CHANGED); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_CHANGED); verify(mNotificationEntryManager, never()).performRemoveNotification( eq(mRow.getEntry().getSbn()), anyInt()); assertFalse(mBubbleController.hasBubbles()); @@ -563,7 +566,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Dismiss currently expanded mBubbleController.removeBubble( - mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(), + mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()) + .getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey()); @@ -574,7 +578,8 @@ public class BubbleControllerTest extends SysuiTestCase { // Dismiss that one mBubbleController.removeBubble( - mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(), + mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()) + .getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); // Make sure state changes and collapse happens @@ -674,7 +679,7 @@ public class BubbleControllerTest extends SysuiTestCase { mRemoveInterceptor.onNotificationRemoveRequested( mRow.getEntry().getKey(), mRow.getEntry(), REASON_APP_CANCEL); - mBubbleController.expandStackAndSelectBubble(key); + mBubbleController.expandStackAndSelectBubble(mRow.getEntry()); assertTrue(mSysUiStateBubblesExpanded); } @@ -700,7 +705,7 @@ public class BubbleControllerTest extends SysuiTestCase { @Test public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED); + mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED); verify(mDeleteIntent, never()).send(); } @@ -708,7 +713,7 @@ public class BubbleControllerTest extends SysuiTestCase { public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(1)).send(); } @@ -727,6 +732,9 @@ public class BubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE; + NotificationListenerService.Ranking ranking = new RankingBuilder( + mRow.getEntry().getRanking()).setCanBubble(false).build(); + mRow.getEntry().setRanking(ranking); mEntryListener.onPreEntryUpdated(mRow.getEntry()); assertFalse(mBubbleController.hasBubbles()); @@ -808,7 +816,7 @@ public class BubbleControllerTest extends SysuiTestCase { // Dismiss the bubble into overflow. mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertFalse(mBubbleController.hasBubbles()); boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( @@ -829,7 +837,7 @@ public class BubbleControllerTest extends SysuiTestCase { mRow.getEntry())); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_NO_LONGER_BUBBLE); + mRow.getEntry().getKey(), BubbleController.DISMISS_NO_LONGER_BUBBLE); assertFalse(mBubbleController.hasBubbles()); boolean intercepted = mRemoveInterceptor.onNotificationRemoveRequested( @@ -851,12 +859,12 @@ public class BubbleControllerTest extends SysuiTestCase { mBubbleData.setMaxOverflowBubbles(1); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertEquals(mBubbleData.getBubbles().size(), 2); assertEquals(mBubbleData.getOverflowBubbles().size(), 1); mBubbleController.removeBubble( - mRow2.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow2.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); // Overflow max of 1 is reached; mRow is oldest, so it gets removed verify(mNotificationEntryManager, times(1)).performRemoveNotification( mRow.getEntry().getSbn(), REASON_CANCEL); 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 66f119a082a6..8224c88e6c75 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleDataTest.java @@ -20,11 +20,8 @@ import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanki import static com.google.common.truth.Truth.assertThat; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.reset; -import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyZeroInteractions; import static org.mockito.Mockito.when; @@ -180,7 +177,8 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE); // Verify verifyUpdateReceived(); @@ -258,14 +256,15 @@ public class BubbleDataTest extends SysuiTestCase { assertThat(update.updatedBubble.showFlyout()).isFalse(); } - // COLLAPSED / ADD + // + // Overflow + // /** - * Verifies that the number of bubbles is not allowed to exceed the maximum. The limit is - * enforced by expiring the bubble which was least recently updated (lowest timestamp). + * Verifies that when the bubble stack reaches its maximum, the oldest bubble is overflowed. */ @Test - public void test_collapsed_addBubble_atMaxBubbles_overflowsOldest() { + public void testOverflow_add_stackAtMaxBubbles_overflowsOldest() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 2000); @@ -288,8 +287,12 @@ public class BubbleDataTest extends SysuiTestCase { assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); } + /** + * Verifies that once the number of overflowed bubbles reaches its maximum, the oldest + * overflow bubble is removed. + */ @Test - public void testOverflowBubble_maxReached_bubbleRemoved() { + public void testOverflow_maxReached_bubbleRemoved() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 2000); @@ -297,80 +300,75 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); mBubbleData.setMaxOverflowBubbles(1); - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertOverflowChangedTo(ImmutableList.of(mBubbleA1)); // Overflow max of 1 is reached; A1 is oldest, so it gets removed - mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); } /** - * Verifies that new bubbles insert to the left when collapsed, carrying along grouped bubbles. - * <p> - * Placement within the list is based on lastUpdate (post time of the notification), descending - * order (with most recent first). - * - * @see #test_expanded_addBubble_sortAndGrouping_newGroup() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * Verifies that overflow bubbles are canceled on notif entry removal. */ @Test - public void test_collapsed_addBubble_sortAndGrouping() { + public void testOverflow_notifCanceled_removesOverflowBubble() { // Setup + sendUpdatedEntryAtTime(mEntryA1, 1000); + sendUpdatedEntryAtTime(mEntryA2, 2000); + sendUpdatedEntryAtTime(mEntryA3, 3000); + sendUpdatedEntryAtTime(mEntryB1, 4000); + sendUpdatedEntryAtTime(mEntryB2, 5000); + sendUpdatedEntryAtTime(mEntryB3, 6000); // [A2, A3, B1, B2, B3], overflow: [A1] + sendUpdatedEntryAtTime(mEntryC1, 7000); // [A3, B1, B2, B3, C1], overflow: [A2, A1] mBubbleData.setListener(mListener); // Test - sendUpdatedEntryAtTime(mEntryA1, 1000); - verifyUpdateReceived(); - assertOrderNotChanged(); - - sendUpdatedEntryAtTime(mEntryB1, 2000); + mBubbleData.notificationEntryRemoved(mEntryA1.getKey(), + BubbleController.DISMISS_NOTIF_CANCEL); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB1, mBubbleA1); - - sendUpdatedEntryAtTime(mEntryB2, 3000); - verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1); + assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); - sendUpdatedEntryAtTime(mEntryA2, 4000); + // Test + mBubbleData.notificationEntryRemoved(mEntryA2.getKey(), + BubbleController.DISMISS_GROUP_CANCELLED); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB2, mBubbleB1); + assertOverflowChangedTo(ImmutableList.of()); } + // COLLAPSED / ADD + /** - * Verifies that new bubbles insert to the left when collapsed, carrying along grouped bubbles. - * Additionally, any bubble which is ongoing is considered "newer" than any non-ongoing bubble. + * Verifies that new bubbles insert to the left when collapsed. * <p> - * Because of the ongoing bubble, the new bubble cannot be placed in the first position. This - * causes the 'B' group to remain last, despite having a new button added. - * - * @see #test_expanded_addBubble_sortAndGrouping_newGroup() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * Placement within the list is based on {@link Bubble#getLastActivity()}, descending + * order (with most recent first). */ @Test - public void test_collapsed_addBubble_sortAndGrouping_withOngoing() { + public void test_collapsed_addBubble() { // Setup mBubbleData.setListener(mListener); // Test - setOngoing(mEntryA1, true); sendUpdatedEntryAtTime(mEntryA1, 1000); verifyUpdateReceived(); assertOrderNotChanged(); sendUpdatedEntryAtTime(mEntryB1, 2000); verifyUpdateReceived(); - assertOrderNotChanged(); + assertOrderChangedTo(mBubbleB1, mBubbleA1); sendUpdatedEntryAtTime(mEntryB2, 3000); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA1, mBubbleB2, mBubbleB1); + assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1); sendUpdatedEntryAtTime(mEntryA2, 4000); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleB2, mBubbleB1); + assertOrderChangedTo(mBubbleA2, mBubbleB2, mBubbleB1, mBubbleA1); } /** @@ -378,7 +376,6 @@ public class BubbleDataTest extends SysuiTestCase { * the collapsed state. * * @see #test_collapsed_updateBubble_selectionChanges() - * @see #test_collapsed_updateBubble_noSelectionChanges_withOngoing() */ @Test public void test_collapsed_addBubble_selectionChanges() { @@ -403,58 +400,28 @@ public class BubbleDataTest extends SysuiTestCase { assertSelectionChangedTo(mBubbleA2); } - /** - * Verifies that while collapsed, the selection will not change if the selected bubble is - * ongoing. It remains the top bubble and as such remains selected. - * - * @see #test_collapsed_addBubble_selectionChanges() - */ - @Test - public void test_collapsed_addBubble_noSelectionChanges_withOngoing() { - // Setup - setOngoing(mEntryA1, true); - sendUpdatedEntryAtTime(mEntryA1, 1000); - assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1); - mBubbleData.setListener(mListener); - - // Test - sendUpdatedEntryAtTime(mEntryB1, 2000); - verifyUpdateReceived(); - assertSelectionNotChanged(); - - sendUpdatedEntryAtTime(mEntryB2, 3000); - verifyUpdateReceived(); - assertSelectionNotChanged(); - - sendUpdatedEntryAtTime(mEntryA2, 4000); - verifyUpdateReceived(); - assertSelectionNotChanged(); - - assertThat(mBubbleData.getSelectedBubble()).isEqualTo(mBubbleA1); // selection unchanged - } - // COLLAPSED / REMOVE /** - * Verifies that groups may reorder when bubbles are removed, while the stack is in the - * collapsed state. + * Verifies order of bubbles after a removal. */ @Test - public void test_collapsed_removeBubble_sortAndGrouping() { + public void test_collapsed_removeBubble_sort() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, A1, B2, B1] + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); + // TODO: this should fail if things work as I expect them to? assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA1); } - /** * Verifies that onOrderChanged is not called when a bubble is removed if the removal does not * cause other bubbles to change position. @@ -465,62 +432,17 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, A1, B2, B1] + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryB1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertOrderNotChanged(); } /** - * Verifies that bubble ordering reverts to normal when an ongoing bubble is removed. A group - * which has a newer bubble may move to the front after the ongoing bubble is removed. - */ - @Test - public void test_collapsed_removeBubble_sortAndGrouping_withOngoing() { - // Setup - setOngoing(mEntryA1, true); - sendUpdatedEntryAtTime(mEntryA1, 1000); - sendUpdatedEntryAtTime(mEntryA2, 2000); - sendUpdatedEntryAtTime(mEntryB1, 3000); - sendUpdatedEntryAtTime(mEntryB2, 4000); // [A1*, A2, B2, B1] - mBubbleData.setListener(mListener); - - // Test - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL); - verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB2, mBubbleB1, mBubbleA2); - } - - /** - * Verifies that overflow bubbles are canceled on notif entry removal. - */ - @Test - public void test_removeOverflowBubble_forCanceledNotif() { - // Setup - sendUpdatedEntryAtTime(mEntryA1, 1000); - sendUpdatedEntryAtTime(mEntryA2, 2000); - sendUpdatedEntryAtTime(mEntryA3, 3000); - sendUpdatedEntryAtTime(mEntryB1, 4000); - sendUpdatedEntryAtTime(mEntryB2, 5000); - sendUpdatedEntryAtTime(mEntryB3, 6000); // [A2, A3, B1, B2, B3], overflow: [A1] - sendUpdatedEntryAtTime(mEntryC1, 7000); // [A3, B1, B2, B3, C1], overflow: [A2, A1] - mBubbleData.setListener(mListener); - - // Test - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_NOTIF_CANCEL); - verifyUpdateReceived(); - assertOverflowChangedTo(ImmutableList.of(mBubbleA2)); - - // Test - mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_GROUP_CANCELLED); - verifyUpdateReceived(); - assertOverflowChangedTo(ImmutableList.of()); - } - - /** * Verifies that when the selected bubble is removed with the stack in the collapsed state, * the selection moves to the next most-recently updated bubble. */ @@ -530,11 +452,12 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, A1, B2, B1] + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_NOTIF_CANCEL); + mBubbleData.notificationEntryRemoved( + mEntryA2.getKey(), BubbleController.DISMISS_NOTIF_CANCEL); verifyUpdateReceived(); assertSelectionChangedTo(mBubbleB2); } @@ -542,26 +465,26 @@ public class BubbleDataTest extends SysuiTestCase { // COLLAPSED / UPDATE /** - * Verifies that bubble and group ordering may change with updates while the stack is in the + * Verifies that bubble ordering changes with updates while the stack is in the * collapsed state. */ @Test - public void test_collapsed_updateBubble_orderAndGrouping() { + public void test_collapsed_updateBubble() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, A1, B2, B1] + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] mBubbleData.setListener(mListener); // Test sendUpdatedEntryAtTime(mEntryB1, 5000); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB1, mBubbleB2, mBubbleA2, mBubbleA1); + assertOrderChangedTo(mBubbleB1, mBubbleA2, mBubbleB2, mBubbleA1); sendUpdatedEntryAtTime(mEntryA1, 6000); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleB1, mBubbleB2); + assertOrderChangedTo(mBubbleA1, mBubbleB1, mBubbleA2, mBubbleB2); } /** @@ -573,7 +496,7 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, A1, B2, B1] + sendUpdatedEntryAtTime(mEntryA2, 4000); // [A2, B2, B1, A1] mBubbleData.setListener(mListener); // Test @@ -587,26 +510,6 @@ public class BubbleDataTest extends SysuiTestCase { } /** - * Verifies that selection does not change in response to updates when collapsed, if the - * selected bubble is ongoing. - */ - @Test - public void test_collapsed_updateBubble_noSelectionChanges_withOngoing() { - // Setup - setOngoing(mEntryA1, true); - sendUpdatedEntryAtTime(mEntryA1, 1000); - sendUpdatedEntryAtTime(mEntryB1, 2000); - sendUpdatedEntryAtTime(mEntryB2, 3000); - sendUpdatedEntryAtTime(mEntryA2, 4000); // [A1*, A2, B2, B1] - mBubbleData.setListener(mListener); - - // Test - sendUpdatedEntryAtTime(mEntryB2, 5000); // [A1*, A2, B2, B1] - verifyUpdateReceived(); - assertSelectionNotChanged(); - } - - /** * Verifies that a request to expand the stack has no effect if there are no bubbles. */ @Test @@ -618,6 +521,9 @@ public class BubbleDataTest extends SysuiTestCase { verifyZeroInteractions(mListener); } + /** + * Verifies that removing the last bubble clears the selected bubble and collapses the stack. + */ @Test public void test_collapsed_removeLastBubble_clearsSelectedBubble() { // Setup @@ -625,27 +531,27 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE); // Verify the selection was cleared. verifyUpdateReceived(); + assertThat(mBubbleData.isExpanded()).isFalse(); assertSelectionCleared(); } - // EXPANDED / ADD + // EXPANDED / ADD / UPDATE /** - * Verifies that bubbles added as part of a new group insert before existing groups while - * expanded. + * Verifies that bubbles are added at the front of the stack. * <p> - * Placement within the list is based on lastUpdate (post time of the notification), descending + * Placement within the list is based on {@link Bubble#getLastActivity()}, descending * order (with most recent first). * - * @see #test_collapsed_addBubble_sortAndGrouping() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * @see #test_collapsed_addBubble() */ @Test - public void test_expanded_addBubble_sortAndGrouping_newGroup() { + public void test_expanded_addBubble() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 2000); @@ -656,65 +562,15 @@ public class BubbleDataTest extends SysuiTestCase { // Test sendUpdatedEntryAtTime(mEntryC1, 4000); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB1, mBubbleC1, mBubbleA2, mBubbleA1); + assertOrderChangedTo(mBubbleC1, mBubbleB1, mBubbleA2, mBubbleA1); } /** - * Verifies that bubbles added as part of a new group insert before existing groups while - * expanded, but not before any groups with ongoing bubbles. - * - * @see #test_collapsed_addBubble_sortAndGrouping_withOngoing() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() - */ - @Test - public void test_expanded_addBubble_sortAndGrouping_newGroup_withOngoing() { - // Setup - setOngoing(mEntryA1, true); - sendUpdatedEntryAtTime(mEntryA1, 1000); - sendUpdatedEntryAtTime(mEntryA2, 2000); - sendUpdatedEntryAtTime(mEntryB1, 3000); // [A1*, A2, B1] - changeExpandedStateAtTime(true, 4000L); - mBubbleData.setListener(mListener); - - // Test - sendUpdatedEntryAtTime(mEntryC1, 4000); - verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleC1, mBubbleB1); - } - - /** - * Verifies that bubbles added as part of an existing group insert to the beginning of that - * group. The order of groups within the list must not change while in the expanded state. - * - * @see #test_collapsed_addBubble_sortAndGrouping() - * @see #test_expanded_addBubble_sortAndGrouping_newGroup() - */ - @Test - public void test_expanded_addBubble_sortAndGrouping_existingGroup() { - // Setup - sendUpdatedEntryAtTime(mEntryA1, 1000); - sendUpdatedEntryAtTime(mEntryA2, 2000); - sendUpdatedEntryAtTime(mEntryB1, 3000); // [B1, A2, A1] - changeExpandedStateAtTime(true, 4000L); - mBubbleData.setListener(mListener); - - // Test - sendUpdatedEntryAtTime(mEntryA3, 4000); - verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB1, mBubbleA3, mBubbleA2, mBubbleA1); - } - - // EXPANDED / UPDATE - - /** * Verifies that updates to bubbles while expanded do not result in any change to sorting - * or grouping of bubbles or sorting of groups. - * - * @see #test_collapsed_addBubble_sortAndGrouping() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * of bubbles. */ @Test - public void test_expanded_updateBubble_sortAndGrouping_noChanges() { + public void test_expanded_updateBubble_noChanges() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryA2, 2000); @@ -733,7 +589,6 @@ public class BubbleDataTest extends SysuiTestCase { * Verifies that updates to bubbles while expanded do not result in any change to selection. * * @see #test_collapsed_addBubble_selectionChanges() - * @see #test_collapsed_updateBubble_noSelectionChanges_withOngoing() */ @Test public void test_expanded_updateBubble_noSelectionChanges() { @@ -762,26 +617,25 @@ public class BubbleDataTest extends SysuiTestCase { // EXPANDED / REMOVE /** - * Verifies that removing a bubble while expanded does not result in reordering of groups - * or any of the remaining bubbles. + * Verifies that removing a bubble while expanded does not result in reordering of bubbles. * - * @see #test_collapsed_addBubble_sortAndGrouping() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * @see #test_collapsed_addBubble() */ @Test - public void test_expanded_removeBubble_sortAndGrouping() { + public void test_expanded_removeBubble() { // Setup sendUpdatedEntryAtTime(mEntryA1, 1000); sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryA2, 3000); - sendUpdatedEntryAtTime(mEntryB2, 4000); // [B2, B1, A2, A1] + sendUpdatedEntryAtTime(mEntryB2, 4000); // [B2, A2, B1, A1] changeExpandedStateAtTime(true, 5000L); mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryB2, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryB2.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleB1, mBubbleA2, mBubbleA1); + assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleA1); } /** @@ -789,8 +643,7 @@ public class BubbleDataTest extends SysuiTestCase { * selected. The replacement selection is the bubble which appears at the same index as the * previous one, or the previous index if this was the last position. * - * @see #test_collapsed_addBubble_sortAndGrouping() - * @see #test_expanded_addBubble_sortAndGrouping_existingGroup() + * @see #test_collapsed_addBubble() */ @Test public void test_expanded_removeBubble_selectionChanges_whenSelectedRemoved() { @@ -800,17 +653,19 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryA2, 3000); sendUpdatedEntryAtTime(mEntryB2, 4000); changeExpandedStateAtTime(true, 5000L); - mBubbleData.setSelectedBubble(mBubbleA2); // [B2, B1, ^A2, A1] + mBubbleData.setSelectedBubble(mBubbleA2); // [B2, A2^, B1, A1] mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA2, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA2.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); - assertSelectionChangedTo(mBubbleA1); + assertSelectionChangedTo(mBubbleB1); - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryB1.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); - assertSelectionChangedTo(mBubbleB1); + assertSelectionChangedTo(mBubbleA1); } @Test @@ -838,7 +693,6 @@ public class BubbleDataTest extends SysuiTestCase { * expanded. * <p> * When the stack transitions to the collapsed state, the selected bubble is brought to the top. - * Bubbles within the same group should move up with it. * <p> * When the stack transitions back to the expanded state, this new order is kept as is. */ @@ -849,13 +703,13 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryA2, 3000); sendUpdatedEntryAtTime(mEntryB2, 4000); - changeExpandedStateAtTime(true, 5000L); // [B2=4000, B1=2000, A2=3000, A1=1000] - sendUpdatedEntryAtTime(mEntryB1, 6000); // [B2=4000, B1=6000*, A2=3000, A1=1000] + changeExpandedStateAtTime(true, 5000L); // [B2=4000, A2=3000, B1=2000, A1=1000] + sendUpdatedEntryAtTime(mEntryB1, 6000); // [B2=4000, A2=3000, B1=6000, A1=1000] setCurrentTime(7000); mBubbleData.setSelectedBubble(mBubbleA2); mBubbleData.setListener(mListener); assertThat(mBubbleData.getBubbles()).isEqualTo( - ImmutableList.of(mBubbleB2, mBubbleB1, mBubbleA2, mBubbleA1)); + ImmutableList.of(mBubbleB2, mBubbleA2, mBubbleB1, mBubbleA1)); // Test @@ -863,18 +717,17 @@ public class BubbleDataTest extends SysuiTestCase { // stack is expanded. When next collapsed, sorting will be applied and saved, just prior // to moving the selected bubble to the top (first). // - // In this case, the expected re-expand state will be: [A2, A1, B1, B2] + // In this case, the expected re-expand state will be: [A2^, B1, B2, A1] // // collapse -> selected bubble (A2) moves first. changeExpandedStateAtTime(false, 8000L); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2); + assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleB2, mBubbleA1); } /** * When a change occurs while collapsed (any update, add, remove), the previous expanded - * order and grouping becomes invalidated, and the order and grouping when next expanded will - * remain the same as collapsed. + * order becomes invalidated, the stack is resorted and will reflect that when next expanded. */ @Test public void test_expansionChanges_withUpdatesWhileCollapsed() { @@ -883,10 +736,10 @@ public class BubbleDataTest extends SysuiTestCase { sendUpdatedEntryAtTime(mEntryB1, 2000); sendUpdatedEntryAtTime(mEntryA2, 3000); sendUpdatedEntryAtTime(mEntryB2, 4000); - changeExpandedStateAtTime(true, 5000L); // [B2=4000, B1=2000, A2=3000, A1=1000] - sendUpdatedEntryAtTime(mEntryB1, 6000); // [B2=4000, B1=*6000, A2=3000, A1=1000] + changeExpandedStateAtTime(true, 5000L); // [B2=4000, A2=3000, B1=2000, A1=1000] + sendUpdatedEntryAtTime(mEntryB1, 6000); // [B2=4000, A2=3000, B1=6000, A1=1000] setCurrentTime(7000); - mBubbleData.setSelectedBubble(mBubbleA2); // [B2, B1, ^A2, A1] + mBubbleData.setSelectedBubble(mBubbleA2); // [B2, A2^, B1, A1] mBubbleData.setListener(mListener); // Test @@ -895,7 +748,7 @@ public class BubbleDataTest extends SysuiTestCase { // stack is expanded. When next collapsed, sorting will be applied and saved, just prior // to moving the selected bubble to the top (first). // - // In this case, the expected re-expand state will be: [B1, B2, A2*, A1] + // In this case, the expected re-expand state will be: [A2^, B1, B2, A1] // // That state is restored as long as no changes occur (add/remove/update) while in // the collapsed state. @@ -903,11 +756,12 @@ public class BubbleDataTest extends SysuiTestCase { // collapse -> selected bubble (A2) moves first. changeExpandedStateAtTime(false, 8000L); verifyUpdateReceived(); - assertOrderChangedTo(mBubbleA2, mBubbleA1, mBubbleB1, mBubbleB2); + assertOrderChangedTo(mBubbleA2, mBubbleB1, mBubbleB2, mBubbleA1); // An update occurs, which causes sorting, and this invalidates the previously saved order. - sendUpdatedEntryAtTime(mEntryA2, 9000); + sendUpdatedEntryAtTime(mEntryA1, 9000); verifyUpdateReceived(); + assertOrderChangedTo(mBubbleA1, mBubbleA2, mBubbleB1, mBubbleB2); // No order changes when expanding because the new sorted order remains. changeExpandedStateAtTime(true, 10000L); @@ -923,7 +777,8 @@ public class BubbleDataTest extends SysuiTestCase { mBubbleData.setListener(mListener); // Test - mBubbleData.notificationEntryRemoved(mEntryA1, BubbleController.DISMISS_USER_GESTURE); + mBubbleData.notificationEntryRemoved( + mEntryA1.getKey(), BubbleController.DISMISS_USER_GESTURE); verifyUpdateReceived(); assertExpandedChangedTo(false); } 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 73b876019863..ead95ca1665e 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/NewNotifPipelineBubbleControllerTest.java @@ -46,6 +46,7 @@ import android.hardware.face.FaceManager; import android.os.Handler; import android.os.PowerManager; import android.service.dreams.IDreamManager; +import android.service.notification.NotificationListenerService; import android.service.notification.ZenModeConfig; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; @@ -62,6 +63,7 @@ import com.android.systemui.model.SysUiState; 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; @@ -285,7 +287,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); verify(mNotifCallback, times(1)).invalidateNotifications(anyString()); - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mBubbleController.removeBubble( + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey())); verify(mNotifCallback, times(2)).invalidateNotifications(anyString()); } @@ -302,7 +305,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true); // Now remove the bubble - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mBubbleController.removeBubble( + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertTrue(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())); // We don't remove the notification since the bubble is still in overflow. @@ -322,7 +326,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { mBubbleData.getBubbleInStackWithKey(mRow.getEntry().getKey()).setSuppressNotification(true); // Now remove the bubble - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL); + mBubbleController.removeBubble( + mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL); assertFalse(mBubbleData.hasOverflowBubbleWithKey(mRow.getEntry().getKey())); // Since the notif is dismissed and not in overflow, once the bubble is removed, @@ -502,7 +507,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Dismiss currently expanded mBubbleController.removeBubble( - mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(), + mBubbleData.getBubbleInStackWithKey( + stackView.getExpandedBubble().getKey()).getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow2.getEntry().getKey()); @@ -513,7 +519,8 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Dismiss that one mBubbleController.removeBubble( - mBubbleData.getBubbleInStackWithKey(stackView.getExpandedBubble().getKey()).getEntry(), + mBubbleData.getBubbleInStackWithKey( + stackView.getExpandedBubble().getKey()).getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); // Make sure state changes and collapse happens @@ -613,7 +620,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { @Test public void testDeleteIntent_removeBubble_aged() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); - mBubbleController.removeBubble(mRow.getEntry(), BubbleController.DISMISS_AGED); + mBubbleController.removeBubble(mRow.getEntry().getKey(), BubbleController.DISMISS_AGED); verify(mDeleteIntent, never()).send(); } @@ -621,7 +628,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { public void testDeleteIntent_removeBubble_user() throws PendingIntent.CanceledException { mBubbleController.updateBubble(mRow.getEntry()); mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); verify(mDeleteIntent, times(1)).send(); } @@ -640,6 +647,9 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { assertTrue(mBubbleController.hasBubbles()); mRow.getEntry().getSbn().getNotification().flags &= ~FLAG_BUBBLE; + NotificationListenerService.Ranking ranking = new RankingBuilder( + mRow.getEntry().getRanking()).setCanBubble(false).build(); + mRow.getEntry().setRanking(ranking); mEntryListener.onEntryUpdated(mRow.getEntry()); assertFalse(mBubbleController.hasBubbles()); @@ -686,7 +696,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Dismiss the bubble mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_USER_GESTURE); + mRow.getEntry().getKey(), BubbleController.DISMISS_USER_GESTURE); assertFalse(mBubbleController.hasBubbles()); // Dismiss the notification @@ -707,7 +717,7 @@ public class NewNotifPipelineBubbleControllerTest extends SysuiTestCase { // Dismiss the bubble mBubbleController.removeBubble( - mRow.getEntry(), BubbleController.DISMISS_NOTIF_CANCEL); + mRow.getEntry().getKey(), BubbleController.DISMISS_NOTIF_CANCEL); assertFalse(mBubbleController.hasBubbles()); // Dismiss the notification diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt index d49d0219fa54..f46819252fac 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubblePersistentRepositoryTest.kt @@ -29,9 +29,9 @@ import org.junit.runner.RunWith class BubblePersistentRepositoryTest : SysuiTestCase() { private val bubbles = listOf( - BubbleEntity(0, "com.example.messenger", "shortcut-1"), - BubbleEntity(10, "com.example.chat", "alice and bob"), - BubbleEntity(0, "com.example.messenger", "shortcut-2") + BubbleEntity(0, "com.example.messenger", "shortcut-1", "key-1"), + BubbleEntity(10, "com.example.chat", "alice and bob", "key-2"), + BubbleEntity(0, "com.example.messenger", "shortcut-2", "key-3") ) private lateinit var repository: BubblePersistentRepository diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt index 7acc93712d9b..2bb6bb8ebe14 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleVolatileRepositoryTest.kt @@ -16,37 +16,92 @@ package com.android.systemui.bubbles.storage +import android.content.pm.LauncherApps +import android.os.UserHandle import android.testing.AndroidTestingRunner import androidx.test.filters.SmallTest import com.android.systemui.SysuiTestCase +import com.android.systemui.util.mockito.eq import junit.framework.Assert.assertEquals import org.junit.Before import org.junit.Test import org.junit.runner.RunWith +import org.mockito.Mockito.mock +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions @SmallTest @RunWith(AndroidTestingRunner::class) class BubbleVolatileRepositoryTest : SysuiTestCase() { - private val bubble1 = BubbleEntity(0, "com.example.messenger", "shortcut-1") - private val bubble2 = BubbleEntity(10, "com.example.chat", "alice and bob") - private val bubble3 = BubbleEntity(0, "com.example.messenger", "shortcut-2") + private val user0 = UserHandle.of(0) + private val user10 = UserHandle.of(10) + + private val bubble1 = BubbleEntity(0, PKG_MESSENGER, "shortcut-1", "k1") + private val bubble2 = BubbleEntity(10, PKG_CHAT, "alice and bob", "k2") + private val bubble3 = BubbleEntity(0, PKG_MESSENGER, "shortcut-2", "k3") + private val bubbles = listOf(bubble1, bubble2, bubble3) private lateinit var repository: BubbleVolatileRepository + private lateinit var launcherApps: LauncherApps @Before fun setup() { - repository = BubbleVolatileRepository() + launcherApps = mock(LauncherApps::class.java) + repository = BubbleVolatileRepository(launcherApps) } @Test - fun testAddAndRemoveBubbles() { + fun testAddBubbles() { repository.addBubbles(bubbles) assertEquals(bubbles, repository.bubbles) + verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER), + eq(listOf("shortcut-1", "shortcut-2")), eq(user0), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) + verify(launcherApps).cacheShortcuts(eq(PKG_CHAT), + eq(listOf("alice and bob")), eq(user10), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) + repository.addBubbles(listOf(bubble1)) assertEquals(listOf(bubble2, bubble3, bubble1), repository.bubbles) + verifyNoMoreInteractions(launcherApps) + } + + @Test + fun testRemoveBubbles() { + repository.addBubbles(bubbles) + assertEquals(bubbles, repository.bubbles) + repository.removeBubbles(listOf(bubble3)) - assertEquals(listOf(bubble2, bubble1), repository.bubbles) + assertEquals(listOf(bubble1, bubble2), repository.bubbles) + verify(launcherApps).uncacheShortcuts(eq(PKG_MESSENGER), + eq(listOf("shortcut-2")), eq(user0), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) + } + + @Test + fun testAddAndRemoveBubblesWhenExceedingCapacity() { + repository.capacity = 2 + // push bubbles beyond capacity + repository.addBubbles(bubbles) + // verify it is trim down to capacity + assertEquals(listOf(bubble2, bubble3), repository.bubbles) + verify(launcherApps).cacheShortcuts(eq(PKG_MESSENGER), + eq(listOf("shortcut-2")), eq(user0), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) + verify(launcherApps).cacheShortcuts(eq(PKG_CHAT), + eq(listOf("alice and bob")), eq(user10), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) + + repository.addBubbles(listOf(bubble1)) + // verify the oldest bubble is popped + assertEquals(listOf(bubble3, bubble1), repository.bubbles) + verify(launcherApps).uncacheShortcuts(eq(PKG_CHAT), + eq(listOf("alice and bob")), eq(user10), + eq(LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS)) } -}
\ No newline at end of file +} + +private const val PKG_MESSENGER = "com.example.messenger" +private const val PKG_CHAT = "com.example.chat" diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt index ef4580c6b28d..79701ecf70f8 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/storage/BubbleXmlHelperTest.kt @@ -31,17 +31,17 @@ import java.io.ByteArrayOutputStream class BubbleXmlHelperTest : SysuiTestCase() { private val bubbles = listOf( - BubbleEntity(0, "com.example.messenger", "shortcut-1"), - BubbleEntity(10, "com.example.chat", "alice and bob"), - BubbleEntity(0, "com.example.messenger", "shortcut-2") + BubbleEntity(0, "com.example.messenger", "shortcut-1", "k1"), + BubbleEntity(10, "com.example.chat", "alice and bob", "k2"), + BubbleEntity(0, "com.example.messenger", "shortcut-2", "k3") ) @Test fun testWriteXml() { val expectedEntries = """ - <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" /> - <bb uid="10" pkg="com.example.chat" sid="alice and bob" /> - <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" /> + <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" /> + <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" /> + <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" /> """.trimIndent() ByteArrayOutputStream().use { writeXml(it, bubbles) @@ -56,9 +56,9 @@ class BubbleXmlHelperTest : SysuiTestCase() { val src = """ <?xml version='1.0' encoding='utf-8' standalone='yes' ?> <bs> - <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" /> - <bb uid="10" pkg="com.example.chat" sid="alice and bob" /> - <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" /> + <bb uid="0" pkg="com.example.messenger" sid="shortcut-1" key="k1" /> + <bb uid="10" pkg="com.example.chat" sid="alice and bob" key="k2" /> + <bb uid="0" pkg="com.example.messenger" sid="shortcut-2" key="k3" /> </bs> """.trimIndent() val actual = readXml(ByteArrayInputStream(src.toByteArray(Charsets.UTF_8))) diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt new file mode 100644 index 000000000000..7fe682793152 --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/dagger/ControlsComponentTest.kt @@ -0,0 +1,81 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.systemui.controls.dagger + +import android.testing.AndroidTestingRunner +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.controller.ControlsController +import com.android.systemui.controls.management.ControlsListingController +import com.android.systemui.controls.ui.ControlsUiController +import dagger.Lazy +import org.junit.Assert.assertEquals +import org.junit.Assert.assertFalse +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.junit.runner.RunWith +import org.mockito.Mock +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class ControlsComponentTest : SysuiTestCase() { + + @Mock + private lateinit var controller: ControlsController + @Mock + private lateinit var uiController: ControlsUiController + @Mock + private lateinit var listingController: ControlsListingController + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + } + + @Test + fun testFeatureEnabled() { + val component = ControlsComponent( + true, + Lazy { controller }, + Lazy { uiController }, + Lazy { listingController } + ) + + assertTrue(component.getControlsController().isPresent) + assertEquals(controller, component.getControlsController().get()) + assertTrue(component.getControlsUiController().isPresent) + assertEquals(uiController, component.getControlsUiController().get()) + assertTrue(component.getControlsListingController().isPresent) + assertEquals(listingController, component.getControlsListingController().get()) + } + + @Test + fun testFeatureDisabled() { + val component = ControlsComponent( + false, + Lazy { controller }, + Lazy { uiController }, + Lazy { listingController } + ) + + assertFalse(component.getControlsController().isPresent) + assertFalse(component.getControlsUiController().isPresent) + assertFalse(component.getControlsListingController().isPresent) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt index 663f011183ab..ee1cc7b1ab71 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsRequestReceiverTest.kt @@ -66,6 +66,7 @@ class ControlsRequestReceiverTest : SysuiTestCase() { MockitoAnnotations.initMocks(this) mContext.setMockPackageManager(packageManager) + `when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(true) mContext.addMockSystemService(ActivityManager::class.java, activityManager) receiver = ControlsRequestReceiver() @@ -145,6 +146,14 @@ class ControlsRequestReceiverTest : SysuiTestCase() { } ?: run { fail("Null start intent") } } + @Test + fun testFeatureDisabled_activityNotStarted() { + `when`(packageManager.hasSystemFeature(PackageManager.FEATURE_CONTROLS)).thenReturn(false) + receiver.onReceive(wrapper, intent) + + assertNull(wrapper.intent) + } + class MyWrapper(context: Context) : ContextWrapper(context) { var intent: Intent? = null diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java index 8db57cdf5f71..32546333aac3 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -59,12 +59,14 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.broadcast.BroadcastDispatcher; import com.android.systemui.colorextraction.SysuiColorExtractor; import com.android.systemui.controls.controller.ControlsController; +import com.android.systemui.controls.dagger.ControlsComponent; import com.android.systemui.controls.management.ControlsListingController; import com.android.systemui.controls.ui.ControlsUiController; import com.android.systemui.model.SysUiState; import com.android.systemui.plugins.ActivityStarter; import com.android.systemui.plugins.GlobalActions; import com.android.systemui.plugins.GlobalActionsPanelPlugin; +import com.android.systemui.settings.CurrentUserContextTracker; import com.android.systemui.statusbar.NotificationShadeDepthController; import com.android.systemui.statusbar.phone.NotificationShadeWindowController; import com.android.systemui.statusbar.policy.ConfigurationController; @@ -119,6 +121,8 @@ public class GlobalActionsDialogTest extends SysuiTestCase { @Mock GlobalActionsPanelPlugin mWalletPlugin; @Mock GlobalActionsPanelPlugin.PanelViewController mWalletController; @Mock private Handler mHandler; + @Mock private CurrentUserContextTracker mCurrentUserContextTracker; + private ControlsComponent mControlsComponent; private TestableLooper mTestableLooper; @@ -129,6 +133,14 @@ public class GlobalActionsDialogTest extends SysuiTestCase { allowTestableLooperAsMainThread(); when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); + when(mCurrentUserContextTracker.getCurrentUserContext()).thenReturn(mContext); + mControlsComponent = new ControlsComponent( + true, + () -> mControlsController, + () -> mControlsUiController, + () -> mControlsListingController + ); + mGlobalActionsDialog = new GlobalActionsDialog(mContext, mWindowManagerFuncs, mAudioManager, @@ -153,15 +165,14 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mColorExtractor, mStatusBarService, mNotificationShadeWindowController, - mControlsUiController, mWindowManager, mBackgroundExecutor, - mControlsListingController, - mControlsController, mUiEventLogger, mRingerModeTracker, mSysUiState, - mHandler + mHandler, + mControlsComponent, + mCurrentUserContextTracker ); mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java index eb43b8172c16..f38c722ad2db 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsImeTest.java @@ -18,10 +18,13 @@ package com.android.systemui.globalactions; import static android.view.WindowInsets.Type.ime; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import android.app.Activity; import android.os.Bundle; +import android.os.PowerManager; import android.os.SystemClock; import android.view.View; import android.view.WindowInsets; @@ -54,16 +57,15 @@ public class GlobalActionsImeTest extends SysuiTestCase { * doesn't interfere with the IME, i.e. soft-keyboard state. */ @Test - public void testGlobalActions_doesntStealImeControl() { + public void testGlobalActions_doesntStealImeControl() throws Exception { + turnScreenOn(); final TestActivity activity = mActivityTestRule.launchActivity(null); - activity.waitFor(() -> activity.mHasFocus && activity.mControlsIme && activity.mImeVisible); + waitUntil("Ime is visible", activity::isImeVisible); - InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand( - "input keyevent --longpress POWER" - ); + executeShellCommand("input keyevent --longpress POWER"); - activity.waitFor(() -> !activity.mHasFocus); + waitUntil("activity loses focus", () -> !activity.mHasFocus); // Give the dialog time to animate in, and steal IME focus. Unfortunately, there's currently // no better way to wait for this. SystemClock.sleep(TimeUnit.SECONDS.toMillis(2)); @@ -76,7 +78,39 @@ public class GlobalActionsImeTest extends SysuiTestCase { }); } - /** Like Instrumentation.runOnMainThread(), but forwards AssertionErrors to the caller. */ + private void turnScreenOn() throws Exception { + PowerManager powerManager = mContext.getSystemService(PowerManager.class); + assertNotNull(powerManager); + if (powerManager.isInteractive()) { + return; + } + executeShellCommand("input keyevent KEYCODE_WAKEUP"); + waitUntil("Device not interactive", powerManager::isInteractive); + executeShellCommand("am wait-for-broadcast-idle"); + } + + private static void waitUntil(String message, BooleanSupplier predicate) + throws Exception { + int sleep = 125; + final long timeout = SystemClock.uptimeMillis() + 10_000; // 10 second timeout + while (SystemClock.uptimeMillis() < timeout) { + if (predicate.getAsBoolean()) { + return; // okay + } + Thread.sleep(sleep); + sleep *= 5; + sleep = Math.min(2000, sleep); + } + fail(message); + } + + private static void executeShellCommand(String cmd) { + InstrumentationRegistry.getInstrumentation().getUiAutomation().executeShellCommand(cmd); + } + + /** + * Like Instrumentation.runOnMainThread(), but forwards AssertionErrors to the caller. + */ private static void runAssertionOnMainThread(Runnable r) { AssertionError[] t = new AssertionError[1]; InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> { @@ -96,7 +130,6 @@ public class GlobalActionsImeTest extends SysuiTestCase { WindowInsetsController.OnControllableInsetsChangedListener, View.OnApplyWindowInsetsListener { - private EditText mContent; boolean mHasFocus; boolean mControlsIme; boolean mImeVisible; @@ -105,13 +138,13 @@ public class GlobalActionsImeTest extends SysuiTestCase { protected void onCreate(@Nullable Bundle savedInstanceState) { super.onCreate(savedInstanceState); - mContent = new EditText(this); - mContent.setCursorVisible(false); // Otherwise, main thread doesn't go idle. - setContentView(mContent); - mContent.requestFocus(); + EditText content = new EditText(this); + content.setCursorVisible(false); // Otherwise, main thread doesn't go idle. + setContentView(content); + content.requestFocus(); getWindow().getDecorView().setOnApplyWindowInsetsListener(this); - WindowInsetsController wic = mContent.getWindowInsetsController(); + WindowInsetsController wic = content.getWindowInsetsController(); wic.addOnControllableInsetsChangedListener(this); wic.show(ime()); } @@ -133,16 +166,8 @@ public class GlobalActionsImeTest extends SysuiTestCase { } } - void waitFor(BooleanSupplier condition) { - synchronized (this) { - while (!condition.getAsBoolean()) { - try { - wait(TimeUnit.SECONDS.toMillis(5)); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - } + boolean isImeVisible() { + return mHasFocus && mControlsIme && mImeVisible; } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt index 7b80a6ea94a0..c0aef8adc4af 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaDeviceManagerTest.kt @@ -17,6 +17,7 @@ package com.android.systemui.media import android.app.Notification +import android.graphics.drawable.Drawable import android.media.MediaMetadata import android.media.MediaRouter2Manager import android.media.RoutingSessionInfo @@ -73,6 +74,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { private lateinit var fakeExecutor: FakeExecutor @Mock private lateinit var listener: MediaDeviceManager.Listener @Mock private lateinit var device: MediaDevice + @Mock private lateinit var icon: Drawable @Mock private lateinit var route: RoutingSessionInfo private lateinit var session: MediaSession private lateinit var metadataBuilder: MediaMetadata.Builder @@ -89,6 +91,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { // Configure mocks. whenever(device.name).thenReturn(DEVICE_NAME) + whenever(device.iconWithoutBackground).thenReturn(icon) whenever(lmmFactory.create(PACKAGE)).thenReturn(lmm) whenever(lmm.getCurrentConnectedDevice()).thenReturn(device) whenever(mr2.getRoutingSessionForMediaController(any())).thenReturn(route) @@ -157,6 +160,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) + assertThat(data.icon).isEqualTo(icon) } @Test @@ -170,6 +174,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) + assertThat(data.icon).isEqualTo(icon) } @Test @@ -183,6 +188,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isTrue() assertThat(data.name).isEqualTo(DEVICE_NAME) + assertThat(data.icon).isEqualTo(icon) } @Test @@ -204,6 +210,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() assertThat(data.name).isNull() + assertThat(data.icon).isNull() } @Test @@ -221,6 +228,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() assertThat(data.name).isNull() + assertThat(data.icon).isNull() } @Test @@ -238,6 +246,7 @@ public class MediaDeviceManagerTest : SysuiTestCase() { val data = captureDeviceData(KEY) assertThat(data.enabled).isFalse() assertThat(data.name).isNull() + assertThat(data.icon).isNull() } fun captureCallback(): LocalMediaManager.DeviceCallback { diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java index 425bf88ebec0..f404f0489e01 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/PipBoundsHandlerTest.java @@ -19,6 +19,7 @@ package com.android.systemui.pip; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; import android.content.ComponentName; import android.graphics.Rect; @@ -32,6 +33,7 @@ import android.view.Gravity; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; +import com.android.systemui.wm.DisplayController; import org.junit.Before; import org.junit.Test; @@ -63,7 +65,8 @@ public class PipBoundsHandlerTest extends SysuiTestCase { @Before public void setUp() throws Exception { initializeMockResources(); - mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext)); + mPipBoundsHandler = new PipBoundsHandler(mContext, new PipSnapAlgorithm(mContext), + mock(DisplayController.class)); mTestComponentName1 = new ComponentName(mContext, "component1"); mTestComponentName2 = new ComponentName(mContext, "component2"); diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java index 2c4304d51720..d3b33992d017 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ScreenshotNotificationSmartActionsTest.java @@ -22,7 +22,6 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doThrow; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -37,6 +36,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.os.Looper; +import android.os.UserHandle; import android.testing.AndroidTestingRunner; import androidx.test.filters.SmallTest; @@ -79,13 +79,12 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); ScreenshotNotificationSmartActionsProvider smartActionsProvider = mock( ScreenshotNotificationSmartActionsProvider.class); - when(smartActionsProvider.getActions(any(), any(), any(), any(), - eq(false))).thenThrow( - RuntimeException.class); + when(smartActionsProvider.getActions(any(), any(), any(), any(), any())) + .thenThrow(RuntimeException.class); CompletableFuture<List<Notification.Action>> smartActionsFuture = ScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://authority/data"), bitmap, smartActionsProvider, - true, false); + true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); assertEquals(Collections.emptyList(), smartActions); @@ -125,9 +124,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { CompletableFuture<List<Notification.Action>> smartActionsFuture = ScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, - true, true); - verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), - eq(false)); + true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); + verify(mSmartActionsProvider, never()).getActions(any(), any(), any(), any(), any()); assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); assertEquals(Collections.emptyList(), smartActions); @@ -140,9 +138,8 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { when(bitmap.getConfig()).thenReturn(Bitmap.Config.HARDWARE); ScreenshotSmartActions.getSmartActionsFuture( "", Uri.parse("content://autority/data"), bitmap, mSmartActionsProvider, true, - true); - verify(mSmartActionsProvider, times(1)) - .getActions(any(), any(), any(), any(), eq(true)); + UserHandle.getUserHandleForUid(UserHandle.myUserId())); + verify(mSmartActionsProvider, times(1)).getActions(any(), any(), any(), any(), any()); } // Tests for a hardware bitmap, a completed future is returned. @@ -157,7 +154,7 @@ public class ScreenshotNotificationSmartActionsTest extends SysuiTestCase { CompletableFuture<List<Notification.Action>> smartActionsFuture = ScreenshotSmartActions.getSmartActionsFuture("", null, bitmap, actionsProvider, - true, true); + true, UserHandle.getUserHandleForUid(UserHandle.myUserId())); assertNotNull(smartActionsFuture); List<Notification.Action> smartActions = smartActionsFuture.get(5, TimeUnit.MILLISECONDS); assertEquals(smartActions.size(), 0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java index 1654a5442635..cdef49d6c94d 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/ActivityLaunchAnimatorTest.java @@ -19,18 +19,14 @@ package com.android.systemui.statusbar.notification; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.doAnswer; -import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; -import android.os.RemoteException; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; -import android.view.IRemoteAnimationFinishedCallback; import android.view.RemoteAnimationAdapter; -import android.view.RemoteAnimationTarget; import android.view.View; import com.android.systemui.SysuiTestCase; @@ -40,8 +36,6 @@ import com.android.systemui.statusbar.notification.stack.NotificationListContain import com.android.systemui.statusbar.phone.NotificationPanelViewController; import com.android.systemui.statusbar.phone.NotificationShadeWindowView; import com.android.systemui.statusbar.phone.NotificationShadeWindowViewController; -import com.android.systemui.util.concurrency.FakeExecutor; -import com.android.systemui.util.time.FakeSystemClock; import org.junit.Assert; import org.junit.Before; @@ -74,11 +68,9 @@ public class ActivityLaunchAnimatorTest extends SysuiTestCase { private NotificationPanelViewController mNotificationPanelViewController; @Rule public MockitoRule rule = MockitoJUnit.rule(); - private FakeExecutor mExecutor; @Before public void setUp() throws Exception { - mExecutor = new FakeExecutor(new FakeSystemClock()); when(mNotificationShadeWindowViewController.getView()) .thenReturn(mNotificationShadeWindowView); when(mNotificationShadeWindowView.getResources()).thenReturn(mContext.getResources()); @@ -88,8 +80,8 @@ public class ActivityLaunchAnimatorTest extends SysuiTestCase { mCallback, mNotificationPanelViewController, mNotificationShadeDepthController, - mNotificationContainer, - mExecutor); + mNotificationContainer); + } @Test @@ -121,29 +113,6 @@ public class ActivityLaunchAnimatorTest extends SysuiTestCase { verify(mCallback).onExpandAnimationTimedOut(); } - @Test - public void testRowLinkBrokenOnAnimationStartFail() throws RemoteException { - ActivityLaunchAnimator.AnimationRunner runner = mLaunchAnimator.new AnimationRunner(mRow, - mExecutor); - // WHEN onAnimationStart with no valid remote target - runner.onAnimationStart(new RemoteAnimationTarget[0], new RemoteAnimationTarget[0], - mock(IRemoteAnimationFinishedCallback.class)); - mExecutor.runAllReady(); - // THEN the row is nulled out so that it won't be retained - Assert.assertTrue("The row should be null", runner.getRow() == null); - } - - @Test - public void testRowLinkBrokenOnAnimationCancelled() throws RemoteException { - ActivityLaunchAnimator.AnimationRunner runner = mLaunchAnimator.new AnimationRunner(mRow, - mExecutor); - // WHEN onAnimationCancelled - runner.onAnimationCancelled(); - mExecutor.runAllReady(); - // THEN the row is nulled out so that it won't be retained - Assert.assertTrue("The row should be null", runner.getRow() == null); - } - private void executePostsImmediately(View view) { doAnswer((i) -> { Runnable run = i.getArgument(0); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java index 4b21ef294db8..0272028e62fc 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationConversationInfoTest.java @@ -60,6 +60,7 @@ import android.content.pm.ShortcutInfo; import android.content.pm.ShortcutManager; import android.graphics.drawable.Drawable; import android.graphics.drawable.Icon; +import android.os.Handler; import android.os.UserHandle; import android.service.notification.StatusBarNotification; import android.test.suitebuilder.annotation.SmallTest; @@ -72,7 +73,6 @@ import android.widget.TextView; import com.android.internal.logging.MetricsLogger; import com.android.settingslib.notification.ConversationIconFactory; -import com.android.systemui.Dependency; import com.android.systemui.Prefs; import com.android.systemui.R; import com.android.systemui.SysuiTestCase; @@ -153,13 +153,14 @@ public class NotificationConversationInfoTest extends SysuiTestCase { private Provider<PriorityOnboardingDialogController.Builder> mBuilderProvider = () -> mBuilder; @Mock private Notification.BubbleMetadata mBubbleMetadata; + private Handler mTestHandler; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mTestableLooper = TestableLooper.get(this); - mDependency.injectTestDependency(Dependency.BG_LOOPER, mTestableLooper.getLooper()); + mTestHandler = new Handler(mTestableLooper.getLooper()); mDependency.injectTestDependency(MetricsLogger.class, mMetricsLogger); mDependency.injectTestDependency(BubbleController.class, mBubbleController); mDependency.injectTestDependency(ShadeController.class, mShadeController); @@ -253,7 +254,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final ImageView view = mNotificationInfo.findViewById(R.id.conversation_icon); assertEquals(mIconDrawable, view.getDrawable()); } @@ -275,7 +278,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final TextView textView = mNotificationInfo.findViewById(R.id.pkg_name); assertTrue(textView.getText().toString().contains("App Name")); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -324,7 +329,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertTrue(textView.getText().toString().contains(group.getName())); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); @@ -348,7 +355,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final TextView textView = mNotificationInfo.findViewById(R.id.group_name); assertEquals(VISIBLE, mNotificationInfo.findViewById(R.id.header).getVisibility()); assertEquals(GONE, textView.getVisibility()); @@ -371,7 +380,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(GONE, nameView.getVisibility()); } @@ -404,7 +415,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final TextView nameView = mNotificationInfo.findViewById(R.id.delegate_name); assertEquals(VISIBLE, nameView.getVisibility()); assertTrue(nameView.getText().toString().contains("Proxied")); @@ -430,7 +443,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final View settingsButton = mNotificationInfo.findViewById(R.id.info); settingsButton.performClick(); @@ -454,7 +469,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -479,7 +496,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - false); + false, + mTestHandler, + mTestHandler); final View settingsButton = mNotificationInfo.findViewById(R.id.info); assertTrue(settingsButton.getVisibility() != View.VISIBLE); } @@ -502,7 +521,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View view = mNotificationInfo.findViewById(R.id.silence); assertThat(view.isSelected()).isTrue(); } @@ -528,7 +549,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo( @@ -557,7 +580,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View view = mNotificationInfo.findViewById(R.id.default_behavior); assertThat(view.isSelected()).isTrue(); assertThat(((TextView) view.findViewById(R.id.default_summary)).getText()).isEqualTo( @@ -585,7 +610,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -627,7 +654,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mTestableLooper.processAllMessages(); @@ -668,7 +697,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View silence = mNotificationInfo.findViewById(R.id.silence); @@ -710,7 +741,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -745,7 +778,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View fave = mNotificationInfo.findViewById(R.id.priority); fave.performClick(); @@ -778,7 +813,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -812,7 +849,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -846,7 +885,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); mNotificationInfo.findViewById(R.id.default_behavior).performClick(); mNotificationInfo.findViewById(R.id.done).performClick(); @@ -879,7 +920,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); View silence = mNotificationInfo.findViewById(R.id.silence); silence.performClick(); @@ -911,7 +954,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); verify(mMockINotificationManager, times(1)).createConversationNotificationChannelForPackage( anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID)); @@ -934,7 +979,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, mBuilderProvider, - true); + true, + mTestHandler, + mTestHandler); verify(mMockINotificationManager, never()).createConversationNotificationChannelForPackage( anyString(), anyInt(), anyString(), any(), eq(CONVERSATION_ID)); @@ -967,7 +1014,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, () -> b, - true); + true, + mTestHandler, + mTestHandler); // WHEN user clicks "priority" mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); @@ -1001,7 +1050,9 @@ public class NotificationConversationInfoTest extends SysuiTestCase { mIconFactory, mContext, () -> b, - true); + true, + mTestHandler, + mTestHandler); // WHEN user clicks "priority" mNotificationInfo.setSelectedAction(NotificationConversationInfo.ACTION_FAVORITE); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java index eeb912e7aac8..da7d249cc5ef 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/NotificationGutsManagerTest.java @@ -144,7 +144,7 @@ public class NotificationGutsManagerTest extends SysuiTestCase { when(mAccessibilityManager.isTouchExplorationEnabled()).thenReturn(false); mGutsManager = new NotificationGutsManager(mContext, mVisualStabilityManager, - () -> mStatusBar, mHandler, mAccessibilityManager, mHighPriorityProvider, + () -> mStatusBar, mHandler, mHandler, mAccessibilityManager, mHighPriorityProvider, mINotificationManager, mLauncherApps, mShortcutManager, mChannelEditorDialogController, mContextTracker, mProvider); mGutsManager.setUpWithPresenter(mPresenter, mStackScroller, diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java index 06a2eecd208c..323d8bd9d2e6 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationSwipeHelperTest.java @@ -436,8 +436,8 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { assertEquals("returns false when view is null", false, NotificationSwipeHelper.isTouchInView(mEvent, null)); - doReturn(5f).when(mEvent).getRawX(); - doReturn(10f).when(mEvent).getRawY(); + doReturn(5f).when(mEvent).getX(); + doReturn(10f).when(mEvent).getY(); doReturn(20).when(mView).getWidth(); doReturn(20).when(mView).getHeight(); @@ -453,7 +453,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mView)); - doReturn(50f).when(mEvent).getRawX(); + doReturn(50f).when(mEvent).getX(); assertFalse("Touch is not within the view", mSwipeHelper.isTouchInView(mEvent, mView)); @@ -464,8 +464,8 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { assertEquals("returns false when view is null", false, NotificationSwipeHelper.isTouchInView(mEvent, null)); - doReturn(5f).when(mEvent).getRawX(); - doReturn(10f).when(mEvent).getRawY(); + doReturn(5f).when(mEvent).getX(); + doReturn(10f).when(mEvent).getY(); doReturn(20).when(mNotificationRow).getWidth(); doReturn(20).when(mNotificationRow).getActualHeight(); @@ -481,7 +481,7 @@ public class NotificationSwipeHelperTest extends SysuiTestCase { assertTrue("Touch is within the view", mSwipeHelper.isTouchInView(mEvent, mNotificationRow)); - doReturn(50f).when(mEvent).getRawX(); + doReturn(50f).when(mEvent).getX(); assertFalse("Touch is not within the view", mSwipeHelper.isTouchInView(mEvent, mNotificationRow)); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java deleted file mode 100644 index a14d57556360..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/PhoneStatusBarPolicyTest.java +++ /dev/null @@ -1,168 +0,0 @@ -/* - * Copyright (C) 2020 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.systemui.statusbar.phone; - -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.clearInvocations; -import static org.mockito.Mockito.spy; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - -import android.app.AlarmManager; -import android.app.IActivityManager; -import android.content.SharedPreferences; -import android.content.res.Resources; -import android.os.UserManager; -import android.telecom.TelecomManager; -import android.testing.AndroidTestingRunner; -import android.testing.TestableLooper; - -import androidx.test.filters.SmallTest; - -import com.android.systemui.SysuiTestCase; -import com.android.systemui.broadcast.BroadcastDispatcher; -import com.android.systemui.media.MediaDataManager; -import com.android.systemui.screenrecord.RecordingController; -import com.android.systemui.statusbar.CommandQueue; -import com.android.systemui.statusbar.policy.BluetoothController; -import com.android.systemui.statusbar.policy.CastController; -import com.android.systemui.statusbar.policy.DataSaverController; -import com.android.systemui.statusbar.policy.DeviceProvisionedController; -import com.android.systemui.statusbar.policy.HotspotController; -import com.android.systemui.statusbar.policy.KeyguardStateController; -import com.android.systemui.statusbar.policy.LocationController; -import com.android.systemui.statusbar.policy.NextAlarmController; -import com.android.systemui.statusbar.policy.RotationLockController; -import com.android.systemui.statusbar.policy.SensorPrivacyController; -import com.android.systemui.statusbar.policy.UserInfoController; -import com.android.systemui.statusbar.policy.ZenModeController; -import com.android.systemui.util.RingerModeLiveData; -import com.android.systemui.util.RingerModeTracker; -import com.android.systemui.util.time.DateFormatUtil; - -import org.junit.Before; -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.mockito.Mock; -import org.mockito.junit.MockitoJUnit; -import org.mockito.junit.MockitoRule; - -import java.util.concurrent.Executor; - -@RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper -@SmallTest -public class PhoneStatusBarPolicyTest extends SysuiTestCase { - - private static final int DISPLAY_ID = 0; - @Mock - private StatusBarIconController mIconController; - @Mock - private CommandQueue mCommandQueue; - @Mock - private BroadcastDispatcher mBroadcastDispatcher; - @Mock - private Executor mBackgroundExecutor; - @Mock - private CastController mCastController; - @Mock - private HotspotController mHotSpotController; - @Mock - private BluetoothController mBluetoothController; - @Mock - private NextAlarmController mNextAlarmController; - @Mock - private UserInfoController mUserInfoController; - @Mock - private RotationLockController mRotationLockController; - @Mock - private DataSaverController mDataSaverController; - @Mock - private ZenModeController mZenModeController; - @Mock - private DeviceProvisionedController mDeviceProvisionerController; - @Mock - private KeyguardStateController mKeyguardStateController; - @Mock - private LocationController mLocationController; - @Mock - private SensorPrivacyController mSensorPrivacyController; - @Mock - private IActivityManager mIActivityManager; - @Mock - private AlarmManager mAlarmManager; - @Mock - private UserManager mUserManager; - @Mock - private RecordingController mRecordingController; - @Mock - private MediaDataManager mMediaDataManager; - @Mock - private TelecomManager mTelecomManager; - @Mock - private SharedPreferences mSharedPreferences; - @Mock - private DateFormatUtil mDateFormatUtil; - @Mock - private RingerModeTracker mRingerModeTracker; - @Mock - private RingerModeLiveData mRingerModeLiveData; - @Rule - public MockitoRule rule = MockitoJUnit.rule(); - private Resources mResources; - private PhoneStatusBarPolicy mPhoneStatusBarPolicy; - - @Before - public void setup() { - mResources = spy(getContext().getResources()); - mPhoneStatusBarPolicy = new PhoneStatusBarPolicy(mIconController, mCommandQueue, - mBroadcastDispatcher, mBackgroundExecutor, mResources, mCastController, - mHotSpotController, mBluetoothController, mNextAlarmController, mUserInfoController, - mRotationLockController, mDataSaverController, mZenModeController, - mDeviceProvisionerController, mKeyguardStateController, mLocationController, - mSensorPrivacyController, mIActivityManager, mAlarmManager, mUserManager, - mRecordingController, mMediaDataManager, mTelecomManager, DISPLAY_ID, - mSharedPreferences, mDateFormatUtil, mRingerModeTracker); - when(mRingerModeTracker.getRingerMode()).thenReturn(mRingerModeLiveData); - when(mRingerModeTracker.getRingerModeInternal()).thenReturn(mRingerModeLiveData); - clearInvocations(mIconController); - } - - @Test - public void testInit_registerMediaCallback() { - mPhoneStatusBarPolicy.init(); - verify(mMediaDataManager).addListener(eq(mPhoneStatusBarPolicy)); - } - - @Test - public void testOnMediaDataLoaded_updatesIcon_hasMedia() { - String mediaSlot = mResources.getString(com.android.internal.R.string.status_bar_media); - when(mMediaDataManager.hasActiveMedia()).thenReturn(true); - mPhoneStatusBarPolicy.onMediaDataLoaded(null, null); - verify(mMediaDataManager).hasActiveMedia(); - verify(mIconController).setIconVisibility(eq(mediaSlot), eq(true)); - } - - @Test - public void testOnMediaDataRemoved_updatesIcon_noMedia() { - String mediaSlot = mResources.getString(com.android.internal.R.string.status_bar_media); - mPhoneStatusBarPolicy.onMediaDataRemoved(null); - verify(mMediaDataManager).hasActiveMedia(); - verify(mIconController).setIconVisibility(eq(mediaSlot), eq(false)); - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java index 53a1773b1bd1..acdb2c59dc0c 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java @@ -282,7 +282,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + verify(mBubbleController).expandStackAndSelectBubble(eq(mBubbleNotificationRow.getEntry())); // This is called regardless, and simply short circuits when there is nothing to do. verify(mShadeController, atLeastOnce()).collapsePanel(); @@ -313,7 +313,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + verify(mBubbleController).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); verify(mShadeController, atLeastOnce()).collapsePanel(); @@ -343,7 +343,7 @@ public class StatusBarNotificationActivityStarterTest extends SysuiTestCase { mNotificationActivityStarter.onNotificationClicked(sbn, mBubbleNotificationRow); // Then - verify(mBubbleController).expandStackAndSelectBubble(eq(sbn.getKey())); + verify(mBubbleController).expandStackAndSelectBubble(mBubbleNotificationRow.getEntry()); verify(mShadeController, atLeastOnce()).collapsePanel(); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java index 27cbb03b4e9d..5a08c9ca017b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java @@ -251,7 +251,6 @@ public class StatusBarTest extends SysuiTestCase { @Mock private Lazy<NotificationShadeDepthController> mNotificationShadeDepthControllerLazy; private ShadeController mShadeController; private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock()); - private FakeExecutor mMainExecutor = new FakeExecutor(new FakeSystemClock()); private InitController mInitController = new InitController(); @Before @@ -354,7 +353,6 @@ public class StatusBarTest extends SysuiTestCase { new DisplayMetrics(), mMetricsLogger, mUiBgExecutor, - mMainExecutor, mNotificationMediaManager, mLockscreenUserManager, mRemoteInputManager, diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 1ee017be5097..8ae30a5c6f92 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -33,7 +33,7 @@ java_defaults { "net-utils-framework-common", ], libs: [ - "framework-tethering", + "framework-tethering.impl", "framework-wifi-stubs-systemapi", "unsupportedappusage", ], diff --git a/packages/Tethering/common/TetheringLib/Android.bp b/packages/Tethering/common/TetheringLib/Android.bp index ae4bb3e5e259..408725c8658b 100644 --- a/packages/Tethering/common/TetheringLib/Android.bp +++ b/packages/Tethering/common/TetheringLib/Android.bp @@ -13,31 +13,28 @@ // See the License for the specific language governing permissions and // limitations under the License. -java_library { +java_sdk_library { name: "framework-tethering", - sdk_version: "module_current", + defaults: ["framework-module-defaults"], srcs: [ ":framework-tethering-srcs", ], + + // TODO(b/155480189) - Remove naming_scheme once references have been resolved. + // Temporary java_sdk_library component naming scheme to use to ease the transition from separate + // modules to java_sdk_library. + naming_scheme: "framework-modules", + jarjar_rules: "jarjar-rules.txt", installable: true, - libs: [ - "framework-annotations-lib", - ], - hostdex: true, // for hiddenapi check visibility: ["//frameworks/base/packages/Tethering:__subpackages__"], + stubs_library_visibility: ["//visibility:public"], apex_available: ["com.android.tethering"], permitted_packages: ["android.net"], } -stubs_defaults { - name: "framework-tethering-stubs-defaults", - srcs: [":framework-tethering-srcs"], - dist: { dest: "framework-tethering.txt" }, -} - filegroup { name: "framework-tethering-srcs", srcs: [ @@ -55,83 +52,3 @@ filegroup { ], path: "src" } - -droidstubs { - name: "framework-tethering-stubs-srcs-publicapi", - defaults: [ - "framework-module-stubs-defaults-publicapi", - "framework-tethering-stubs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-tethering.api.public.latest", - removed_api_file: ":framework-tethering-removed.api.public.latest", - }, - api_lint: { - new_since: ":framework-tethering.api.public.latest", - }, - }, -} - -droidstubs { - name: "framework-tethering-stubs-srcs-systemapi", - defaults: [ - "framework-module-stubs-defaults-systemapi", - "framework-tethering-stubs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-tethering.api.system.latest", - removed_api_file: ":framework-tethering-removed.api.system.latest", - }, - api_lint: { - new_since: ":framework-tethering.api.system.latest", - }, - }, -} - -droidstubs { - name: "framework-tethering-api-module_libs_api", - defaults: [ - "framework-module-api-defaults-module_libs_api", - "framework-tethering-stubs-defaults", - ], - check_api: { - last_released: { - api_file: ":framework-tethering.api.module-lib.latest", - removed_api_file: ":framework-tethering-removed.api.module-lib.latest", - }, - api_lint: { - new_since: ":framework-tethering.api.module-lib.latest", - }, - }, -} - -droidstubs { - name: "framework-tethering-stubs-srcs-module_libs_api", - defaults: [ - "framework-module-stubs-defaults-module_libs_api", - "framework-tethering-stubs-defaults", - ], -} - -java_library { - name: "framework-tethering-stubs-publicapi", - srcs: [":framework-tethering-stubs-srcs-publicapi"], - defaults: ["framework-module-stubs-lib-defaults-publicapi"], - dist: { dest: "framework-tethering.jar" }, -} - -java_library { - name: "framework-tethering-stubs-systemapi", - srcs: [":framework-tethering-stubs-srcs-systemapi"], - defaults: ["framework-module-stubs-lib-defaults-systemapi"], - dist: { dest: "framework-tethering.jar" }, -} - -java_library { - name: "framework-tethering-stubs-module_libs_api", - srcs: [":framework-tethering-stubs-srcs-module_libs_api"], - defaults: ["framework-module-stubs-lib-defaults-module_libs_api"], - dist: { dest: "framework-tethering.jar" }, -} diff --git a/packages/Tethering/tests/integration/Android.bp b/packages/Tethering/tests/integration/Android.bp index 3305ed084481..ed69b7d63cb4 100644 --- a/packages/Tethering/tests/integration/Android.bp +++ b/packages/Tethering/tests/integration/Android.bp @@ -63,7 +63,6 @@ android_test { // NetworkStackTests. android_test { name: "TetheringCoverageTests", - certificate: "platform", platform_apis: true, test_suites: ["device-tests", "mts"], test_config: "AndroidTest_Coverage.xml", diff --git a/packages/Tethering/tests/unit/Android.bp b/packages/Tethering/tests/unit/Android.bp index 08cfb30813ca..fccc6902e365 100644 --- a/packages/Tethering/tests/unit/Android.bp +++ b/packages/Tethering/tests/unit/Android.bp @@ -29,7 +29,7 @@ java_library { sdk_version: "core_platform", libs: [ "framework-minus-apex", - "framework-tethering", + "framework-tethering.impl", ], visibility: ["//cts/tests/tests/tethering"], } @@ -59,7 +59,7 @@ java_defaults { "ext", "framework-minus-apex", "framework-res", - "framework-tethering", + "framework-tethering.impl", "framework-wifi-stubs-module_libs_api", ], jni_libs: [ @@ -83,7 +83,7 @@ android_library { android_test { name: "TetheringTests", - certificate: "platform", + platform_apis: true, test_suites: [ "device-tests", "mts", diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java index 07bb3356aec0..22b082f84a84 100644 --- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java +++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java @@ -1136,6 +1136,7 @@ public class AccessibilityManagerService extends IAccessibilityManager.Stub userState.mEnabledServices, UserHandle.USER_SYSTEM); onUserStateChangedLocked(userState); + migrateAccessibilityButtonSettingsIfNecessaryLocked(userState, null); } private int getClientStateLocked(AccessibilityUserState userState) { diff --git a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java index 103151dcdda5..26e85beba58b 100644 --- a/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java +++ b/services/appprediction/java/com/android/server/appprediction/AppPredictionPerUserService.java @@ -51,7 +51,7 @@ import java.util.function.Consumer; */ public class AppPredictionPerUserService extends AbstractPerUserSystemService<AppPredictionPerUserService, AppPredictionManagerService> - implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks { + implements RemoteAppPredictionService.RemoteAppPredictionServiceCallbacks { private static final String TAG = AppPredictionPerUserService.class.getSimpleName(); private static final String PREDICT_USING_PEOPLE_SERVICE_PREFIX = @@ -114,8 +114,11 @@ public class AppPredictionPerUserService extends public void onCreatePredictionSessionLocked(@NonNull AppPredictionContext context, @NonNull AppPredictionSessionId sessionId) { if (!mSessionInfos.containsKey(sessionId)) { + // TODO(b/157500121): remove below forceUsingPeopleService logic after testing + // PeopleService for 2 weeks on Droidfood. + final boolean forceUsingPeopleService = context.getUiSurface().equals("share"); mSessionInfos.put(sessionId, new AppPredictionSessionInfo(sessionId, context, - DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, + forceUsingPeopleService || DeviceConfig.getBoolean(NAMESPACE_SYSTEMUI, PREDICT_USING_PEOPLE_SERVICE_PREFIX + context.getUiSurface(), false), this::removeAppPredictionSessionInfo)); } diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java index 06c60a3d08eb..37ed6f790c19 100644 --- a/services/autofill/java/com/android/server/autofill/Session.java +++ b/services/autofill/java/com/android/server/autofill/Session.java @@ -2588,14 +2588,15 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState id)) { // Regular autofill handled the view and returned null response, but it // triggered augmented autofill - if (!isSameViewEntered) { + if (!isSameViewEntered || mExpiredResponse) { if (sDebug) Slog.d(TAG, "trigger augmented autofill."); triggerAugmentedAutofillLocked(flags); } else { if (sDebug) Slog.d(TAG, "skip augmented autofill for same view."); } return; - } else if (mForAugmentedAutofillOnly && isSameViewEntered) { + } else if (mForAugmentedAutofillOnly && isSameViewEntered + && !mExpiredResponse) { // Regular autofill is disabled. if (sDebug) Slog.d(TAG, "skip augmented autofill for same view."); return; diff --git a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java index 9a170ac6da10..0b9bf3962562 100644 --- a/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java +++ b/services/contentcapture/java/com/android/server/contentcapture/RemoteContentCaptureService.java @@ -54,7 +54,9 @@ final class RemoteContentCaptureService boolean verbose, int idleUnbindTimeoutMs) { super(context, serviceInterface, serviceComponentName, userId, perUserService, context.getMainThreadHandler(), - bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0, verbose, + Context.BIND_INCLUDE_CAPABILITIES + | (bindInstantServiceAllowed ? Context.BIND_ALLOW_INSTANT : 0), + verbose, /* initialCapacity= */ 2); mPerUserService = perUserService; mServerCallback = callback.asBinder(); diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java index 72e170ff9532..b765d81d42b7 100644 --- a/services/core/java/com/android/server/AppStateTracker.java +++ b/services/core/java/com/android/server/AppStateTracker.java @@ -448,6 +448,7 @@ public class AppStateTracker { IntentFilter filter = new IntentFilter(); filter.addAction(Intent.ACTION_USER_REMOVED); filter.addAction(Intent.ACTION_BATTERY_CHANGED); + filter.addAction(Intent.ACTION_PACKAGE_REMOVED); mContext.registerReceiver(new MyReceiver(), filter); refreshForcedAppStandbyUidPackagesLocked(); @@ -688,6 +689,13 @@ public class AppStateTracker { mIsPluggedIn = (intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0) != 0); } updateForceAllAppStandbyState(); + } else if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction()) + && !intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) { + final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1); + final String pkgName = intent.getData().getSchemeSpecificPart(); + if (mExemptedPackages.remove(userId, pkgName)) { + mHandler.notifyExemptChanged(); + } } } } diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 7c61ba2e7adb..1e9a9d85e06a 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3102,30 +3102,24 @@ public class ConnectivityService extends IConnectivityManager.Stub } private void notifyDataStallSuspected(DataStallReportParcelable p, int netId) { + log("Data stall detected with methods: " + p.detectionMethod); + final PersistableBundle extras = new PersistableBundle(); - switch (p.detectionMethod) { - case DETECTION_METHOD_DNS_EVENTS: - extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts); - break; - case DETECTION_METHOD_TCP_METRICS: - extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate); - extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, - p.tcpMetricsCollectionPeriodMillis); - break; - default: - // TODO(b/156294356): update for new data stall detection methods - log("Unknown data stall detection method, ignoring: " + p.detectionMethod); - return; + int detectionMethod = 0; + if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) { + extras.putInt(KEY_DNS_CONSECUTIVE_TIMEOUTS, p.dnsConsecutiveTimeouts); + detectionMethod |= DETECTION_METHOD_DNS_EVENTS; + } + if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) { + extras.putInt(KEY_TCP_PACKET_FAIL_RATE, p.tcpPacketFailRate); + extras.putInt(KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS, + p.tcpMetricsCollectionPeriodMillis); + detectionMethod |= DETECTION_METHOD_TCP_METRICS; } - notifyDataStallSuspected(p.detectionMethod, netId, p.timestampMillis, extras); - } - - private void notifyDataStallSuspected(int detectionMethod, int netId, long timestampMillis, - @NonNull PersistableBundle extras) { final Message msg = mConnectivityDiagnosticsHandler.obtainMessage( ConnectivityDiagnosticsHandler.EVENT_DATA_STALL_SUSPECTED, detectionMethod, netId, - timestampMillis); + p.timestampMillis); msg.setData(new Bundle(extras)); // NetworkStateTrackerHandler currently doesn't take any actions based on data @@ -3134,6 +3128,10 @@ public class ConnectivityService extends IConnectivityManager.Stub mConnectivityDiagnosticsHandler.sendMessage(msg); } + private boolean hasDataStallDetectionMethod(DataStallReportParcelable p, int detectionMethod) { + return (p.detectionMethod & detectionMethod) != 0; + } + private boolean networkRequiresPrivateDnsValidation(NetworkAgentInfo nai) { return isPrivateDnsValidationRequired(nai.networkCapabilities); } @@ -8189,6 +8187,19 @@ public class ConnectivityService extends IConnectivityManager.Stub + "creators"); } - notifyDataStallSuspected(detectionMethod, network.netId, timestampMillis, extras); + final DataStallReportParcelable p = new DataStallReportParcelable(); + p.timestampMillis = timestampMillis; + p.detectionMethod = detectionMethod; + + if (hasDataStallDetectionMethod(p, DETECTION_METHOD_DNS_EVENTS)) { + p.dnsConsecutiveTimeouts = extras.getInt(KEY_DNS_CONSECUTIVE_TIMEOUTS); + } + if (hasDataStallDetectionMethod(p, DETECTION_METHOD_TCP_METRICS)) { + p.tcpPacketFailRate = extras.getInt(KEY_TCP_PACKET_FAIL_RATE); + p.tcpMetricsCollectionPeriodMillis = extras.getInt( + KEY_TCP_METRICS_COLLECTION_PERIOD_MILLIS); + } + + notifyDataStallSuspected(p, network.netId); } } diff --git a/services/core/java/com/android/server/PackageWatchdog.java b/services/core/java/com/android/server/PackageWatchdog.java index e77458cc955a..e303f0d00214 100644 --- a/services/core/java/com/android/server/PackageWatchdog.java +++ b/services/core/java/com/android/server/PackageWatchdog.java @@ -177,9 +177,6 @@ public class PackageWatchdog { // 0 if no prune is scheduled. @GuardedBy("mLock") private long mUptimeAtLastStateSync; - // If true, sync explicit health check packages with the ExplicitHealthCheckController. - @GuardedBy("mLock") - private boolean mSyncRequired = false; @FunctionalInterface @VisibleForTesting @@ -255,7 +252,6 @@ public class PackageWatchdog { */ public void registerHealthObserver(PackageHealthObserver observer) { synchronized (mLock) { - mSyncRequired = true; ObserverInternal internalObserver = mAllObservers.get(observer.getName()); if (internalObserver != null) { internalObserver.registeredObserver = observer; @@ -642,7 +638,7 @@ public class PackageWatchdog { synchronized (mLock) { if (mIsPackagesReady) { Set<String> packages = getPackagesPendingHealthChecksLocked(); - if (!packages.equals(mRequestedHealthCheckPackages) || mSyncRequired) { + if (!packages.equals(mRequestedHealthCheckPackages) || packages.isEmpty()) { syncRequired = true; mRequestedHealthCheckPackages = packages; } @@ -654,7 +650,6 @@ public class PackageWatchdog { Slog.i(TAG, "Syncing health check requests for packages: " + mRequestedHealthCheckPackages); mHealthCheckController.syncRequests(mRequestedHealthCheckPackages); - mSyncRequired = false; } } diff --git a/services/core/java/com/android/server/SystemService.java b/services/core/java/com/android/server/SystemService.java index e5c05408f628..45d53a14d1e9 100644 --- a/services/core/java/com/android/server/SystemService.java +++ b/services/core/java/com/android/server/SystemService.java @@ -68,8 +68,7 @@ import java.util.List; public abstract class SystemService { /** @hide */ - // TODO(b/133242016) STOPSHIP: change to false before R ships - protected static final boolean DEBUG_USER = true; + protected static final boolean DEBUG_USER = false; /* * The earliest boot phase the system send to system services on boot. diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java index cca604655f3d..ec12aebc37f6 100644 --- a/services/core/java/com/android/server/am/ActiveServices.java +++ b/services/core/java/com/android/server/am/ActiveServices.java @@ -4914,8 +4914,13 @@ public final class ActiveServices { // TODO: remove this toast after feature development is done void showWhileInUseDebugToastLocked(int uid, int op, int mode) { - for (int i = mAm.mProcessList.mLruProcesses.size() - 1; i >= 0; i--) { - ProcessRecord pr = mAm.mProcessList.mLruProcesses.get(i); + 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; } diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java index 671733b7cb7a..7ef527cb7d84 100644 --- a/services/core/java/com/android/server/am/ActivityManagerService.java +++ b/services/core/java/com/android/server/am/ActivityManagerService.java @@ -11112,6 +11112,14 @@ public class ActivityManagerService extends IActivityManager.Stub } pw.print(" UID "); UserHandle.formatUid(pw, uidRec.uid); pw.print(": "); pw.println(uidRec); + pw.print(" curProcState="); pw.print(uidRec.mCurProcState); + pw.print(" curCapability="); + ActivityManager.printCapabilitiesFull(pw, uidRec.curCapability); + pw.println(); + for (int j = uidRec.procRecords.size() - 1; j >= 0; j--) { + pw.print(" proc="); + pw.println(uidRec.procRecords.valueAt(j)); + } } return printed; } diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java index f7a158a885c6..a81590c8c022 100644 --- a/services/core/java/com/android/server/am/OomAdjuster.java +++ b/services/core/java/com/android/server/am/OomAdjuster.java @@ -324,8 +324,21 @@ public final class OomAdjuster { boolean success = applyOomAdjLocked(app, doingAll, now, SystemClock.elapsedRealtime()); if (uidRec != null) { - updateAppUidRecLocked(app); - // If this proc state is changed, need to update its uid record here + // After uidRec.reset() above, for UidRecord that has multiple processes (ProcessRecord) + // , We need to apply all ProcessRecord into UidRecord. + final ArraySet<ProcessRecord> procRecords = app.uidRecord.procRecords; + for (int i = procRecords.size() - 1; i >= 0; i--) { + final ProcessRecord pr = procRecords.valueAt(i); + if (!pr.killedByAm && pr.thread != null) { + if (pr.isolated && pr.numberOfRunningServices() <= 0 + && pr.isolatedEntryPoint == null) { + // No op. + } else { + // Keeping this process, update its uid. + updateAppUidRecLocked(pr); + } + } + } if (uidRec.getCurProcState() != PROCESS_STATE_NONEXISTENT && (uidRec.setProcState != uidRec.getCurProcState() || uidRec.setCapability != uidRec.curCapability diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java index 108fb7dff2cd..9f2a77c05d2b 100644 --- a/services/core/java/com/android/server/am/ProcessList.java +++ b/services/core/java/com/android/server/am/ProcessList.java @@ -2808,6 +2808,7 @@ public final class ProcessList { uidRec.curCapability); } proc.uidRecord = uidRec; + uidRec.procRecords.add(proc); // Reset render thread tid if it was already set, so new process can set it again. proc.renderThreadTid = 0; @@ -2901,6 +2902,7 @@ public final class ProcessList { } if (old != null && old.uidRecord != null) { old.uidRecord.numProcs--; + old.uidRecord.procRecords.remove(old); if (old.uidRecord.numProcs == 0) { // No more processes using this uid, tell clients it is gone. if (DEBUG_UID_OBSERVERS) Slog.i(TAG_UID_OBSERVERS, diff --git a/services/core/java/com/android/server/am/UidRecord.java b/services/core/java/com/android/server/am/UidRecord.java index acf8b2e84821..c84ccb298bef 100644 --- a/services/core/java/com/android/server/am/UidRecord.java +++ b/services/core/java/com/android/server/am/UidRecord.java @@ -21,6 +21,7 @@ import android.app.ActivityManager; import android.content.pm.PackageManager; import android.os.SystemClock; import android.os.UserHandle; +import android.util.ArraySet; import android.util.TimeUtils; import android.util.proto.ProtoOutputStream; import android.util.proto.ProtoUtils; @@ -32,7 +33,7 @@ import com.android.internal.annotations.GuardedBy; */ public final class UidRecord { final int uid; - private int mCurProcState; + int mCurProcState; int setProcState = ActivityManager.PROCESS_STATE_NONEXISTENT; int curCapability; int setCapability; @@ -44,6 +45,7 @@ public final class UidRecord { boolean idle; boolean setIdle; int numProcs; + ArraySet<ProcessRecord> procRecords = new ArraySet<>(); /** * Sequence number associated with the {@link #mCurProcState}. This is incremented using diff --git a/services/core/java/com/android/server/appop/AppOpsService.java b/services/core/java/com/android/server/appop/AppOpsService.java index e70de5727334..a33ad7dc0ea1 100644 --- a/services/core/java/com/android/server/appop/AppOpsService.java +++ b/services/core/java/com/android/server/appop/AppOpsService.java @@ -5533,10 +5533,12 @@ public class AppOpsService extends IAppOpsService.Stub { pw.println(AppOpsManager.getUidStateName(uidState.pendingState)); } pw.print(" capability="); - pw.println(uidState.capability); + ActivityManager.printCapabilitiesFull(pw, uidState.capability); + pw.println(); if (uidState.capability != uidState.pendingCapability) { pw.print(" pendingCapability="); - pw.println(uidState.pendingCapability); + ActivityManager.printCapabilitiesFull(pw, uidState.pendingCapability); + pw.println(); } pw.print(" appWidgetVisible="); pw.println(uidState.appWidgetVisible); diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java index df4c269d6afa..67e27c41bbc7 100644 --- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java +++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java @@ -45,7 +45,10 @@ import com.android.internal.annotations.GuardedBy; import java.io.PrintWriter; import java.util.ArrayList; +import java.util.HashSet; import java.util.NoSuchElementException; +import java.util.Set; +import java.util.concurrent.atomic.AtomicBoolean; /** @hide */ @@ -59,6 +62,9 @@ import java.util.NoSuchElementException; // Timeout for connection to bluetooth headset service /*package*/ static final int BT_HEADSET_CNCT_TIMEOUT_MS = 3000; + // Delay before checking it music should be unmuted after processing an A2DP message + private static final int BTA2DP_MUTE_CHECK_DELAY_MS = 50; + private final @NonNull AudioService mAudioService; private final @NonNull Context mContext; @@ -1050,9 +1056,19 @@ import java.util.NoSuchElementException; final int strategy = msg.arg1; mDeviceInventory.onSaveRemovePreferredDevice(strategy); } break; + case MSG_CHECK_MUTE_MUSIC: + checkMessagesMuteMusic(); + break; default: Log.wtf(TAG, "Invalid message " + msg.what); } + + // Give some time to Bluetooth service to post a connection message + // in case of active device switch + if (MESSAGES_MUTE_MUSIC.contains(msg.what)) { + sendMsg(MSG_CHECK_MUTE_MUSIC, SENDMSG_REPLACE, BTA2DP_MUTE_CHECK_DELAY_MS); + } + if (isMessageHandledUnderWakelock(msg.what)) { try { mBrokerEventWakeLock.release(); @@ -1116,6 +1132,7 @@ import java.util.NoSuchElementException; private static final int MSG_I_SAVE_REMOVE_PREF_DEVICE_FOR_STRATEGY = 34; private static final int MSG_L_SPEAKERPHONE_CLIENT_DIED = 35; + private static final int MSG_CHECK_MUTE_MUSIC = 36; private static boolean isMessageHandledUnderWakelock(int msgId) { @@ -1132,6 +1149,7 @@ import java.util.NoSuchElementException; case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION: case MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION: case MSG_L_HEARING_AID_DEVICE_CONNECTION_CHANGE_EXT: + case MSG_CHECK_MUTE_MUSIC: return true; default: return false; @@ -1231,6 +1249,37 @@ import java.util.NoSuchElementException; mBrokerHandler.sendMessageAtTime(mBrokerHandler.obtainMessage(msg, arg1, arg2, obj), time); } + if (MESSAGES_MUTE_MUSIC.contains(msg)) { + checkMessagesMuteMusic(); + } + } + + /** List of messages for which music is muted while processing is pending */ + private static final Set<Integer> MESSAGES_MUTE_MUSIC; + static { + MESSAGES_MUTE_MUSIC = new HashSet<>(); + MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_CONNECTED); + MESSAGES_MUTE_MUSIC.add(MSG_IL_SET_A2DP_SINK_CONNECTION_STATE_DISCONNECTED); + MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONFIG_CHANGE); + MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_ACTIVE_DEVICE_CHANGE); + MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_CONNECTION); + MESSAGES_MUTE_MUSIC.add(MSG_L_A2DP_DEVICE_CONNECTION_CHANGE_EXT_DISCONNECTION); + } + + private AtomicBoolean mMusicMuted = new AtomicBoolean(false); + + /** Mutes or unmutes music according to pending A2DP messages */ + private void checkMessagesMuteMusic() { + boolean mute = false; + for (int msg : MESSAGES_MUTE_MUSIC) { + if (mBrokerHandler.hasMessages(msg)) { + mute = true; + break; + } + } + if (mute != mMusicMuted.getAndSet(mute)) { + mAudioService.setMusicMute(mute); + } } private class SpeakerphoneClient implements IBinder.DeathRecipient { diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java index d5f014ba38c0..ed05ffffaa38 100755 --- a/services/core/java/com/android/server/audio/AudioService.java +++ b/services/core/java/com/android/server/audio/AudioService.java @@ -109,6 +109,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.PowerManager; +import android.os.Process; import android.os.RemoteException; import android.os.ServiceManager; import android.os.SystemClock; @@ -3186,10 +3187,17 @@ public class AudioService extends IAudioService.Stub return (mStreamStates[streamType].getMaxIndex() + 5) / 10; } - /** @see AudioManager#getStreamMinVolumeInt(int) */ + /** @see AudioManager#getStreamMinVolumeInt(int) + * Part of service interface, check permissions here */ public int getStreamMinVolume(int streamType) { ensureValidStreamType(streamType); - return (mStreamStates[streamType].getMinIndex() + 5) / 10; + final boolean isPrivileged = + Binder.getCallingUid() == Process.SYSTEM_UID + || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_SETTINGS) + == PackageManager.PERMISSION_GRANTED) + || (mContext.checkCallingPermission(Manifest.permission.MODIFY_AUDIO_ROUTING) + == PackageManager.PERMISSION_GRANTED); + return (mStreamStates[streamType].getMinIndex(isPrivileged) + 5) / 10; } /** Get last audible volume before stream was muted. */ @@ -5061,6 +5069,10 @@ public class AudioService extends IAudioService.Stub profile, suppressNoisyIntent, a2dpVolume); } + /*package*/ void setMusicMute(boolean mute) { + mStreamStates[AudioSystem.STREAM_MUSIC].muteInternally(mute); + } + /** * See AudioManager.handleBluetoothA2dpDeviceConfigChange() * @param device @@ -5463,6 +5475,7 @@ public class AudioService extends IAudioService.Stub private int mIndexMax; private boolean mIsMuted; + private boolean mIsMutedInternally; private String mVolumeIndexSettingName; private int mObservedDevices; @@ -5636,7 +5649,8 @@ public class AudioService extends IAudioService.Stub // Only set audio policy BT SCO stream volume to 0 when the stream is actually muted. // This allows RX path muting by the audio HAL only when explicitly muted but not when // index is just set to 0 to repect BT requirements - if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 && !mIsMuted) { + if (mStreamType == AudioSystem.STREAM_BLUETOOTH_SCO && index == 0 + && !isFullyMuted()) { index = 1; } AudioSystem.setStreamVolumeIndexAS(mStreamType, index, device); @@ -5645,7 +5659,7 @@ public class AudioService extends IAudioService.Stub // must be called while synchronized VolumeStreamState.class /*package*/ void applyDeviceVolume_syncVSS(int device, boolean isAvrcpAbsVolSupported) { int index; - if (mIsMuted) { + if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { @@ -5668,7 +5682,7 @@ public class AudioService extends IAudioService.Stub for (int i = 0; i < mIndexMap.size(); i++) { final int device = mIndexMap.keyAt(i); if (device != AudioSystem.DEVICE_OUT_DEFAULT) { - if (mIsMuted) { + if (isFullyMuted()) { index = 0; } else if (AudioSystem.DEVICE_OUT_ALL_A2DP_SET.contains(device) && isAvrcpAbsVolSupported) { @@ -5685,7 +5699,7 @@ public class AudioService extends IAudioService.Stub } // apply default volume last: by convention , default device volume will be used // by audio policy manager if no explicit volume is present for a given device type - if (mIsMuted) { + if (isFullyMuted()) { index = 0; } else { index = (getIndex(AudioSystem.DEVICE_OUT_DEFAULT) + 5)/10; @@ -5790,11 +5804,23 @@ public class AudioService extends IAudioService.Stub return mIndexMax; } + /** + * @return the lowest index regardless of permissions + */ public int getMinIndex() { return mIndexMin; } /** + * @param isPrivileged true if the caller is privileged and not subject to minimum + * volume index thresholds + * @return the lowest index that this caller can set or adjust to + */ + public int getMinIndex(boolean isPrivileged) { + return isPrivileged ? mIndexMin : mIndexMinNoPerm; + } + + /** * Copies all device/index pairs from the given VolumeStreamState after initializing * them with the volume for DEVICE_OUT_DEFAULT. No-op if the source VolumeStreamState * has the same stream type as this instance. @@ -5867,6 +5893,41 @@ public class AudioService extends IAudioService.Stub return changed; } + /** + * Mute/unmute the stream by AudioService + * @param state the new mute state + * @return true if the mute state was changed + */ + public boolean muteInternally(boolean state) { + boolean changed = false; + synchronized (VolumeStreamState.class) { + if (state != mIsMutedInternally) { + changed = true; + mIsMutedInternally = state; + + // Set the new mute volume. This propagates the values to + // the audio system, otherwise the volume won't be changed + // at the lower level. + sendMsg(mAudioHandler, + MSG_SET_ALL_VOLUMES, + SENDMSG_QUEUE, + 0, + 0, + this, 0); + } + } + if (changed) { + sVolumeLogger.log(new VolumeEvent( + VolumeEvent.VOL_MUTE_STREAM_INT, mStreamType, state)); + } + return changed; + } + + @GuardedBy("VolumeStreamState.class") + public boolean isFullyMuted() { + return mIsMuted || mIsMutedInternally; + } + public int getStreamType() { return mStreamType; } @@ -5903,6 +5964,8 @@ public class AudioService extends IAudioService.Stub private void dump(PrintWriter pw) { pw.print(" Muted: "); pw.println(mIsMuted); + pw.print(" Muted Internally: "); + pw.println(mIsMutedInternally); pw.print(" Min: "); pw.print((mIndexMin + 5) / 10); if (mIndexMin != mIndexMinNoPerm) { diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java index 591356746e38..f3ff02f3aedc 100644 --- a/services/core/java/com/android/server/audio/AudioServiceEvents.java +++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java @@ -100,6 +100,7 @@ public class AudioServiceEvents { static final int VOL_VOICE_ACTIVITY_HEARING_AID = 6; static final int VOL_MODE_CHANGE_HEARING_AID = 7; static final int VOL_SET_GROUP_VOL = 8; + static final int VOL_MUTE_STREAM_INT = 9; final int mOp; final int mStream; @@ -188,6 +189,18 @@ public class AudioServiceEvents { logMetricEvent(); } + /** used for VOL_MUTE_STREAM_INT */ + VolumeEvent(int op, int stream, boolean state) { + mOp = op; + mStream = stream; + mVal1 = state ? 1 : 0; + mVal2 = 0; + mCaller = null; + mGroupName = null; + mAudioAttributes = null; + logMetricEvent(); + } + /** * Audio Analytics unique Id. @@ -278,6 +291,9 @@ public class AudioServiceEvents { .set(MediaMetrics.Property.INDEX, mVal1) .record(); return; + case VOL_MUTE_STREAM_INT: + // No value in logging metrics for this internal event + return; default: return; } @@ -343,6 +359,11 @@ public class AudioServiceEvents { .append(" flags:0x").append(Integer.toHexString(mVal2)) .append(") from ").append(mCaller) .toString(); + case VOL_MUTE_STREAM_INT: + return new StringBuilder("VolumeStreamState.muteInternally(stream:") + .append(AudioSystem.streamToString(mStream)) + .append(mVal1 == 1 ? ", muted)" : ", unmuted)") + .toString(); default: return new StringBuilder("FIXME invalid op:").append(mOp).toString(); } } diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java index f3c787462d61..a33817c0bf24 100644 --- a/services/core/java/com/android/server/connectivity/Vpn.java +++ b/services/core/java/com/android/server/connectivity/Vpn.java @@ -65,6 +65,7 @@ import android.net.NetworkCapabilities; import android.net.NetworkInfo; import android.net.NetworkInfo.DetailedState; import android.net.NetworkProvider; +import android.net.NetworkRequest; import android.net.RouteInfo; import android.net.UidRange; import android.net.VpnManager; @@ -2225,12 +2226,27 @@ public class Vpn { @Override public void run() { - // Explicitly use only the network that ConnectivityService thinks is the "best." In - // other words, only ever use the currently selected default network. This does mean - // that in both onLost() and onConnected(), any old sessions MUST be torn down. This - // does NOT include VPNs. + // Unless the profile is restricted to test networks, explicitly use only the network + // that ConnectivityService thinks is the "best." In other words, only ever use the + // currently selected default network. This does mean that in both onLost() and + // onConnected(), any old sessions MUST be torn down. This does NOT include VPNs. + // + // When restricted to test networks, select any network with TRANSPORT_TEST. Since the + // creator of the profile and the test network creator both have MANAGE_TEST_NETWORKS, + // this is considered safe. final ConnectivityManager cm = ConnectivityManager.from(mContext); - cm.requestNetwork(cm.getDefaultRequest(), mNetworkCallback); + final NetworkRequest req; + + if (mProfile.isRestrictedToTestNetworks()) { + req = new NetworkRequest.Builder() + .clearCapabilities() + .addTransportType(NetworkCapabilities.TRANSPORT_TEST) + .build(); + } else { + req = cm.getDefaultRequest(); + } + + cm.requestNetwork(req, mNetworkCallback); } private boolean isActiveNetwork(@Nullable Network network) { @@ -2868,6 +2884,11 @@ public class Vpn { verifyCallingUidAndPackage(packageName); enforceNotRestrictedUser(); + if (profile.isRestrictedToTestNetworks) { + mContext.enforceCallingPermission(Manifest.permission.MANAGE_TEST_NETWORKS, + "Test-mode profiles require the MANAGE_TEST_NETWORKS permission"); + } + final byte[] encodedProfile = profile.encode(); if (encodedProfile.length > MAX_VPN_PROFILE_SIZE_BYTES) { throw new IllegalArgumentException("Profile too big"); diff --git a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java index b9cd43d0803d..787f7f398fcb 100644 --- a/services/core/java/com/android/server/display/BrightnessMappingStrategy.java +++ b/services/core/java/com/android/server/display/BrightnessMappingStrategy.java @@ -28,7 +28,6 @@ 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; @@ -347,10 +346,11 @@ public abstract class BrightnessMappingStrategy { } } + // Normalize entire brightness range to 0 - 1. protected static float normalizeAbsoluteBrightness(int brightness) { - return BrightnessSynchronizer.brightnessIntToFloat(brightness, - PowerManager.BRIGHTNESS_OFF + 1, PowerManager.BRIGHTNESS_ON, - PowerManager.BRIGHTNESS_MIN, PowerManager.BRIGHTNESS_MAX); + brightness = MathUtils.constrain(brightness, + PowerManager.BRIGHTNESS_OFF, PowerManager.BRIGHTNESS_ON); + return (float) brightness / PowerManager.BRIGHTNESS_ON; } private Pair<float[], float[]> insertControlPoint( diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java index 02d499fbd81f..dee6cd02917f 100644 --- a/services/core/java/com/android/server/display/DisplayManagerService.java +++ b/services/core/java/com/android/server/display/DisplayManagerService.java @@ -111,6 +111,7 @@ import java.io.PrintWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.List; +import java.util.Optional; import java.util.concurrent.CopyOnWriteArrayList; /** @@ -971,6 +972,18 @@ public final class DisplayManagerService extends SystemService { if (diff == DisplayDeviceInfo.DIFF_STATE) { Slog.i(TAG, "Display device changed state: \"" + info.name + "\", " + Display.stateToString(info.state)); + final Optional<Integer> viewportType = getViewportType(info); + if (viewportType.isPresent()) { + for (DisplayViewport d : mViewports) { + if (d.type == viewportType.get() && info.uniqueId.equals(d.uniqueId)) { + // Update display view port power state + d.isActive = Display.isActiveState(info.state); + } + } + if (mInputManagerInternal != null) { + mHandler.sendEmptyMessage(MSG_UPDATE_VIEWPORT); + } + } } else if (diff != 0) { Slog.i(TAG, "Display device changed: " + info); } @@ -1507,6 +1520,23 @@ public final class DisplayManagerService extends SystemService { mViewports.clear(); } + private Optional<Integer> getViewportType(DisplayDeviceInfo info) { + // Get the corresponding viewport type. + if ((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) { + return Optional.of(VIEWPORT_INTERNAL); + } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) { + return Optional.of(VIEWPORT_EXTERNAL); + } else if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL + && !TextUtils.isEmpty(info.uniqueId)) { + return Optional.of(VIEWPORT_VIRTUAL); + } else { + if (DEBUG) { + Slog.i(TAG, "Display " + info + " does not support input device matching."); + } + } + return Optional.empty(); + } + private void configureDisplayLocked(SurfaceControl.Transaction t, DisplayDevice device) { final DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked(); final boolean ownContent = (info.flags & DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY) != 0; @@ -1533,21 +1563,10 @@ public final class DisplayManagerService extends SystemService { return; } display.configureDisplayLocked(t, device, info.state == Display.STATE_OFF); - final int viewportType; - // Update the corresponding viewport. - if ((info.flags & DisplayDeviceInfo.FLAG_DEFAULT_DISPLAY) != 0) { - viewportType = VIEWPORT_INTERNAL; - } else if (info.touch == DisplayDeviceInfo.TOUCH_EXTERNAL) { - viewportType = VIEWPORT_EXTERNAL; - } else if (info.touch == DisplayDeviceInfo.TOUCH_VIRTUAL - && !TextUtils.isEmpty(info.uniqueId)) { - viewportType = VIEWPORT_VIRTUAL; - } else { - Slog.i(TAG, "Display " + info + " does not support input device matching."); - return; + final Optional<Integer> viewportType = getViewportType(info); + if (viewportType.isPresent()) { + populateViewportLocked(viewportType.get(), display.getDisplayIdLocked(), device, info); } - - populateViewportLocked(viewportType, display.getDisplayIdLocked(), device, info.uniqueId); } /** @@ -1587,12 +1606,13 @@ public final class DisplayManagerService extends SystemService { return viewport; } - private void populateViewportLocked(int viewportType, - int displayId, DisplayDevice device, String uniqueId) { - final DisplayViewport viewport = getViewportLocked(viewportType, uniqueId); + private void populateViewportLocked(int viewportType, int displayId, DisplayDevice device, + DisplayDeviceInfo info) { + final DisplayViewport viewport = getViewportLocked(viewportType, info.uniqueId); device.populateViewportLocked(viewport); viewport.valid = true; viewport.displayId = displayId; + viewport.isActive = Display.isActiveState(info.state); } private LogicalDisplay findLogicalDisplayForDeviceLocked(DisplayDevice device) { diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java index 52116a07e8e6..a498e3867c05 100644 --- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java +++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java @@ -820,10 +820,15 @@ public class InputMethodManagerService extends IInputMethodManager.Stub final EditorInfo mEditorInfo; @NonNull final String mRequestWindowName; + @Nullable + final String mImeControlTargetName; + @Nullable + final String mImeTargetNameFromWm; Entry(ClientState client, EditorInfo editorInfo, String focusedWindowName, @SoftInputModeFlags int softInputMode, @SoftInputShowHideReason int reason, - boolean inFullscreenMode, String requestWindowName) { + boolean inFullscreenMode, String requestWindowName, + @Nullable String imeControlTargetName, @Nullable String imeTargetName) { mClientState = client; mEditorInfo = editorInfo; mFocusedWindowName = focusedWindowName; @@ -833,6 +838,8 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mWallTime = System.currentTimeMillis(); mInFullscreenMode = inFullscreenMode; mRequestWindowName = requestWindowName; + mImeControlTargetName = imeControlTargetName; + mImeTargetNameFromWm = imeTargetName; } } @@ -873,6 +880,12 @@ public class InputMethodManagerService extends IInputMethodManager.Stub pw.println(" requestWindowName=" + entry.mRequestWindowName); pw.print(prefix); + pw.println(" imeControlTargetName=" + entry.mImeControlTargetName); + + pw.print(prefix); + pw.println(" imeTargetNameFromWm=" + entry.mImeTargetNameFromWm); + + pw.print(prefix); pw.print(" editorInfo: "); pw.print(" inputType=" + entry.mEditorInfo.inputType); pw.print(" privateImeOptions=" + entry.mEditorInfo.privateImeOptions); @@ -4123,7 +4136,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mWindowManagerInternal.getWindowName(mCurFocusedWindow), mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode, mWindowManagerInternal.getWindowName( - mShowRequestWindowMap.get(args.arg3)))); + mShowRequestWindowMap.get(args.arg3)), + mWindowManagerInternal.getImeControlTargetNameForLogging( + mCurTokenDisplayId), + mWindowManagerInternal.getImeTargetNameForLogging( + mCurTokenDisplayId))); } catch (RemoteException e) { } args.recycle(); @@ -4142,7 +4159,11 @@ public class InputMethodManagerService extends IInputMethodManager.Stub mWindowManagerInternal.getWindowName(mCurFocusedWindow), mCurFocusedWindowSoftInputMode, reason, mInFullscreenMode, mWindowManagerInternal.getWindowName( - mHideRequestWindowMap.get(args.arg3)))); + mHideRequestWindowMap.get(args.arg3)), + mWindowManagerInternal.getImeControlTargetNameForLogging( + mCurTokenDisplayId), + mWindowManagerInternal.getImeTargetNameForLogging( + mCurTokenDisplayId))); } catch (RemoteException e) { } args.recycle(); diff --git a/services/core/java/com/android/server/net/NetworkStatsFactory.java b/services/core/java/com/android/server/net/NetworkStatsFactory.java index 3dac106418c5..86ad0b308676 100644 --- a/services/core/java/com/android/server/net/NetworkStatsFactory.java +++ b/services/core/java/com/android/server/net/NetworkStatsFactory.java @@ -152,12 +152,10 @@ public class NetworkStatsFactory { /** * Applies 464xlat adjustments with ifaces noted with {@link #noteStackedIface(String, String)}. - * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map, boolean) + * @see NetworkStats#apply464xlatAdjustments(NetworkStats, NetworkStats, Map) */ - public void apply464xlatAdjustments(NetworkStats baseTraffic, - NetworkStats stackedTraffic, boolean useBpfStats) { - NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces, - useBpfStats); + public void apply464xlatAdjustments(NetworkStats baseTraffic, NetworkStats stackedTraffic) { + NetworkStats.apply464xlatAdjustments(baseTraffic, stackedTraffic, mStackedIfaces); } public NetworkStatsFactory() { @@ -380,7 +378,7 @@ public class NetworkStatsFactory { // network, the overhead is their fault. // No locking here: apply464xlatAdjustments behaves fine with an add-only // ConcurrentHashMap. - delta.apply464xlatAdjustments(mStackedIfaces, mUseBpfStats); + delta.apply464xlatAdjustments(mStackedIfaces); // Migrate data usage over a VPN to the TUN network. for (VpnInfo info : vpnArray) { diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java index dcbdfdf7a297..ba9f486092f7 100644 --- a/services/core/java/com/android/server/net/NetworkStatsService.java +++ b/services/core/java/com/android/server/net/NetworkStatsService.java @@ -1311,21 +1311,39 @@ public class NetworkStatsService extends INetworkStatsService.Stub { } // Traffic occurring on stacked interfaces is usually clatd. - // UID stats are always counted on the stacked interface and never - // on the base interface, because the packets on the base interface - // do not actually match application sockets until they are translated. // - // Interface stats are more complicated. Packets subject to BPF offload - // never appear on the base interface and only appear on the stacked - // interface, so to ensure those packets increment interface stats, interface - // stats from stacked interfaces must be collected. + // UID stats are always counted on the stacked interface and never on the base + // interface, because the packets on the base interface do not actually match + // application sockets (they're not IPv4) and thus the app uid is not known. + // For receive this is obvious: packets must be translated from IPv6 to IPv4 + // before the application socket can be found. + // For transmit: either they go through the clat daemon which by virtue of going + // through userspace strips the original socket association during the IPv4 to + // IPv6 translation process, or they are offloaded by eBPF, which doesn't: + // However, on an ebpf device the accounting is done in cgroup ebpf hooks, + // which don't trigger again post ebpf translation. + // (as such stats accounted to the clat uid are ignored) + // + // Interface stats are more complicated. + // + // eBPF offloaded 464xlat'ed packets never hit base interface ip6tables, and thus + // *all* statistics are collected by iptables on the stacked v4-* interface. + // + // Additionally for ingress all packets bound for the clat IPv6 address are dropped + // in ip6tables raw prerouting and thus even non-offloaded packets are only + // accounted for on the stacked interface. + // + // For egress, packets subject to eBPF offload never appear on the base interface + // and only appear on the stacked interface. Thus to ensure packets increment + // interface stats, we must collate data from stacked interfaces. For xt_qtaguid + // (or non eBPF offloaded) TX they would appear on both, however egress interface + // accounting is explicitly bypassed for traffic from the clat uid. + // final List<LinkProperties> stackedLinks = state.linkProperties.getStackedLinks(); for (LinkProperties stackedLink : stackedLinks) { final String stackedIface = stackedLink.getInterfaceName(); if (stackedIface != null) { - if (mUseBpfTrafficStats) { - findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); - } + findOrCreateNetworkIdentitySet(mActiveIfaces, stackedIface).add(ident); findOrCreateNetworkIdentitySet(mActiveUidIfaces, stackedIface).add(ident); if (isMobile) { mobileIfaces.add(stackedIface); @@ -1864,14 +1882,13 @@ public class NetworkStatsService extends INetworkStatsService.Stub { // fold tethering stats and operations into uid snapshot final NetworkStats tetherSnapshot = getNetworkStatsTethering(STATS_PER_UID); tetherSnapshot.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot, - mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, tetherSnapshot); uidSnapshot.combineAllValues(tetherSnapshot); // get a stale copy of uid stats snapshot provided by providers. final NetworkStats providerStats = getNetworkStatsFromProviders(STATS_PER_UID); providerStats.filter(UID_ALL, ifaces, TAG_ALL); - mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats, mUseBpfTrafficStats); + mStatsFactory.apply464xlatAdjustments(uidSnapshot, providerStats); uidSnapshot.combineAllValues(providerStats); uidSnapshot.combineAllValues(mUidOperations); diff --git a/services/core/java/com/android/server/notification/BubbleExtractor.java b/services/core/java/com/android/server/notification/BubbleExtractor.java index d7d413c2ffb0..0fa339f65cdb 100644 --- a/services/core/java/com/android/server/notification/BubbleExtractor.java +++ b/services/core/java/com/android/server/notification/BubbleExtractor.java @@ -75,9 +75,19 @@ public class BubbleExtractor implements NotificationSignalExtractor { mConfig.getBubblePreference( record.getSbn().getPackageName(), record.getSbn().getUid()); NotificationChannel recordChannel = record.getChannel(); + boolean canPresentAsBubble = canPresentAsBubble(record) + && !mActivityManager.isLowRamDevice() + && record.isConversation() + && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0; - if (!mConfig.bubblesEnabled() || bubblePreference == BUBBLE_PREFERENCE_NONE) { + if (!mConfig.bubblesEnabled() + || bubblePreference == BUBBLE_PREFERENCE_NONE + || !canPresentAsBubble) { record.setAllowBubble(false); + if (!canPresentAsBubble) { + // clear out bubble metadata since it can't be used + record.getNotification().setBubbleMetadata(null); + } } else if (recordChannel == null) { // the app is allowed but there's no channel to check record.setAllowBubble(true); @@ -86,14 +96,15 @@ public class BubbleExtractor implements NotificationSignalExtractor { } else if (bubblePreference == BUBBLE_PREFERENCE_SELECTED) { record.setAllowBubble(recordChannel.canBubble()); } + if (DBG) { + Slog.d(TAG, "record: " + record.getKey() + + " appPref: " + bubblePreference + + " canBubble: " + record.canBubble() + + " canPresentAsBubble: " + canPresentAsBubble + + " flagRemoved: " + record.isFlagBubbleRemoved()); + } - final boolean fulfillsPolicy = record.canBubble() - && record.isConversation() - && !mActivityManager.isLowRamDevice() - && (record.getNotification().flags & FLAG_FOREGROUND_SERVICE) == 0; - final boolean applyFlag = fulfillsPolicy - && canPresentAsBubble(record) - && !record.isFlagBubbleRemoved(); + final boolean applyFlag = record.canBubble() && !record.isFlagBubbleRemoved(); if (applyFlag) { record.getNotification().flags |= FLAG_BUBBLE; } else { diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java index 86e8734177f0..86d2e63975db 100755 --- a/services/core/java/com/android/server/notification/NotificationManagerService.java +++ b/services/core/java/com/android/server/notification/NotificationManagerService.java @@ -292,6 +292,7 @@ import java.io.PrintWriter; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.Arrays; +import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.List; @@ -530,6 +531,7 @@ public class NotificationManagerService extends SystemService { private final SavePolicyFileRunnable mSavePolicyFile = new SavePolicyFileRunnable(); private NotificationRecordLogger mNotificationRecordLogger; private InstanceIdSequence mNotificationInstanceIdSequence; + private Set<String> mMsgPkgsAllowedAsConvos = new HashSet(); static class Archive { final SparseArray<Boolean> mEnabled; @@ -2042,6 +2044,9 @@ public class NotificationManagerService extends SystemService { mStripRemoteViewsSizeBytes = getContext().getResources().getInteger( com.android.internal.R.integer.config_notificationStripRemoteViewSizeBytes); + mMsgPkgsAllowedAsConvos = Set.of( + getContext().getResources().getStringArray( + com.android.internal.R.array.config_notificationMsgPkgsAllowedAsConvos)); mStatsManager = statsManager; } @@ -5683,6 +5688,7 @@ public class NotificationManagerService extends SystemService { r.setIsAppImportanceLocked(mPreferencesHelper.getIsAppImportanceLocked(pkg, callingUid)); r.setPostSilently(postSilently); r.setFlagBubbleRemoved(false); + r.setPkgAllowedAsConvo(mMsgPkgsAllowedAsConvos.contains(pkg)); if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0) { final boolean fgServiceShown = channel.isFgServiceShown(); diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java index c10782242faa..bae02ac75f0a 100644 --- a/services/core/java/com/android/server/notification/NotificationRecord.java +++ b/services/core/java/com/android/server/notification/NotificationRecord.java @@ -190,6 +190,7 @@ public final class NotificationRecord { private boolean mPostSilently; private boolean mHasSentValidMsg; private boolean mAppDemotedFromConvo; + private boolean mPkgAllowedAsConvo; /** * Whether this notification (and its channels) should be considered user locked. Used in * conjunction with user sentiment calculation. @@ -1387,21 +1388,33 @@ public final class NotificationRecord { mAppDemotedFromConvo = userDemoted; } + public void setPkgAllowedAsConvo(boolean allowedAsConvo) { + mPkgAllowedAsConvo = allowedAsConvo; + } + /** * Whether this notification is a conversation notification. */ public boolean isConversation() { Notification notification = getNotification(); - if (!Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { - // very common; don't bother logging + // user kicked it out of convo space + if (mChannel.isDemoted() || mAppDemotedFromConvo) { return false; } - if (mChannel.isDemoted()) { + // NAS kicked it out of notification space + if (mIsNotConversationOverride) { return false; } - if (mIsNotConversationOverride) { + if (!Notification.MessagingStyle.class.equals(notification.getNotificationStyle())) { + // some non-msgStyle notifs can temporarily appear in the conversation space if category + // is right + if (mPkgAllowedAsConvo && mTargetSdkVersion < Build.VERSION_CODES.R + && Notification.CATEGORY_MESSAGE.equals(getNotification().category)) { + return true; + } return false; } + if (mTargetSdkVersion >= Build.VERSION_CODES.R && Notification.MessagingStyle.class.equals(notification.getNotificationStyle()) && mShortcutInfo == null) { @@ -1410,9 +1423,6 @@ public final class NotificationRecord { if (mHasSentValidMsg && mShortcutInfo == null) { return false; } - if (mAppDemotedFromConvo) { - return false; - } return true; } diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java index 9d56d817440b..77b030f9ed0d 100644 --- a/services/core/java/com/android/server/notification/PreferencesHelper.java +++ b/services/core/java/com/android/server/notification/PreferencesHelper.java @@ -85,7 +85,8 @@ public class PreferencesHelper implements RankingConfig { private static final int XML_VERSION = 2; /** What version to check to do the upgrade for bubbles. */ private static final int XML_VERSION_BUBBLES_UPGRADE = 1; - private static final int UNKNOWN_UID = UserHandle.USER_NULL; + @VisibleForTesting + static final int UNKNOWN_UID = UserHandle.USER_NULL; private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":"; @VisibleForTesting @@ -224,7 +225,7 @@ public class PreferencesHelper implements RankingConfig { } boolean skipWarningLogged = false; boolean hasSAWPermission = false; - if (upgradeForBubbles) { + if (upgradeForBubbles && uid != UNKNOWN_UID) { hasSAWPermission = mAppOps.noteOpNoThrow( OP_SYSTEM_ALERT_WINDOW, uid, name, null, "check-notif-bubble") == AppOpsManager.MODE_ALLOWED; diff --git a/services/core/java/com/android/server/notification/ShortcutHelper.java b/services/core/java/com/android/server/notification/ShortcutHelper.java index e79d33fa5f7a..ee02e3fa8140 100644 --- a/services/core/java/com/android/server/notification/ShortcutHelper.java +++ b/services/core/java/com/android/server/notification/ShortcutHelper.java @@ -28,6 +28,7 @@ import android.content.pm.ShortcutServiceInternal; import android.os.Binder; import android.os.Handler; import android.os.UserHandle; +import android.text.TextUtils; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; @@ -111,6 +112,15 @@ public class ShortcutHelper { } if (!foundShortcut) { bubbleKeysToRemove.add(shortcutBubbles.get(shortcutId)); + shortcutBubbles.remove(shortcutId); + if (shortcutBubbles.isEmpty()) { + mActiveShortcutBubbles.remove(packageName); + if (mLauncherAppsCallbackRegistered + && mActiveShortcutBubbles.isEmpty()) { + mLauncherAppsService.unregisterCallback(mLauncherAppsCallback); + mLauncherAppsCallbackRegistered = false; + } + } } } } @@ -198,7 +208,7 @@ public class ShortcutHelper { if (shortcutInfo.isLongLived() && !shortcutInfo.isCached()) { mShortcutServiceInternal.cacheShortcuts(user.getIdentifier(), "android", shortcutInfo.getPackage(), Collections.singletonList(shortcutInfo.getId()), - shortcutInfo.getUserId()); + shortcutInfo.getUserId(), ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); } } @@ -209,15 +219,16 @@ public class ShortcutHelper { * @param removedNotification true if this notification is being removed * @param handler handler to register the callback with */ - void maybeListenForShortcutChangesForBubbles(NotificationRecord r, boolean removedNotification, + void maybeListenForShortcutChangesForBubbles(NotificationRecord r, + boolean removedNotification, Handler handler) { final String shortcutId = r.getNotification().getBubbleMetadata() != null ? r.getNotification().getBubbleMetadata().getShortcutId() : null; - if (shortcutId == null) { - return; - } - if (r.getNotification().isBubbleNotification() && !removedNotification) { + if (!removedNotification + && !TextUtils.isEmpty(shortcutId) + && r.getShortcutInfo() != null + && r.getShortcutInfo().getId().equals(shortcutId)) { // Must track shortcut based bubbles in case the shortcut is removed HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get( r.getSbn().getPackageName()); @@ -235,10 +246,21 @@ public class ShortcutHelper { HashMap<String, String> packageBubbles = mActiveShortcutBubbles.get( r.getSbn().getPackageName()); if (packageBubbles != null) { - packageBubbles.remove(shortcutId); - } - if (packageBubbles != null && packageBubbles.isEmpty()) { - mActiveShortcutBubbles.remove(r.getSbn().getPackageName()); + if (!TextUtils.isEmpty(shortcutId)) { + packageBubbles.remove(shortcutId); + } else { + // Check if there was a matching entry + for (String pkgShortcutId : packageBubbles.keySet()) { + String entryKey = packageBubbles.get(pkgShortcutId); + if (r.getKey().equals(entryKey)) { + // No longer has shortcut id so remove it + packageBubbles.remove(pkgShortcutId); + } + } + } + if (packageBubbles.isEmpty()) { + mActiveShortcutBubbles.remove(r.getSbn().getPackageName()); + } } if (mLauncherAppsCallbackRegistered && mActiveShortcutBubbles.isEmpty()) { mLauncherAppsService.unregisterCallback(mLauncherAppsCallback); diff --git a/services/core/java/com/android/server/om/IdmapDaemon.java b/services/core/java/com/android/server/om/IdmapDaemon.java index 910ed44df0f8..19fa9204935d 100644 --- a/services/core/java/com/android/server/om/IdmapDaemon.java +++ b/services/core/java/com/android/server/om/IdmapDaemon.java @@ -30,6 +30,7 @@ import android.util.Slog; import com.android.server.FgThread; +import java.io.File; import java.util.concurrent.TimeoutException; import java.util.concurrent.atomic.AtomicInteger; @@ -124,9 +125,13 @@ class IdmapDaemon { } } - String getIdmapPath(String overlayPath, int userId) throws TimeoutException, RemoteException { + boolean idmapExists(String overlayPath, int userId) { try (Connection c = connect()) { - return mService.getIdmapPath(overlayPath, userId); + return new File(mService.getIdmapPath(overlayPath, userId)).isFile(); + } catch (Exception e) { + Slog.wtf(TAG, "failed to check if idmap exists for " + overlayPath + ": " + + e.getMessage()); + return false; } } diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 90c85ada9def..735d66983520 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -27,10 +27,10 @@ import android.content.pm.PackageInfo; import android.os.Build.VERSION_CODES; import android.os.OverlayablePolicy; import android.os.SystemProperties; -import android.os.UserHandle; import android.util.Slog; -import java.io.File; +import com.android.internal.util.ArrayUtils; + import java.io.IOException; /** @@ -55,12 +55,16 @@ class IdmapManager { VENDOR_IS_Q_OR_LATER = isQOrLater; } - private final OverlayableInfoCallback mOverlayableCallback; private final IdmapDaemon mIdmapDaemon; + private final OverlayableInfoCallback mOverlayableCallback; + private final String mOverlayableConfigurator; + private final String[] mOverlayableConfiguratorTargets; - IdmapManager(final OverlayableInfoCallback verifyCallback) { + IdmapManager(final IdmapDaemon idmapDaemon, final OverlayableInfoCallback verifyCallback) { mOverlayableCallback = verifyCallback; - mIdmapDaemon = IdmapDaemon.getInstance(); + mIdmapDaemon = idmapDaemon; + mOverlayableConfigurator = verifyCallback.getOverlayableConfigurator(); + mOverlayableConfiguratorTargets = verifyCallback.getOverlayableConfiguratorTargets() ; } /** @@ -103,23 +107,11 @@ class IdmapManager { } boolean idmapExists(@NonNull final OverlayInfo oi) { - return new File(getIdmapPath(oi.baseCodePath, oi.userId)).isFile(); + return mIdmapDaemon.idmapExists(oi.baseCodePath, oi.userId); } boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { - return new File(getIdmapPath(overlayPackage.applicationInfo.getBaseCodePath(), userId)) - .isFile(); - } - - private @NonNull String getIdmapPath(@NonNull final String overlayPackagePath, - final int userId) { - try { - return mIdmapDaemon.getIdmapPath(overlayPackagePath, userId); - } catch (Exception e) { - Slog.w(TAG, "failed to get idmap path for " + overlayPackagePath + ": " - + e.getMessage()); - return ""; - } + return mIdmapDaemon.idmapExists(overlayPackage.applicationInfo.getBaseCodePath(), userId); } /** @@ -198,9 +190,17 @@ class IdmapManager { String targetOverlayableName = overlayPackage.targetOverlayableName; if (targetOverlayableName != null) { try { + if (!mOverlayableConfigurator.isEmpty() + && ArrayUtils.contains(mOverlayableConfiguratorTargets, + targetPackage.packageName) + && mOverlayableCallback.signaturesMatching(mOverlayableConfigurator, + overlayPackage.packageName, userId)) { + return true; + } + OverlayableInfo overlayableInfo = mOverlayableCallback.getOverlayableForTarget( targetPackage.packageName, targetOverlayableName, userId); - if (overlayableInfo != null) { + if (overlayableInfo != null && overlayableInfo.actor != null) { String actorPackageName = OverlayActorEnforcer.getPackageNameForActor( overlayableInfo.actor, mOverlayableCallback.getNamedActors()).first; if (mOverlayableCallback.signaturesMatching(actorPackageName, diff --git a/services/core/java/com/android/server/om/OverlayActorEnforcer.java b/services/core/java/com/android/server/om/OverlayActorEnforcer.java index ef6655dd224e..2bc34998785b 100644 --- a/services/core/java/com/android/server/om/OverlayActorEnforcer.java +++ b/services/core/java/com/android/server/om/OverlayActorEnforcer.java @@ -50,8 +50,8 @@ public class OverlayActorEnforcer { /** * @return nullable actor result with {@link ActorState} failure status */ - static Pair<String, ActorState> getPackageNameForActor(String actorUriString, - Map<String, Map<String, String>> namedActors) { + static Pair<String, ActorState> getPackageNameForActor(@NonNull String actorUriString, + @NonNull Map<String, Map<String, String>> namedActors) { Uri actorUri = Uri.parse(actorUriString); String actorScheme = actorUri.getScheme(); diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java index 6a8e465529d7..086ab8183254 100644 --- a/services/core/java/com/android/server/om/OverlayManagerService.java +++ b/services/core/java/com/android/server/om/OverlayManagerService.java @@ -45,6 +45,7 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageManagerInternal; import android.content.pm.UserInfo; import android.content.res.ApkAssets; +import android.content.res.Resources; import android.net.Uri; import android.os.Binder; import android.os.Environment; @@ -62,6 +63,7 @@ import android.util.AtomicFile; import android.util.Slog; import android.util.SparseArray; +import com.android.internal.R; import com.android.internal.content.om.OverlayConfig; import com.android.server.FgThread; import com.android.server.IoThread; @@ -246,7 +248,7 @@ public final class OverlayManagerService extends SystemService { new File(Environment.getDataSystemDirectory(), "overlays.xml"), "overlays"); mPackageManager = new PackageManagerHelperImpl(context); mUserManager = UserManagerService.getInstance(); - IdmapManager im = new IdmapManager(mPackageManager); + IdmapManager im = new IdmapManager(IdmapDaemon.getInstance(), mPackageManager); mSettings = new OverlayManagerSettings(); mImpl = new OverlayManagerServiceImpl(mPackageManager, im, mSettings, OverlayConfig.getSystemInstance(), getDefaultOverlayPackages(), @@ -1119,6 +1121,17 @@ public final class OverlayManagerService extends SystemService { } @Override + public String getOverlayableConfigurator() { + return Resources.getSystem().getString(R.string.config_overlayableConfigurator); + } + + @Override + public String[] getOverlayableConfiguratorTargets() { + return Resources.getSystem().getStringArray( + R.array.config_overlayableConfiguratorTargets); + } + + @Override public List<PackageInfo> getOverlayPackages(final int userId) { final List<PackageInfo> overlays = mPackageManagerInternal.getOverlayPackages(userId); for (final PackageInfo info : overlays) { diff --git a/services/core/java/com/android/server/om/OverlayableInfoCallback.java b/services/core/java/com/android/server/om/OverlayableInfoCallback.java index 5066ecdd6316..41c341adf1bc 100644 --- a/services/core/java/com/android/server/om/OverlayableInfoCallback.java +++ b/services/core/java/com/android/server/om/OverlayableInfoCallback.java @@ -80,4 +80,24 @@ public interface OverlayableInfoCallback { * in the system returns {@link PackageManager#SIGNATURE_MATCH} */ boolean signaturesMatching(@NonNull String pkgName1, @NonNull String pkgName2, int userId); + + /** + * Retrieves the package name that is recognized as an actor for the packages specified by + * {@link #getOverlayableConfiguratorTargets()}. + */ + @NonNull + default String getOverlayableConfigurator() { + return ""; + } + + /** + * Retrieves the target packages that recognize the {@link #getOverlayableConfigurator} as an + * actor for its overlayable declarations. Overlays targeting one of the specified targets that + * are signed with the same signature as the overlayable configurator will be granted the + * "actor" policy. + */ + @NonNull + default String[] getOverlayableConfiguratorTargets() { + return new String[0]; + } } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index c6d08c36631a..5bbe49088c02 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -18,6 +18,8 @@ package com.android.server.pm; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT; +import static android.content.pm.LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; +import static android.content.pm.LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; import android.annotation.NonNull; import android.annotation.Nullable; @@ -78,6 +80,7 @@ import com.android.internal.content.PackageMonitor; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.parsing.pkg.AndroidPackage; @@ -780,26 +783,28 @@ public class LauncherAppsService extends SystemService { @Override public void cacheShortcuts(String callingPackage, String packageName, List<String> ids, - UserHandle targetUser) { + UserHandle targetUser, int cacheFlags) { ensureStrictAccessShortcutsPermission(callingPackage); if (!canAccessProfile(targetUser.getIdentifier(), "Cannot cache shortcuts")) { return; } - mShortcutServiceInternal.cacheShortcuts(getCallingUserId(), - callingPackage, packageName, ids, targetUser.getIdentifier()); + mShortcutServiceInternal.cacheShortcuts( + getCallingUserId(), callingPackage, packageName, ids, + targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); } @Override public void uncacheShortcuts(String callingPackage, String packageName, List<String> ids, - UserHandle targetUser) { + UserHandle targetUser, int cacheFlags) { ensureStrictAccessShortcutsPermission(callingPackage); if (!canAccessProfile(targetUser.getIdentifier(), "Cannot uncache shortcuts")) { return; } - mShortcutServiceInternal.uncacheShortcuts(getCallingUserId(), - callingPackage, packageName, ids, targetUser.getIdentifier()); + mShortcutServiceInternal.uncacheShortcuts( + getCallingUserId(), callingPackage, packageName, ids, + targetUser.getIdentifier(), toShortcutsCacheFlags(cacheFlags)); } @Override @@ -1058,6 +1063,18 @@ public class LauncherAppsService extends SystemService { user.getIdentifier(), debugMsg, false); } + private int toShortcutsCacheFlags(int cacheFlags) { + int ret = 0; + if (cacheFlags == FLAG_CACHE_NOTIFICATION_SHORTCUTS) { + ret = ShortcutInfo.FLAG_CACHED_NOTIFICATIONS; + } else if (cacheFlags == FLAG_CACHE_BUBBLE_SHORTCUTS) { + ret = ShortcutInfo.FLAG_CACHED_BUBBLES; + } + Preconditions.checkArgumentPositive(ret, "Invalid cache owner"); + + return ret; + } + @VisibleForTesting void postToPackageMonitorHandler(Runnable r) { mCallbackHandler.post(r); @@ -1154,7 +1171,7 @@ public class LauncherAppsService extends SystemService { final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) - | (matchCached ? ShortcutInfo.FLAG_CACHED : 0); + | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); for (int i = 0; i < shortcuts.size(); i++) { final ShortcutInfo si = shortcuts.get(i); diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java index f8278de1531d..7ab05c4f762c 100644 --- a/services/core/java/com/android/server/pm/PackageInstallerSession.java +++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java @@ -105,8 +105,10 @@ import android.os.RemoteException; import android.os.RevocableFileDescriptor; import android.os.SystemProperties; import android.os.UserHandle; +import android.os.incremental.IStorageHealthListener; import android.os.incremental.IncrementalFileStorages; import android.os.incremental.IncrementalManager; +import android.os.incremental.StorageHealthCheckParams; import android.os.storage.StorageManager; import android.provider.Settings.Secure; import android.stats.devicepolicy.DevicePolicyEnums; @@ -231,6 +233,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { private static final String SYSTEM_DATA_LOADER_PACKAGE = "android"; + private static final int INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS = 2000; + private static final int INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS = 7000; + private static final int INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS = 60000; + // TODO: enforce INSTALL_ALLOW_TEST // TODO: enforce INSTALL_ALLOW_DOWNGRADE @@ -1568,7 +1574,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { dispatchSessionFinished(error, detailMessage, null); } - private void onDataLoaderUnrecoverable() { + private void onStorageUnhealthy() { if (TextUtils.isEmpty(mPackageName)) { // The package has not been installed. return; @@ -2745,7 +2751,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { final DataLoaderParams params = this.params.dataLoaderParams; final boolean manualStartAndDestroy = !isIncrementalInstallation(); - final IDataLoaderStatusListener listener = new IDataLoaderStatusListener.Stub() { + final IDataLoaderStatusListener statusListener = new IDataLoaderStatusListener.Stub() { @Override public void onStatusChanged(int dataLoaderId, int status) { switch (status) { @@ -2757,7 +2763,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { if (mDestroyed || mDataLoaderFinished) { switch (status) { case IDataLoaderStatusListener.DATA_LOADER_UNRECOVERABLE: - onDataLoaderUnrecoverable(); + onStorageUnhealthy(); return; } return; @@ -2840,9 +2846,49 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { }; if (!manualStartAndDestroy) { + final StorageHealthCheckParams healthCheckParams = new StorageHealthCheckParams(); + healthCheckParams.blockedTimeoutMs = INCREMENTAL_STORAGE_BLOCKED_TIMEOUT_MS; + healthCheckParams.unhealthyTimeoutMs = INCREMENTAL_STORAGE_UNHEALTHY_TIMEOUT_MS; + healthCheckParams.unhealthyMonitoringMs = INCREMENTAL_STORAGE_UNHEALTHY_MONITORING_MS; + + final boolean systemDataLoader = + params.getComponentName().getPackageName() == SYSTEM_DATA_LOADER_PACKAGE; + final IStorageHealthListener healthListener = new IStorageHealthListener.Stub() { + @Override + public void onHealthStatus(int storageId, int status) { + if (mDestroyed || mDataLoaderFinished) { + // App's installed. + switch (status) { + case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY: + onStorageUnhealthy(); + return; + } + return; + } + + switch (status) { + case IStorageHealthListener.HEALTH_STATUS_OK: + break; + case IStorageHealthListener.HEALTH_STATUS_READS_PENDING: + case IStorageHealthListener.HEALTH_STATUS_BLOCKED: + if (systemDataLoader) { + // It's OK for ADB data loader to wait for pages. + break; + } + // fallthrough + case IStorageHealthListener.HEALTH_STATUS_UNHEALTHY: + // Even ADB installation can't wait for missing pages for too long. + mDataLoaderFinished = true; + dispatchSessionVerificationFailure(INSTALL_FAILED_MEDIA_UNAVAILABLE, + "Image is missing pages required for installation."); + break; + } + } + }; + try { mIncrementalFileStorages = IncrementalFileStorages.initialize(mContext, stageDir, - params, listener, addedFiles); + params, statusListener, healthCheckParams, healthListener, addedFiles); return false; } catch (IOException e) { throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, e.getMessage(), @@ -2850,8 +2896,7 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub { } } - if (!dataLoaderManager.bindToDataLoader( - sessionId, params.getData(), listener)) { + if (!dataLoaderManager.bindToDataLoader(sessionId, params.getData(), statusListener)) { throw new PackageManagerException(INSTALL_FAILED_MEDIA_UNAVAILABLE, "Failed to initialize data loader"); } diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index fbe810025edb..aa7a1ad2b47a 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -369,6 +369,7 @@ import com.android.server.pm.permission.PermissionsState; import com.android.server.policy.PermissionPolicyInternal; import com.android.server.security.VerityUtils; import com.android.server.storage.DeviceStorageMonitorInternal; +import com.android.server.uri.UriGrantsManagerInternal; import com.android.server.utils.TimingsTraceAndSlog; import com.android.server.wm.ActivityTaskManagerInternal; @@ -4406,6 +4407,11 @@ public class PackageManagerService extends IPackageManager.Stub if (getInstantAppPackageName(callingUid) != null) { throw new SecurityException("Instant applications don't have access to this method"); } + if (!mUserManager.exists(userId)) { + throw new SecurityException("User doesn't exist"); + } + mPermissionManager.enforceCrossUserPermission( + callingUid, userId, false, false, "checkPackageStartable"); final boolean userKeyUnlocked = StorageManager.isUserKeyUnlocked(userId); synchronized (mLock) { final PackageSetting ps = mSettings.mPackages.get(packageName); @@ -5778,9 +5784,15 @@ public class PackageManagerService extends IPackageManager.Stub @Override public ChangedPackages getChangedPackages(int sequenceNumber, int userId) { - if (getInstantAppPackageName(Binder.getCallingUid()) != null) { + final int callingUid = Binder.getCallingUid(); + if (getInstantAppPackageName(callingUid) != null) { + return null; + } + if (!mUserManager.exists(userId)) { return null; } + mPermissionManager.enforceCrossUserPermission( + callingUid, userId, false, false, "getChangedPackages"); synchronized (mLock) { if (sequenceNumber >= mChangedPackagesSequenceNumber) { return null; @@ -8800,9 +8812,23 @@ public class PackageManagerService extends IPackageManager.Stub private ProviderInfo resolveContentProviderInternal(String name, int flags, int userId) { if (!mUserManager.exists(userId)) return null; - flags = updateFlagsForComponent(flags, userId); final int callingUid = Binder.getCallingUid(); + flags = updateFlagsForComponent(flags, userId); final ProviderInfo providerInfo = mComponentResolver.queryProvider(name, flags, userId); + boolean checkedGrants = false; + if (providerInfo != null) { + // Looking for cross-user grants before enforcing the typical cross-users permissions + if (userId != UserHandle.getUserId(callingUid)) { + final UriGrantsManagerInternal mUgmInternal = + LocalServices.getService(UriGrantsManagerInternal.class); + checkedGrants = + mUgmInternal.checkAuthorityGrants(callingUid, providerInfo, userId, true); + } + } + if (!checkedGrants) { + mPermissionManager.enforceCrossUserPermission( + callingUid, userId, false, false, "resolveContentProvider"); + } if (providerInfo == null) { return null; } diff --git a/services/core/java/com/android/server/pm/ShortcutPackage.java b/services/core/java/com/android/server/pm/ShortcutPackage.java index 16426072ae78..9e27f65105eb 100644 --- a/services/core/java/com/android/server/pm/ShortcutPackage.java +++ b/services/core/java/com/android/server/pm/ShortcutPackage.java @@ -287,7 +287,7 @@ class ShortcutPackage extends ShortcutPackageItem { if (shortcut != null) { mShortcutUser.mService.removeIconLocked(shortcut); shortcut.clearFlags(ShortcutInfo.FLAG_DYNAMIC | ShortcutInfo.FLAG_PINNED - | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED); + | ShortcutInfo.FLAG_MANIFEST | ShortcutInfo.FLAG_CACHED_ALL); } return shortcut; } @@ -323,36 +323,18 @@ class ShortcutPackage extends ShortcutPackageItem { newShortcut.addFlags(ShortcutInfo.FLAG_DYNAMIC); final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId()); - - final boolean replaced; - - final boolean wasPinned; - final boolean wasCached; - - if (oldShortcut == null) { - replaced = false; - wasPinned = false; - wasCached = false; - } else { + if (oldShortcut != null) { // It's an update case. // Make sure the target is updatable. (i.e. should be mutable.) oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); - replaced = true; - - wasPinned = oldShortcut.isPinned(); - wasCached = oldShortcut.isCached(); - } - // If it was originally pinned, the new one should be pinned too. - if (wasPinned) { - newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); - } - if (wasCached) { - newShortcut.addFlags(ShortcutInfo.FLAG_CACHED); + // If it was originally pinned or cached, the new one should be pinned or cached too. + newShortcut.addFlags(oldShortcut.getFlags() + & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL)); } forceReplaceShortcutInner(newShortcut); - return replaced; + return oldShortcut != null; } /** @@ -373,9 +355,6 @@ class ShortcutPackage extends ShortcutPackageItem { changedShortcuts.clear(); final ShortcutInfo oldShortcut = mShortcuts.get(newShortcut.getId()); - boolean wasPinned = false; - boolean wasCached = false; - boolean deleted = false; if (oldShortcut == null) { @@ -408,16 +387,9 @@ class ShortcutPackage extends ShortcutPackageItem { // Make sure the target is updatable. (i.e. should be mutable.) oldShortcut.ensureUpdatableWith(newShortcut, /*isUpdating=*/ false); - wasPinned = oldShortcut.isPinned(); - wasCached = oldShortcut.isCached(); - } - - // If it was originally pinned or cached, the new one should be pinned or cached too. - if (wasPinned) { - newShortcut.addFlags(ShortcutInfo.FLAG_PINNED); - } - if (wasCached) { - newShortcut.addFlags(ShortcutInfo.FLAG_CACHED); + // If it was originally pinned or cached, the new one should be pinned or cached too. + newShortcut.addFlags(oldShortcut.getFlags() + & (ShortcutInfo.FLAG_PINNED | ShortcutInfo.FLAG_CACHED_ALL)); } forceReplaceShortcutInner(newShortcut); @@ -511,7 +483,7 @@ class ShortcutPackage extends ShortcutPackageItem { public ShortcutInfo deleteLongLivedWithId(@NonNull String shortcutId, boolean ignoreInvisible) { final ShortcutInfo shortcut = mShortcuts.get(shortcutId); if (shortcut != null) { - shortcut.clearFlags(ShortcutInfo.FLAG_CACHED); + shortcut.clearFlags(ShortcutInfo.FLAG_CACHED_ALL); } return deleteOrDisableWithId( shortcutId, /* disable =*/ false, /* overrideImmutable=*/ false, ignoreInvisible, diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index 3732b479c3a3..3ec139763e80 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -2407,7 +2407,7 @@ public class ShortcutService extends IShortcutService.Stub { final int shortcutFlags = (matchDynamic ? ShortcutInfo.FLAG_DYNAMIC : 0) | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) - | (matchCached ? ShortcutInfo.FLAG_CACHED : 0); + | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, @@ -3045,17 +3045,17 @@ public class ShortcutService extends IShortcutService.Stub { @Override public void cacheShortcuts(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, - @NonNull List<String> shortcutIds, int userId) { + @NonNull List<String> shortcutIds, int userId, int cacheFlags) { updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds, - userId, /* doCache= */ true); + userId, cacheFlags, /* doCache= */ true); } @Override public void uncacheShortcuts(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, - @NonNull List<String> shortcutIds, int userId) { + @NonNull List<String> shortcutIds, int userId, int cacheFlags) { updateCachedShortcutsInternal(launcherUserId, callingPackage, packageName, shortcutIds, - userId, /* doCache= */ false); + userId, cacheFlags, /* doCache= */ false); } @Override @@ -3079,10 +3079,12 @@ public class ShortcutService extends IShortcutService.Stub { private void updateCachedShortcutsInternal(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, - @NonNull List<String> shortcutIds, int userId, boolean doCache) { + @NonNull List<String> shortcutIds, int userId, int cacheFlags, boolean doCache) { // Calling permission must be checked by LauncherAppsImpl. Preconditions.checkStringNotEmpty(packageName, "packageName"); Objects.requireNonNull(shortcutIds, "shortcutIds"); + Preconditions.checkState( + (cacheFlags & ShortcutInfo.FLAG_CACHED_ALL) != 0, "invalid cacheFlags"); List<ShortcutInfo> changedShortcuts = null; List<ShortcutInfo> removedShortcuts = null; @@ -3101,13 +3103,13 @@ public class ShortcutService extends IShortcutService.Stub { for (int i = 0; i < idSize; i++) { final String id = Preconditions.checkStringNotEmpty(shortcutIds.get(i)); final ShortcutInfo si = sp.findShortcutById(id); - if (si == null || doCache == si.isCached()) { + if (si == null || doCache == si.hasFlags(cacheFlags)) { continue; } if (doCache) { if (si.isLongLived()) { - si.addFlags(ShortcutInfo.FLAG_CACHED); + si.addFlags(cacheFlags); if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); } @@ -3118,9 +3120,8 @@ public class ShortcutService extends IShortcutService.Stub { } } else { ShortcutInfo removed = null; - if (si.isDynamic()) { - si.clearFlags(ShortcutInfo.FLAG_CACHED); - } else { + si.clearFlags(cacheFlags); + if (!si.isDynamic() && !si.isCached()) { removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true); } if (removed != null) { diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java index 29428a27e6da..b0e3ecb6d17b 100644 --- a/services/core/java/com/android/server/pm/UserManagerService.java +++ b/services/core/java/com/android/server/pm/UserManagerService.java @@ -3507,7 +3507,7 @@ public class UserManagerService extends IUserManager.Stub { Slog.w(LOG_TAG, "could not start pre-created user " + userId, e); } } else { - dispatchUserAddedIntent(userInfo); + dispatchUserAdded(userInfo); } } finally { @@ -3568,7 +3568,7 @@ public class UserManagerService extends IUserManager.Stub { // Could not read the existing permissions, re-grant them. mPm.onNewUserCreated(preCreatedUser.id); } - dispatchUserAddedIntent(preCreatedUser); + dispatchUserAdded(preCreatedUser); return preCreatedUser; } @@ -3600,7 +3600,7 @@ public class UserManagerService extends IUserManager.Stub { return (now > EPOCH_PLUS_30_YEARS) ? now : 0; } - private void dispatchUserAddedIntent(@NonNull UserInfo userInfo) { + private void dispatchUserAdded(@NonNull UserInfo userInfo) { Intent addedIntent = new Intent(Intent.ACTION_USER_ADDED); addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userInfo.id); // Also, add the UserHandle for mainline modules which can't use the @hide @@ -3610,6 +3610,15 @@ public class UserManagerService extends IUserManager.Stub { android.Manifest.permission.MANAGE_USERS); MetricsLogger.count(mContext, userInfo.isGuest() ? TRON_GUEST_CREATED : (userInfo.isDemo() ? TRON_DEMO_CREATED : TRON_USER_CREATED), 1); + + if (!userInfo.isProfile()) { + // If the user switch hasn't been explicitly toggled on or off by the user, turn it on. + if (android.provider.Settings.Global.getString(mContext.getContentResolver(), + android.provider.Settings.Global.USER_SWITCHER_ENABLED) == null) { + android.provider.Settings.Global.putInt(mContext.getContentResolver(), + android.provider.Settings.Global.USER_SWITCHER_ENABLED, 1); + } + } } /** diff --git a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java index 1fec8aa0a3ff..14d043c371e2 100644 --- a/services/core/java/com/android/server/pm/UserRestrictionsUtils.java +++ b/services/core/java/com/android/server/pm/UserRestrictionsUtils.java @@ -206,21 +206,9 @@ public class UserRestrictionsUtils { */ private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS = Sets.newArraySet( - UserManager.DISALLOW_CONFIG_DATE_TIME, - UserManager.DISALLOW_CAMERA, - UserManager.DISALLOW_BLUETOOTH, - UserManager.DISALLOW_BLUETOOTH_SHARING, - UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, - UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, - UserManager.DISALLOW_CONFIG_PRIVATE_DNS, - UserManager.DISALLOW_CONFIG_TETHERING, - UserManager.DISALLOW_DATA_ROAMING, - UserManager.DISALLOW_SAFE_BOOT, - UserManager.DISALLOW_SMS, - UserManager.DISALLOW_USB_FILE_TRANSFER, UserManager.DISALLOW_AIRPLANE_MODE, - UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, - UserManager.DISALLOW_UNMUTE_MICROPHONE + UserManager.DISALLOW_CONFIG_DATE_TIME, + UserManager.DISALLOW_CONFIG_PRIVATE_DNS ); /** @@ -236,7 +224,19 @@ public class UserRestrictionsUtils { UserManager.DISALLOW_CONTENT_SUGGESTIONS, UserManager.DISALLOW_DEBUGGING_FEATURES, UserManager.DISALLOW_SHARE_LOCATION, - UserManager.DISALLOW_OUTGOING_CALLS + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_CAMERA, + UserManager.DISALLOW_BLUETOOTH, + UserManager.DISALLOW_BLUETOOTH_SHARING, + UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, + UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, + UserManager.DISALLOW_CONFIG_TETHERING, + UserManager.DISALLOW_DATA_ROAMING, + UserManager.DISALLOW_SAFE_BOOT, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_USB_FILE_TRANSFER, + UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, + UserManager.DISALLOW_UNMUTE_MICROPHONE ); /** 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 29c1243c299d..0b3254f53324 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -179,6 +179,7 @@ import java.util.concurrent.Executor; import java.util.concurrent.ThreadLocalRandom; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; +import java.util.function.BiConsumer; /** * SystemService containing PullAtomCallbacks that are registered with statsd. @@ -325,6 +326,7 @@ public class StatsPullAtomService extends SystemService { case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: + case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: return pullDataBytesTransfer(atomTag, data); case FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER: return pullBluetoothBytesTransfer(atomTag, data); @@ -641,11 +643,14 @@ public class StatsPullAtomService extends SystemService { collectNetworkStatsSnapshotForAtom(FrameworkStatsLog.MOBILE_BYTES_TRANSFER)); mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG)); + mNetworkStatsBaselines.addAll(collectNetworkStatsSnapshotForAtom( + FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED)); registerWifiBytesTransfer(); registerWifiBytesTransferBackground(); registerMobileBytesTransfer(); registerMobileBytesTransferBackground(); + registerBytesTransferByTagAndMetered(); } /** @@ -787,50 +792,94 @@ public class StatsPullAtomService extends SystemService { private static class NetworkStatsExt { @NonNull public final NetworkStats stats; - public final int transport; - public final boolean withFgbg; + public final int[] transports; + public final boolean slicedByFgbg; + public final boolean slicedByTag; + public final boolean slicedByMetered; + + NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg) { + this(stats, transports, slicedByFgbg, /*slicedByTag=*/false, /*slicedByMetered=*/false); + } - NetworkStatsExt(@NonNull NetworkStats stats, int transport, boolean withFgbg) { + NetworkStatsExt(@NonNull NetworkStats stats, int[] transports, boolean slicedByFgbg, + boolean slicedByTag, boolean slicedByMetered) { this.stats = stats; - this.transport = transport; - this.withFgbg = withFgbg; + + // Sort transports array so that we can test for equality without considering order. + this.transports = Arrays.copyOf(transports, transports.length); + Arrays.sort(this.transports); + + this.slicedByFgbg = slicedByFgbg; + this.slicedByTag = slicedByTag; + this.slicedByMetered = slicedByMetered; + } + + public boolean hasSameSlicing(@NonNull NetworkStatsExt other) { + return Arrays.equals(transports, other.transports) && slicedByFgbg == other.slicedByFgbg + && slicedByTag == other.slicedByTag && slicedByMetered == other.slicedByMetered; } } @NonNull private List<NetworkStatsExt> collectNetworkStatsSnapshotForAtom(int atomTag) { + List<NetworkStatsExt> ret = new ArrayList<>(); switch(atomTag) { - case FrameworkStatsLog.WIFI_BYTES_TRANSFER: - return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/false); - case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: - return collectUidNetworkStatsSnapshot(TRANSPORT_WIFI, /*withFgbg=*/true); - case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: - return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/false); - case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: - return collectUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, /*withFgbg=*/true); + case FrameworkStatsLog.WIFI_BYTES_TRANSFER: { + final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI, + /*includeTags=*/false); + if (stats != null) { + ret.add(new NetworkStatsExt(stats.groupedByUid(), new int[] {TRANSPORT_WIFI}, + /*slicedByFgbg=*/false)); + } + break; + } + case FrameworkStatsLog.WIFI_BYTES_TRANSFER_BY_FG_BG: { + final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI, + /*includeTags=*/false); + if (stats != null) { + ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats), + new int[] {TRANSPORT_WIFI}, /*slicedByFgbg=*/true)); + } + break; + } + case FrameworkStatsLog.MOBILE_BYTES_TRANSFER: { + final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, + /*includeTags=*/false); + if (stats != null) { + ret.add(new NetworkStatsExt(stats.groupedByUid(), + new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/false)); + } + break; + } + case FrameworkStatsLog.MOBILE_BYTES_TRANSFER_BY_FG_BG: { + final NetworkStats stats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, + /*includeTags=*/false); + if (stats != null) { + ret.add(new NetworkStatsExt(sliceNetworkStatsByUidAndFgbg(stats), + new int[] {TRANSPORT_CELLULAR}, /*slicedByFgbg=*/true)); + } + break; + } + case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: { + final NetworkStats wifiStats = getUidNetworkStatsSnapshot(TRANSPORT_WIFI, + /*includeTags=*/true); + final NetworkStats cellularStats = getUidNetworkStatsSnapshot(TRANSPORT_CELLULAR, + /*includeTags=*/true); + if (wifiStats != null && cellularStats != null) { + final NetworkStats stats = wifiStats.add(cellularStats); + ret.add(new NetworkStatsExt(sliceNetworkStatsByUidTagAndMetered(stats), + new int[] {TRANSPORT_WIFI, TRANSPORT_CELLULAR}, + /*slicedByFgbg=*/false, /*slicedByTag=*/true, + /*slicedByMetered=*/true)); + } + break; + } default: throw new IllegalArgumentException("Unknown atomTag " + atomTag); } - } - - // Get a snapshot of Uid NetworkStats. The snapshot contains NetworkStats with its associated - // information, and wrapped by a list since multiple NetworkStatsExt objects might be collected. - @NonNull - private List<NetworkStatsExt> collectUidNetworkStatsSnapshot(int transport, boolean withFgbg) { - final List<NetworkStatsExt> ret = new ArrayList<>(); - final NetworkTemplate template = (transport == TRANSPORT_CELLULAR - ? NetworkTemplate.buildTemplateMobileWithRatType( - /*subscriptionId=*/null, NETWORK_TYPE_ALL) - : NetworkTemplate.buildTemplateWifiWildcard()); - - final NetworkStats stats = getUidNetworkStatsSnapshot(template, withFgbg); - if (stats != null) { - ret.add(new NetworkStatsExt(stats, transport, withFgbg)); - } return ret; } - private int pullDataBytesTransfer( int atomTag, @NonNull List<StatsEvent> pulledData) { final List<NetworkStatsExt> current = collectNetworkStatsSnapshotForAtom(atomTag); @@ -842,22 +891,28 @@ public class StatsPullAtomService extends SystemService { for (final NetworkStatsExt item : current) { final NetworkStatsExt baseline = CollectionUtils.find(mNetworkStatsBaselines, - it -> it.withFgbg == item.withFgbg && it.transport == item.transport); + it -> it.hasSameSlicing(item)); // No matched baseline indicates error has occurred during initialization stage, // skip reporting anything since the snapshot is invalid. if (baseline == null) { - Slog.e(TAG, "baseline is null for " + atomTag + ", transport=" - + item.transport + " , withFgbg=" + item.withFgbg + ", return."); + Slog.e(TAG, "baseline is null for " + atomTag + ", return."); return StatsManager.PULL_SKIP; } - final NetworkStatsExt diff = new NetworkStatsExt(item.stats.subtract( - baseline.stats).removeEmptyEntries(), item.transport, item.withFgbg); + final NetworkStatsExt diff = new NetworkStatsExt( + item.stats.subtract(baseline.stats).removeEmptyEntries(), item.transports, + item.slicedByFgbg, item.slicedByTag, item.slicedByMetered); // If no diff, skip. if (diff.stats.size() == 0) continue; - addNetworkStats(atomTag, pulledData, diff); + switch (atomTag) { + case FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED: + addBytesTransferByTagAndMeteredAtoms(diff, pulledData); + break; + default: + addNetworkStats(atomTag, pulledData, diff); + } } return StatsManager.PULL_SUCCESS; } @@ -879,7 +934,7 @@ public class StatsPullAtomService extends SystemService { } e.writeInt(entry.uid); e.addBooleanAnnotation(ANNOTATION_ID_IS_UID, true); - if (statsExt.withFgbg) { + if (statsExt.slicedByFgbg) { e.writeInt(entry.set); } e.writeLong(entry.rxBytes); @@ -890,14 +945,38 @@ public class StatsPullAtomService extends SystemService { } } + private void addBytesTransferByTagAndMeteredAtoms(@NonNull NetworkStatsExt statsExt, + @NonNull List<StatsEvent> pulledData) { + final NetworkStats.Entry entry = new NetworkStats.Entry(); // for recycling + for (int i = 0; i < statsExt.stats.size(); i++) { + statsExt.stats.getValues(i, entry); + StatsEvent e = StatsEvent.newBuilder() + .setAtomId(FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED) + .addBooleanAnnotation(ANNOTATION_ID_TRUNCATE_TIMESTAMP, true) + .writeInt(entry.uid) + .addBooleanAnnotation(ANNOTATION_ID_IS_UID, true) + .writeBoolean(entry.metered == NetworkStats.METERED_YES) + .writeInt(entry.tag) + .writeLong(entry.rxBytes) + .writeLong(entry.rxPackets) + .writeLong(entry.txBytes) + .writeLong(entry.txPackets) + .build(); + pulledData.add(e); + } + } + /** * Create a snapshot of NetworkStats since boot, but add 1 bucket duration before boot as a * buffer to ensure at least one full bucket will be included. * Note that this should be only used to calculate diff since the snapshot might contains * some traffic before boot. */ - @Nullable private NetworkStats getUidNetworkStatsSnapshot( - @NonNull NetworkTemplate template, boolean withFgbg) { + @Nullable private NetworkStats getUidNetworkStatsSnapshot(int transport, boolean includeTags) { + final NetworkTemplate template = (transport == TRANSPORT_CELLULAR) + ? NetworkTemplate.buildTemplateMobileWithRatType( + /*subscriptionId=*/null, NETWORK_TYPE_ALL) + : NetworkTemplate.buildTemplateWifiWildcard(); final long elapsedMillisSinceBoot = SystemClock.elapsedRealtime(); final long currentTimeInMillis = MICROSECONDS.toMillis(SystemClock.currentTimeMicro()); @@ -906,38 +985,72 @@ public class StatsPullAtomService extends SystemService { try { final NetworkStats stats = getNetworkStatsSession().getSummaryForAllUid(template, currentTimeInMillis - elapsedMillisSinceBoot - bucketDuration, - currentTimeInMillis, /*includeTags=*/false); - return withFgbg ? rollupNetworkStatsByFgbg(stats) : stats.groupedByUid(); + currentTimeInMillis, includeTags); + return stats; } catch (RemoteException | NullPointerException e) { - Slog.e(TAG, "Pulling netstats for " + template - + " fgbg= " + withFgbg + " bytes has error", e); + Slog.e(TAG, "Pulling netstats for template=" + template + " and includeTags=" + + includeTags + " causes error", e); } return null; } + @NonNull private NetworkStats sliceNetworkStatsByUidAndFgbg(@NonNull NetworkStats stats) { + return sliceNetworkStats(stats, + (newEntry, oldEntry) -> { + newEntry.uid = oldEntry.uid; + newEntry.set = oldEntry.set; + }); + } + + @NonNull private NetworkStats sliceNetworkStatsByUidTagAndMetered(@NonNull NetworkStats stats) { + return sliceNetworkStats(stats, + (newEntry, oldEntry) -> { + newEntry.uid = oldEntry.uid; + newEntry.tag = oldEntry.tag; + newEntry.metered = oldEntry.metered; + }); + } + /** - * Allows rollups per UID but keeping the set (foreground/background) slicing. - * Adapted from groupedByUid in frameworks/base/core/java/android/net/NetworkStats.java + * Slices NetworkStats along the dimensions specified in the slicer lambda and aggregates over + * non-sliced dimensions. + * + * This function iterates through each NetworkStats.Entry, sets its dimensions equal to the + * default state (with the presumption that we don't want to slice on anything), and then + * applies the slicer lambda to allow users to control which dimensions to slice on. This is + * adapted from groupedByUid within NetworkStats.java + * + * @param slicer An operation taking into two parameters, new NetworkStats.Entry and old + * NetworkStats.Entry, that should be used to copy state from the old to the new. + * This is useful for slicing by particular dimensions. For example, if we wished + * to slice by uid and tag, we could write the following lambda: + * (new, old) -> { + * new.uid = old.uid; + * new.tag = old.tag; + * } + * If no slicer is provided, the data is not sliced by any dimensions. + * @return new NeworkStats object appropriately sliced */ - @NonNull private NetworkStats rollupNetworkStatsByFgbg(@NonNull NetworkStats stats) { + @NonNull private NetworkStats sliceNetworkStats(@NonNull NetworkStats stats, + @Nullable BiConsumer<NetworkStats.Entry, NetworkStats.Entry> slicer) { final NetworkStats ret = new NetworkStats(stats.getElapsedRealtime(), 1); final NetworkStats.Entry entry = new NetworkStats.Entry(); + entry.uid = NetworkStats.UID_ALL; entry.iface = NetworkStats.IFACE_ALL; + entry.set = NetworkStats.SET_ALL; entry.tag = NetworkStats.TAG_NONE; entry.metered = NetworkStats.METERED_ALL; entry.roaming = NetworkStats.ROAMING_ALL; + entry.defaultNetwork = NetworkStats.DEFAULT_NETWORK_ALL; - int size = stats.size(); - final NetworkStats.Entry recycle = new NetworkStats.Entry(); // Used for retrieving values - for (int i = 0; i < size; i++) { + final NetworkStats.Entry recycle = new NetworkStats.Entry(); // used for retrieving values + for (int i = 0; i < stats.size(); i++) { stats.getValues(i, recycle); + if (slicer != null) { + slicer.accept(entry, recycle); + } - // Skip specific tags, since already counted in TAG_NONE - if (recycle.tag != NetworkStats.TAG_NONE) continue; - - entry.set = recycle.set; // Allows slicing by background/foreground - entry.uid = recycle.uid; entry.rxBytes = recycle.rxBytes; entry.rxPackets = recycle.rxPackets; entry.txBytes = recycle.txBytes; @@ -987,6 +1100,19 @@ public class StatsPullAtomService extends SystemService { ); } + private void registerBytesTransferByTagAndMetered() { + int tagId = FrameworkStatsLog.BYTES_TRANSFER_BY_TAG_AND_METERED; + PullAtomMetadata metadata = new PullAtomMetadata.Builder() + .setAdditiveFields(new int[] {4, 5, 6, 7}) + .build(); + mStatsManager.setPullAtomCallback( + tagId, + metadata, + BackgroundThread.getExecutor(), + mStatsCallbackImpl + ); + } + private void registerBluetoothBytesTransfer() { int tagId = FrameworkStatsLog.BLUETOOTH_BYTES_TRANSFER; PullAtomMetadata metadata = new PullAtomMetadata.Builder() diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java index e3b1152cd7b7..323ac7b8806e 100755 --- a/services/core/java/com/android/server/tv/TvInputManagerService.java +++ b/services/core/java/com/android/server/tv/TvInputManagerService.java @@ -16,6 +16,7 @@ package com.android.server.tv; +import static android.media.AudioManager.DEVICE_NONE; import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED; import static android.media.tv.TvInputManager.INPUT_STATE_CONNECTED_STANDBY; @@ -2047,6 +2048,36 @@ public final class TvInputManagerService extends SystemService { return clientPid; } + /** + * Add a hardware device in the TvInputHardwareManager for CTS testing + * purpose. + * + * @param device id of the adding hardware device. + */ + @Override + public void addHardwareDevice(int deviceId) { + TvInputHardwareInfo info = new TvInputHardwareInfo.Builder() + .deviceId(deviceId) + .type(TvInputHardwareInfo.TV_INPUT_TYPE_HDMI) + .audioType(DEVICE_NONE) + .audioAddress("0") + .hdmiPortId(0) + .build(); + mTvInputHardwareManager.onDeviceAvailable(info, null); + return; + } + + /** + * Remove a hardware device in the TvInputHardwareManager for CTS testing + * purpose. + * + * @param device id of the removing hardware device. + */ + @Override + public void removeHardwareDevice(int deviceId) { + mTvInputHardwareManager.onDeviceUnavailable(deviceId); + } + private int getClientPidLocked(String sessionId) throws IllegalStateException { if (mSessionIdToSessionStateMap.get(sessionId) == null) { diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java index 5a6e0a1ff9c3..982785e6339e 100644 --- a/services/core/java/com/android/server/wm/ActivityRecord.java +++ b/services/core/java/com/android/server/wm/ActivityRecord.java @@ -3366,8 +3366,6 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A ProtoLog.v(WM_DEBUG_ADD_REMOVE, "Removing starting %s from %s", tStartingWindow, fromActivity); fromActivity.removeChild(tStartingWindow); - fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); - fromActivity.mVisibleSetFromTransferredStartingWindow = false; addWindow(tStartingWindow); // Propagate other interesting state between the tokens. If the old token is displayed, @@ -3394,6 +3392,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A // we've transferred the animation. mUseTransferredAnimation = true; } + // Post cleanup after the visibility and animation are transferred. + fromActivity.postWindowRemoveStartingWindowCleanup(tStartingWindow); + fromActivity.mVisibleSetFromTransferredStartingWindow = false; mWmService.updateFocusedWindowLocked( UPDATE_FOCUS_WILL_PLACE_SURFACES, true /*updateInputWindows*/); diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 9b9b61340332..361df1444e87 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -943,19 +943,7 @@ class ActivityStack extends Task { // task's ordering. However, we still need to move 'task' to back. The intention is that // this ends up behind the home-task so that it is made invisible; so, if the home task // is not a child of this, reparent 'task' to the back of the home task's actual parent. - final ActivityStack home = displayArea.getOrCreateRootHomeTask(); - final WindowContainer homeParent = home.getParent(); - final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; - if (homeParentTask == null) { - ((ActivityStack) task).reparent(displayArea, false /* onTop */); - } else if (homeParentTask == this) { - // Apparently reparent early-outs if same stack, so we have to explicitly reorder. - positionChildAtBottom(task); - } else { - task.reparent((ActivityStack) homeParentTask, false /* toTop */, - REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, false /* deferResume */, - "moveToBack"); - } + displayArea.positionTaskBehindHome((ActivityStack) task); } // TODO: Should each user have there own stacks? @@ -2140,7 +2128,7 @@ class ActivityStack extends Task { // window manager to keep the previous window it had previously // created, if it still had one. Task prevTask = r.getTask(); - ActivityRecord prev = prevTask.topRunningActivityWithStartingWindowLocked(); + ActivityRecord prev = prevTask.topActivityWithStartingWindow(); if (prev != null) { // We don't want to reuse the previous starting preview if: // (1) The current activity is in a different task. @@ -2638,6 +2626,9 @@ class ActivityStack extends Task { mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */, getDisplay().mDisplayId, false /* markFrozenIfConfigChanged */, false /* deferResume */); + // Usually resuming a top activity triggers the next app transition, but nothing's got + // resumed in this case, so we need to execute it explicitly. + getDisplay().mDisplayContent.executeAppTransition(); } else { mRootWindowContainer.resumeFocusedStacksTopActivities(); } diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 62979ffc4a8c..80ca95fe2ebd 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -72,6 +72,7 @@ import static com.android.server.wm.ActivityTaskManagerService.RELAUNCH_REASON_N import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS; import static com.android.server.wm.RootWindowContainer.MATCH_TASK_IN_STACKS_OR_RECENT_TASKS_AND_RESTORE; import static com.android.server.wm.RootWindowContainer.TAG_STATES; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION; import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_PINNED_TASK; import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE; import static com.android.server.wm.Task.LOCK_TASK_AUTH_LAUNCHABLE_PRIV; @@ -1441,11 +1442,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { try { stack.setWindowingMode(WINDOWING_MODE_UNDEFINED); stack.setBounds(null); - if (toDisplay.getDisplayId() != stack.getDisplayId()) { - stack.reparent(toDisplay.getDefaultTaskDisplayArea(), false /* onTop */); - } else { - toDisplay.getDefaultTaskDisplayArea().positionStackAtBottom(stack); - } + toDisplay.getDefaultTaskDisplayArea().positionTaskBehindHome(stack); // Follow on the workaround: activities are kept force hidden till the new windowing // mode is set. @@ -1807,15 +1804,11 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { ArrayList<ActivityRecord> readyToStopActivities = null; for (int i = mStoppingActivities.size() - 1; i >= 0; --i) { final ActivityRecord s = mStoppingActivities.get(i); - final boolean animating = s.isAnimating(TRANSITION | PARENTS); + final boolean animating = s.isAnimating(TRANSITION | PARENTS, + ANIMATION_TYPE_APP_TRANSITION); if (DEBUG_STATES) Slog.v(TAG, "Stopping " + s + ": nowVisible=" + s.nowVisible + " animating=" + animating + " finishing=" + s.finishing); - - final ActivityStack stack = s.getRootTask(); - final boolean shouldSleepOrShutDown = stack != null - ? stack.shouldSleepOrShutDownActivities() - : mService.isSleepingOrShuttingDownLocked(); - if (!animating || shouldSleepOrShutDown) { + if (!animating || mService.mShuttingDown) { if (!processPausingActivities && s.isState(PAUSING)) { // Defer processing pausing activities in this iteration and reschedule // a delayed idle to reprocess it again diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index c28d47cdbe80..c4ccd00d9b0a 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -467,28 +467,33 @@ public class ActivityStartController { final ActivityRecord[] outActivity = new ActivityRecord[1]; // Lock the loop to ensure the activities launched in a sequence. synchronized (mService.mGlobalLock) { - for (int i = 0; i < starters.length; i++) { - final int startResult = starters[i].setResultTo(resultTo) - .setOutActivity(outActivity).execute(); - if (startResult < START_SUCCESS) { - // Abort by error result and recycle unused starters. - for (int j = i + 1; j < starters.length; j++) { - mFactory.recycle(starters[j]); + mService.deferWindowLayout(); + try { + for (int i = 0; i < starters.length; i++) { + final int startResult = starters[i].setResultTo(resultTo) + .setOutActivity(outActivity).execute(); + if (startResult < START_SUCCESS) { + // Abort by error result and recycle unused starters. + for (int j = i + 1; j < starters.length; j++) { + mFactory.recycle(starters[j]); + } + return startResult; } - return startResult; - } - final ActivityRecord started = outActivity[0]; - if (started != null && started.getUid() == filterCallingUid) { - // Only the started activity which has the same uid as the source caller can - // be the caller of next activity. - resultTo = started.appToken; - } else { - resultTo = sourceResultTo; - // Different apps not adjacent to the caller are forced to be new task. - if (i < starters.length - 1) { - starters[i + 1].getIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + final ActivityRecord started = outActivity[0]; + if (started != null && started.getUid() == filterCallingUid) { + // Only the started activity which has the same uid as the source caller + // can be the caller of next activity. + resultTo = started.appToken; + } else { + resultTo = sourceResultTo; + // Different apps not adjacent to the caller are forced to be new task. + if (i < starters.length - 1) { + starters[i + 1].getIntent().addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + } } } + } finally { + mService.continueWindowLayout(); } } } finally { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index eb85db61754f..b6672d3c73c0 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -99,6 +99,7 @@ import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_SCREEN_ON; import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS; @@ -498,6 +499,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ private ActivityRecord mFixedRotationLaunchingApp; + private FixedRotationAnimationController mFixedRotationAnimationController; + final FixedRotationTransitionListener mFixedRotationTransitionListener = new FixedRotationTransitionListener(); @@ -1106,12 +1109,14 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } void removeShellRoot(int windowType) { - ShellRoot root = mShellRoots.get(windowType); - if (root == null) { - return; + synchronized(mWmService.mGlobalLock) { + ShellRoot root = mShellRoots.get(windowType); + if (root == null) { + return; + } + root.clear(); + mShellRoots.remove(windowType); } - root.clear(); - mShellRoots.remove(windowType); } void setRemoteInsetsController(IDisplayWindowInsetsController controller) { @@ -1481,8 +1486,21 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo return true; } - @Nullable ActivityRecord getFixedRotationLaunchingApp() { - return mFixedRotationLaunchingApp; + /** Returns {@code true} if the top activity is transformed with the new rotation of display. */ + boolean hasTopFixedRotationLaunchingApp() { + return mFixedRotationLaunchingApp != null + // Ignore animating recents because it hasn't really become the top. + && mFixedRotationLaunchingApp != mFixedRotationTransitionListener.mAnimatingRecents; + } + + @VisibleForTesting + boolean isFixedRotationLaunchingApp(ActivityRecord r) { + return mFixedRotationLaunchingApp == r; + } + + @VisibleForTesting + @Nullable FixedRotationAnimationController getFixedRotationAnimationController() { + return mFixedRotationAnimationController; } void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r) { @@ -1492,8 +1510,13 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo void setFixedRotationLaunchingAppUnchecked(@Nullable ActivityRecord r, int rotation) { if (mFixedRotationLaunchingApp == null && r != null) { mWmService.mDisplayNotificationController.dispatchFixedRotationStarted(this, rotation); + if (mFixedRotationAnimationController == null) { + mFixedRotationAnimationController = new FixedRotationAnimationController(this); + mFixedRotationAnimationController.hide(); + } } else if (mFixedRotationLaunchingApp != null && r == null) { mWmService.mDisplayNotificationController.dispatchFixedRotationFinished(this); + finishFixedRotationAnimationIfPossible(); } mFixedRotationLaunchingApp = r; } @@ -1582,6 +1605,15 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo } } + /** Re-show the previously hidden windows if all seamless rotated windows are done. */ + void finishFixedRotationAnimationIfPossible() { + final FixedRotationAnimationController controller = mFixedRotationAnimationController; + if (controller != null && !mDisplayRotation.hasSeamlessRotatingWindow()) { + controller.show(); + mFixedRotationAnimationController = null; + } + } + /** * Update rotation of the display. * @@ -3494,7 +3526,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; } - + ProtoLog.i(WM_DEBUG_IME, "setInputMethodTarget %s", target); mInputMethodTarget = target; mInputMethodTargetWaitingAnim = targetWaitingAnim; assignWindowLayers(true /* setLayoutNeeded */); @@ -3508,6 +3540,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo */ void setInputMethodInputTarget(WindowState target) { if (mInputMethodInputTarget != target) { + ProtoLog.i(WM_DEBUG_IME, "setInputMethodInputTarget %s", target); mInputMethodInputTarget = target; updateImeControlTarget(); } @@ -3515,6 +3548,8 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private void updateImeControlTarget() { mInputMethodControlTarget = computeImeControlTarget(); + ProtoLog.i(WM_DEBUG_IME, "updateImeControlTarget %s", + mInputMethodControlTarget.getWindow()); mInsetsStateController.onImeControlTargetChanged(mInputMethodControlTarget); } diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java index 702df2a0fc63..831491dd145e 100644 --- a/services/core/java/com/android/server/wm/DisplayRotation.java +++ b/services/core/java/com/android/server/wm/DisplayRotation.java @@ -560,6 +560,7 @@ public class DisplayRotation { }, true /* traverseTopToBottom */); mSeamlessRotationCount = 0; mRotatingSeamlessly = false; + mDisplayContent.finishFixedRotationAnimationIfPossible(); } private void prepareSeamlessRotation() { @@ -573,11 +574,15 @@ public class DisplayRotation { return mRotatingSeamlessly; } + boolean hasSeamlessRotatingWindow() { + return mSeamlessRotationCount > 0; + } + @VisibleForTesting boolean shouldRotateSeamlessly(int oldRotation, int newRotation, boolean forceUpdate) { // Display doesn't need to be frozen because application has been started in correct // rotation already, so the rest of the windows can use seamless rotation. - if (mDisplayContent.getFixedRotationLaunchingApp() != null) { + if (mDisplayContent.hasTopFixedRotationLaunchingApp()) { return true; } @@ -646,6 +651,7 @@ public class DisplayRotation { "Performing post-rotate rotation after seamless rotation"); // Finish seamless rotation. mRotatingSeamlessly = false; + mDisplayContent.finishFixedRotationAnimationIfPossible(); updateRotationAndSendNewConfigIfChanged(); } diff --git a/services/core/java/com/android/server/wm/FixedRotationAnimationController.java b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java new file mode 100644 index 000000000000..cc02e991c2ae --- /dev/null +++ b/services/core/java/com/android/server/wm/FixedRotationAnimationController.java @@ -0,0 +1,166 @@ +/* + * 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.wm; + +import static com.android.server.wm.AnimationSpecProto.WINDOW; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; +import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION; + +import android.content.Context; +import android.util.ArrayMap; +import android.util.proto.ProtoOutputStream; +import android.view.SurfaceControl; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; +import android.view.animation.Transformation; + +import com.android.internal.R; + +import java.io.PrintWriter; +import java.util.ArrayList; + +/** + * Controller to fade out and in system ui when applying a fixed rotation transform to a window + * token. + * + * The system bars will be fade out when the fixed rotation transform starts and will be fade in + * once all surfaces have been rotated. + */ +public class FixedRotationAnimationController { + + private final Context mContext; + private final WindowState mStatusBar; + private final WindowState mNavigationBar; + private final ArrayList<WindowToken> mAnimatedWindowToken = new ArrayList<>(2); + private final ArrayMap<WindowToken, Runnable> mDeferredFinishCallbacks = new ArrayMap<>(); + + public FixedRotationAnimationController(DisplayContent displayContent) { + mContext = displayContent.mWmService.mContext; + final DisplayPolicy displayPolicy = displayContent.getDisplayPolicy(); + mStatusBar = displayPolicy.getStatusBar(); + // Do not animate movable navigation bar (e.g. non-gesture mode). + mNavigationBar = !displayPolicy.navigationBarCanMove() + ? displayPolicy.getNavigationBar() + : null; + } + + /** Applies show animation on the previously hidden window tokens. */ + void show() { + for (int i = mAnimatedWindowToken.size() - 1; i >= 0; i--) { + final WindowToken windowToken = mAnimatedWindowToken.get(i); + fadeWindowToken(true /* show */, windowToken); + } + } + + /** Applies hide animation on the window tokens which may be seamlessly rotated later. */ + void hide() { + if (mNavigationBar != null) { + fadeWindowToken(false /* show */, mNavigationBar.mToken); + } + if (mStatusBar != null) { + fadeWindowToken(false /* show */, mStatusBar.mToken); + } + } + + private void fadeWindowToken(boolean show, WindowToken windowToken) { + if (windowToken == null || windowToken.getParent() == null) { + return; + } + + final Animation animation = AnimationUtils.loadAnimation(mContext, + show ? R.anim.fade_in : R.anim.fade_out); + final LocalAnimationAdapter.AnimationSpec windowAnimationSpec = + createAnimationSpec(animation); + + final FixedRotationAnimationAdapter animationAdapter = new FixedRotationAnimationAdapter( + windowAnimationSpec, windowToken.getSurfaceAnimationRunner(), show, windowToken); + + // We deferred the end of the animation when hiding the token, so we need to end it now that + // it's shown again. + final SurfaceAnimator.OnAnimationFinishedCallback finishedCallback = show ? (t, r) -> { + final Runnable runnable = mDeferredFinishCallbacks.remove(windowToken); + if (runnable != null) { + runnable.run(); + } + } : null; + windowToken.startAnimation(windowToken.getPendingTransaction(), animationAdapter, + show /* hidden */, ANIMATION_TYPE_FIXED_TRANSFORM, finishedCallback); + mAnimatedWindowToken.add(windowToken); + } + + private LocalAnimationAdapter.AnimationSpec createAnimationSpec(Animation animation) { + return new LocalAnimationAdapter.AnimationSpec() { + + final Transformation mTransformation = new Transformation(); + + @Override + public boolean getShowWallpaper() { + return true; + } + + @Override + public long getDuration() { + return animation.getDuration(); + } + + @Override + public void apply(SurfaceControl.Transaction t, SurfaceControl leash, + long currentPlayTime) { + mTransformation.clear(); + animation.getTransformation(currentPlayTime, mTransformation); + t.setAlpha(leash, mTransformation.getAlpha()); + } + + @Override + public void dump(PrintWriter pw, String prefix) { + pw.print(prefix); + pw.println(animation); + } + + @Override + public void dumpDebugInner(ProtoOutputStream proto) { + final long token = proto.start(WINDOW); + proto.write(ANIMATION, animation.toString()); + proto.end(token); + } + }; + } + + private class FixedRotationAnimationAdapter extends LocalAnimationAdapter { + private final boolean mShow; + private final WindowToken mToken; + + FixedRotationAnimationAdapter(AnimationSpec windowAnimationSpec, + SurfaceAnimationRunner surfaceAnimationRunner, boolean show, + WindowToken token) { + super(windowAnimationSpec, surfaceAnimationRunner); + mShow = show; + mToken = token; + } + + @Override + public boolean shouldDeferAnimationFinish(Runnable endDeferFinishCallback) { + // We defer the end of the hide animation to ensure the tokens stay hidden until + // we show them again. + if (!mShow) { + mDeferredFinishCallbacks.put(mToken, endDeferFinishCallback); + return true; + } + return false; + } + } +} diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java index 7491376cd152..8298763c1392 100644 --- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java @@ -18,9 +18,11 @@ package com.android.server.wm; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; +import android.graphics.PixelFormat; import android.view.InsetsSource; import android.view.WindowInsets; +import com.android.internal.annotations.VisibleForTesting; import com.android.server.protolog.common.ProtoLog; /** @@ -65,9 +67,16 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { // Target should still be the same. if (isImeTargetFromDisplayContentAndImeSame()) { final InsetsControlTarget target = mDisplayContent.mInputMethodControlTarget; - ProtoLog.d(WM_DEBUG_IME, "call showInsets(ime) on %s", + + ProtoLog.i(WM_DEBUG_IME, "call showInsets(ime) on %s", target.getWindow() != null ? target.getWindow().getName() : ""); target.showInsets(WindowInsets.Type.ime(), true /* fromIme */); + if (target != mImeTargetFromIme && mImeTargetFromIme != null) { + ProtoLog.w(WM_DEBUG_IME, + "showInsets(ime) was requested by different window: %s ", + (mImeTargetFromIme.getWindow() != null + ? mImeTargetFromIme.getWindow().getName() : "")); + } } abortShowImePostLayout(); }; @@ -100,7 +109,8 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { mShowImeRunner = null; } - private boolean isImeTargetFromDisplayContentAndImeSame() { + @VisibleForTesting + boolean isImeTargetFromDisplayContentAndImeSame() { // IMMS#mLastImeTargetWindow always considers focused window as // IME target, however DisplayContent#computeImeTarget() can compute // a different IME target. @@ -111,6 +121,7 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { // TODO(b/139861270): Remove the child & sublayer check once IMMS is aware of // actual IME target. final WindowState dcTarget = mDisplayContent.mInputMethodTarget; + final InsetsControlTarget controlTarget = mDisplayContent.mInputMethodControlTarget; if (dcTarget == null || mImeTargetFromIme == null) { return false; } @@ -120,6 +131,9 @@ class ImeInsetsSourceProvider extends InsetsSourceProvider { return (!dcTarget.isClosing() && mImeTargetFromIme == dcTarget) || (mImeTargetFromIme != null && dcTarget.getParentWindow() == mImeTargetFromIme && dcTarget.mSubLayer > mImeTargetFromIme.mSubLayer) - || mImeTargetFromIme == mDisplayContent.getImeFallback(); + || mImeTargetFromIme == mDisplayContent.getImeFallback() + // If IME target is transparent but control target matches requesting window. + || (controlTarget == mImeTargetFromIme + && PixelFormat.formatHasAlpha(dcTarget.mAttrs.format)); } } diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java index a6a21fc55770..6a4975950f1a 100644 --- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java +++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java @@ -24,6 +24,7 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME; import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE; import static android.view.ViewRootImpl.sNewInsetsMode; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL; import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED; @@ -40,6 +41,7 @@ import android.view.SurfaceControl.Transaction; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.function.TriConsumer; +import com.android.server.protolog.common.ProtoLog; import com.android.server.wm.SurfaceAnimator.AnimationType; import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback; @@ -134,6 +136,7 @@ class InsetsSourceProvider { // animate-out as new one animates-in. mWin.cancelAnimation(); } + ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win); mWin = win; mFrameProvider = frameProvider; mImeFrameProvider = imeFrameProvider; @@ -299,6 +302,8 @@ class InsetsSourceProvider { updateVisibility(); mControl = new InsetsSourceControl(mSource.getType(), leash, new Point(mWin.getWindowFrames().mFrame.left, mWin.getWindowFrames().mFrame.top)); + ProtoLog.d(WM_DEBUG_IME, + "InsetsSource Control %s for target %s", mControl, mControlTarget); } void startSeamlessRotation() { @@ -349,6 +354,9 @@ class InsetsSourceProvider { final boolean isClientControlled = mControlTarget != null && mControlTarget.isClientControlled(); mSource.setVisible(mServerVisible && (!isClientControlled || mClientVisible)); + ProtoLog.d(WM_DEBUG_IME, + "InsetsSource updateVisibility serverVisible: %s clientVisible: %s", + mServerVisible, mClientVisible); } InsetsSourceControl getControl(InsetsControlTarget target) { @@ -391,6 +399,44 @@ class InsetsSourceProvider { return mImeOverrideFrame; } + public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "InsetsSourceProvider"); + pw.print(prefix + " mSource="); mSource.dump(prefix + " ", pw); + if (mControl != null) { + pw.print(prefix + " mControl="); + mControl.dump(prefix + " ", pw); + } + pw.print(prefix + " mFakeControl="); mFakeControl.dump(prefix + " ", pw); + pw.print(" mIsLeashReadyForDispatching="); pw.print(mIsLeashReadyForDispatching); + pw.print(" mImeOverrideFrame="); pw.print(mImeOverrideFrame.toString()); + if (mWin != null) { + pw.print(prefix + " mWin="); + mWin.dump(pw, prefix + " ", false /* dumpAll */); + } + if (mAdapter != null) { + pw.print(prefix + " mAdapter="); + mAdapter.dump(pw, prefix + " "); + } + if (mControlTarget != null) { + pw.print(prefix + " mControlTarget="); + if (mControlTarget.getWindow() != null) { + mControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */); + } + } + if (mPendingControlTarget != null) { + pw.print(prefix + " mPendingControlTarget="); + if (mPendingControlTarget.getWindow() != null) { + mPendingControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */); + } + } + if (mFakeControlTarget != null) { + pw.print(prefix + " mFakeControlTarget="); + if (mFakeControlTarget.getWindow() != null) { + mFakeControlTarget.getWindow().dump(pw, prefix + " ", false /* dumpAll */); + } + } + } + private class ControlAdapter implements AnimationAdapter { private SurfaceControl mCapturedLeash; @@ -410,6 +456,9 @@ class InsetsSourceProvider { t.setAlpha(animationLeash, 1 /* alpha */); t.hide(animationLeash); } + ProtoLog.i(WM_DEBUG_IME, + "ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource, + mControlTarget); mCapturedLeash = animationLeash; final Rect frame = mWin.getWindowFrames().mFrame; @@ -424,6 +473,9 @@ class InsetsSourceProvider { mControlTarget = null; mAdapter = null; setClientVisible(InsetsState.getDefaultVisibility(mSource.getType())); + ProtoLog.i(WM_DEBUG_IME, + "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s", + mSource, mControlTarget); } } @@ -439,6 +491,8 @@ class InsetsSourceProvider { @Override public void dump(PrintWriter pw, String prefix) { + pw.println(prefix + "ControlAdapter"); + pw.print(prefix + " mCapturedLeash="); pw.print(mCapturedLeash); } @Override diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java index 9798d77c5975..77bc37f0c2d7 100644 --- a/services/core/java/com/android/server/wm/InsetsStateController.java +++ b/services/core/java/com/android/server/wm/InsetsStateController.java @@ -29,6 +29,8 @@ import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD; import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR; import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; + import android.annotation.NonNull; import android.annotation.Nullable; import android.app.WindowConfiguration; @@ -42,6 +44,8 @@ import android.view.InsetsState; import android.view.InsetsState.InternalInsetsType; import android.view.WindowManager; +import com.android.server.protolog.common.ProtoLog; + import java.io.PrintWriter; import java.util.ArrayList; import java.util.function.Consumer; @@ -289,7 +293,10 @@ class InsetsStateController { // Make sure that we always have a control target for the IME, even if the IME target is // null. Otherwise there is no leash that will hide it and IME becomes "randomly" visible. - onControlChanged(ITYPE_IME, imeTarget != null ? imeTarget : mEmptyImeControlTarget); + InsetsControlTarget target = imeTarget != null ? imeTarget : mEmptyImeControlTarget; + onControlChanged(ITYPE_IME, target); + ProtoLog.d(WM_DEBUG_IME, "onImeControlTargetChanged %s", + target != null ? target.getWindow() : "null"); notifyPendingInsetsControlChanged(); } @@ -440,5 +447,11 @@ class InsetsStateController { pw.println(InsetsState.typeToString(mTypeControlTargetMap.keyAt(i)) + " -> " + mTypeControlTargetMap.valueAt(i)); } + pw.println(prefix + " " + "InsetsSourceProviders map:"); + for (int i = mProviders.size() - 1; i >= 0; i--) { + pw.print(prefix + " "); + pw.println(InsetsState.typeToString(mProviders.keyAt(i)) + " -> "); + mProviders.valueAt(i).dump(pw, prefix); + } } } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 0ecde72cc566..ae5adcae5b9b 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -2187,6 +2187,10 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // up-to-dated pinned stack information on this newly created stack. r.reparent(stack, MAX_VALUE, reason); } + // The intermediate windowing mode to be set on the ActivityRecord later. + // This needs to happen before the re-parenting, otherwise we will always set the + // ActivityRecord to be fullscreen. + final int intermediateWindowingMode = stack.getWindowingMode(); if (stack.getParent() != taskDisplayArea) { // stack is nested, but pinned tasks need to be direct children of their // display area, so reparent. @@ -2195,7 +2199,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Defer the windowing mode change until after the transition to prevent the activity // from doing work and changing the activity visuals while animating // TODO(task-org): Figure-out more structured way to do this long term. - r.setWindowingMode(stack.getWindowingMode()); + r.setWindowingMode(intermediateWindowingMode); stack.setWindowingMode(WINDOWING_MODE_PINNED); // Reset the state that indicates it can enter PiP while pausing after we've moved it diff --git a/services/core/java/com/android/server/wm/ShellRoot.java b/services/core/java/com/android/server/wm/ShellRoot.java index 99f710bd8bd4..7a38bb65f73b 100644 --- a/services/core/java/com/android/server/wm/ShellRoot.java +++ b/services/core/java/com/android/server/wm/ShellRoot.java @@ -156,4 +156,3 @@ public class ShellRoot { } } } - diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java index 42342a60ba16..0143eb1abe03 100644 --- a/services/core/java/com/android/server/wm/SurfaceAnimator.java +++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java @@ -489,6 +489,12 @@ class SurfaceAnimator { static final int ANIMATION_TYPE_INSETS_CONTROL = 1 << 5; /** + * Animation when a fixed rotation transform is applied to a window token. + * @hide + */ + static final int ANIMATION_TYPE_FIXED_TRANSFORM = 1 << 6; + + /** * Bitmask to include all animation types. This is NOT an {@link AnimationType} * @hide */ @@ -505,7 +511,8 @@ class SurfaceAnimator { ANIMATION_TYPE_DIMMER, ANIMATION_TYPE_RECENTS, ANIMATION_TYPE_WINDOW_ANIMATION, - ANIMATION_TYPE_INSETS_CONTROL + ANIMATION_TYPE_INSETS_CONTROL, + ANIMATION_TYPE_FIXED_TRANSFORM }) @Retention(RetentionPolicy.SOURCE) @interface AnimationType {} diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index f8ad6f248728..bf7ec910f197 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -436,7 +436,12 @@ class Task extends WindowContainer<WindowContainer> { static final int FLAG_FORCE_HIDDEN_FOR_TASK_ORG = 1 << 1; private int mForceHiddenFlags = 0; + // When non-null, this is a transaction that will get applied on the next frame returned after + // a relayout is requested from the client. While this is only valid on a leaf task; since the + // transaction can effect an ancestor task, this also needs to keep track of the ancestor task + // that this transaction manipulates because deferUntilFrame acts on individual surfaces. SurfaceControl.Transaction mMainWindowSizeChangeTransaction; + Task mMainWindowSizeChangeTask; private final FindRootHelper mFindRootHelper = new FindRootHelper(); private class FindRootHelper { @@ -1309,12 +1314,12 @@ class Task extends WindowContainer<WindowContainer> { return isUidPresent; } - ActivityRecord topRunningActivityWithStartingWindowLocked() { + ActivityRecord topActivityWithStartingWindow() { if (getParent() == null) { return null; } return getActivity((r) -> r.mStartingWindowState == STARTING_WINDOW_SHOWN - && r.canBeTopRunning()); + && r.okToShowLocked()); } /** @@ -1745,7 +1750,7 @@ class Task extends WindowContainer<WindowContainer> { } if (isOrganized()) { - mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, true /* force */); + mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(this, false /* force */); } } @@ -4510,13 +4515,32 @@ class Task extends WindowContainer<WindowContainer> { * to resize, and it will defer the transaction until that resize frame completes. */ void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t) { + setMainWindowSizeChangeTransaction(t, this); + } + + private void setMainWindowSizeChangeTransaction(SurfaceControl.Transaction t, Task origin) { + // This is only meaningful on an activity's task, so put it on the top one. + ActivityRecord topActivity = getTopNonFinishingActivity(); + Task leaf = topActivity != null ? topActivity.getTask() : null; + if (leaf == null) { + return; + } + if (leaf != this) { + leaf.setMainWindowSizeChangeTransaction(t, origin); + return; + } mMainWindowSizeChangeTransaction = t; + mMainWindowSizeChangeTask = t == null ? null : origin; } SurfaceControl.Transaction getMainWindowSizeChangeTransaction() { return mMainWindowSizeChangeTransaction; } + Task getMainWindowSizeChangeTask() { + return mMainWindowSizeChangeTask; + } + void setActivityWindowingMode(int windowingMode) { PooledConsumer c = PooledLambda.obtainConsumer(ActivityRecord::setWindowingMode, PooledLambda.__(ActivityRecord.class), windowingMode); diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index 9130483325b2..6dde5b0d4879 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -765,6 +765,32 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { onStackOrderChanged(stack); } + /** + * Moves/reparents `task` to the back of whatever container the home stack is in. This is for + * when we just want to move a task to "the back" vs. a specific place. The primary use-case + * is to make sure that moved-to-back apps go into secondary split when in split-screen mode. + */ + void positionTaskBehindHome(ActivityStack task) { + final ActivityStack home = getOrCreateRootHomeTask(); + final WindowContainer homeParent = home.getParent(); + final Task homeParentTask = homeParent != null ? homeParent.asTask() : null; + if (homeParentTask == null) { + // reparent throws if parent didn't change... + if (task.getParent() == this) { + positionStackAtBottom(task); + } else { + task.reparent(this, false /* onTop */); + } + } else if (homeParentTask == task.getParent()) { + // Apparently reparent early-outs if same stack, so we have to explicitly reorder. + ((ActivityStack) homeParentTask).positionChildAtBottom(task); + } else { + task.reparent((ActivityStack) homeParentTask, false /* toTop */, + Task.REPARENT_LEAVE_STACK_IN_PLACE, false /* animate */, + false /* deferResume */, "positionTaskBehindHome"); + } + } + ActivityStack getStack(int rootTaskId) { for (int i = getStackCount() - 1; i >= 0; --i) { final ActivityStack stack = getStackAt(i); diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java index a1fbb597533f..3fe8229e2ec2 100644 --- a/services/core/java/com/android/server/wm/WindowContainer.java +++ b/services/core/java/com/android/server/wm/WindowContainer.java @@ -399,7 +399,11 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< } void createSurfaceControl(boolean force) { - setSurfaceControl(makeSurface().build()); + setInitialSurfaceControlProperties(makeSurface().build()); + } + + private void setInitialSurfaceControlProperties(SurfaceControl surfaceControl) { + setSurfaceControl(surfaceControl); getPendingTransaction().show(mSurfaceControl); onSurfaceShown(getPendingTransaction()); updateSurfacePosition(); @@ -423,7 +427,16 @@ class WindowContainer<E extends WindowContainer> extends ConfigurationContainer< // Clear the last position so the new SurfaceControl will get correct position mLastSurfacePosition.set(0, 0); - createSurfaceControl(false /* force */); + final SurfaceControl.Builder b = mWmService.makeSurfaceBuilder(null) + .setContainerLayer() + .setName(getName()); + + setInitialSurfaceControlProperties(b.build()); + + // If parent is null, the layer should be placed offscreen so reparent to null. Otherwise, + // set to the available parent. + t.reparent(mSurfaceControl, mParent == null ? null : mParent.getSurfaceControl()); + if (mLastRelativeToLayer != null) { t.setRelativeLayer(mSurfaceControl, mLastRelativeToLayer, mLastLayer); } else { diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java index e011c7945882..c605e3e1ea60 100644 --- a/services/core/java/com/android/server/wm/WindowManagerInternal.java +++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java @@ -576,4 +576,24 @@ public abstract class WindowManagerInternal { * @return The corresponding {@link WindowState#getName()} */ public abstract String getWindowName(@NonNull IBinder binder); + + /** + * Return the window name of IME Insets control target. + * + * @param displayId The ID of the display which input method is currently focused. + * @return The corresponding {@link WindowState#getName()} + */ + public abstract @Nullable String getImeControlTargetNameForLogging(int displayId); + + /** + * Return the current window name of the input method is on top of. + * + * Note that the concept of this window is only reparent the target window behind the input + * method window, it may different with the window which reported by + * {@code InputMethodManagerService#reportStartInput} which has input connection. + * + * @param displayId The ID of the display which input method is currently focused. + * @return The corresponding {@link WindowState#getName()} + */ + public abstract @Nullable String getImeTargetNameForLogging(int displayId); } diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index 159c59b86b43..f34510e2104a 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -6191,6 +6191,7 @@ public class WindowManagerService extends IWindowManager.Stub final int displayId = dc.getDisplayId(); final WindowState inputMethodTarget = dc.mInputMethodTarget; final WindowState inputMethodInputTarget = dc.mInputMethodInputTarget; + final InsetsControlTarget inputMethodControlTarget = dc.mInputMethodControlTarget; if (inputMethodTarget != null) { pw.print(" mInputMethodTarget in display# "); pw.print(displayId); pw.print(' '); pw.println(inputMethodTarget); @@ -6199,6 +6200,10 @@ public class WindowManagerService extends IWindowManager.Stub pw.print(" mInputMethodInputTarget in display# "); pw.print(displayId); pw.print(' '); pw.println(inputMethodInputTarget); } + if (inputMethodControlTarget != null) { + pw.print(" inputMethodControlTarget in display# "); pw.print(displayId); + pw.print(' '); pw.println(inputMethodControlTarget.getWindow()); + } }); pw.print(" mInTouchMode="); pw.println(mInTouchMode); pw.print(" mLastDisplayFreezeDuration="); @@ -7750,6 +7755,33 @@ public class WindowManagerService extends IWindowManager.Stub return w != null ? w.getName() : null; } } + + @Override + public String getImeControlTargetNameForLogging(int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return null; + } + final InsetsControlTarget target = dc.mInputMethodControlTarget; + if (target == null) { + return null; + } + final WindowState win = target.getWindow(); + return win != null ? win.getName() : target.toString(); + } + } + + @Override + public String getImeTargetNameForLogging(int displayId) { + synchronized (mGlobalLock) { + final DisplayContent dc = mRoot.getDisplayContent(displayId); + if (dc == null) { + return null; + } + return dc.mInputMethodTarget != null ? dc.mInputMethodTarget.getName() : null; + } + } } void registerAppFreezeListener(AppFreezeListener listener) { diff --git a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java index 619d87bc49f0..bdecb8d99752 100644 --- a/services/core/java/com/android/server/wm/WindowManagerShellCommand.java +++ b/services/core/java/com/android/server/wm/WindowManagerShellCommand.java @@ -351,6 +351,11 @@ public class WindowManagerShellCommand extends ShellCommand { } private int runDumpVisibleWindowViews(PrintWriter pw) { + if (!mInternal.checkCallingPermission(android.Manifest.permission.DUMP, + "runDumpVisibleWindowViews()")) { + throw new SecurityException("Requires DUMP permission"); + } + try (ZipOutputStream out = new ZipOutputStream(getRawOutputStream())) { ArrayList<Pair<String, ByteTransferPipe>> requestList = new ArrayList<>(); synchronized (mInternal.mGlobalLock) { diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 707a7898f8b6..a3faa86758cd 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -163,8 +163,42 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub Slog.e(TAG, "Attempt to operate on detached container: " + wc); continue; } + if (syncId >= 0) { + mBLASTSyncEngine.addToSyncSet(syncId, wc); + } effects |= sanitizeAndApplyHierarchyOp(wc, hop); } + // Queue-up bounds-change transactions for tasks which are now organized. Do + // this after hierarchy ops so we have the final organized state. + entries = t.getChanges().entrySet().iterator(); + while (entries.hasNext()) { + final Map.Entry<IBinder, WindowContainerTransaction.Change> entry = + entries.next(); + final Task task = WindowContainer.fromBinder(entry.getKey()).asTask(); + final Rect surfaceBounds = entry.getValue().getBoundsChangeSurfaceBounds(); + if (task == null || !task.isAttached() || surfaceBounds == null) { + continue; + } + if (!task.isOrganized()) { + final Task parent = + task.getParent() != null ? task.getParent().asTask() : null; + // Also allow direct children of created-by-organizer tasks to be + // controlled. In the future, these will become organized anyways. + if (parent == null || !parent.mCreatedByOrganizer) { + throw new IllegalArgumentException( + "Can't manipulate non-organized task surface " + task); + } + } + final SurfaceControl.Transaction sft = new SurfaceControl.Transaction(); + final SurfaceControl sc = task.getSurfaceControl(); + sft.setPosition(sc, surfaceBounds.left, surfaceBounds.top); + if (surfaceBounds.isEmpty()) { + sft.setWindowCrop(sc, null); + } else { + sft.setWindowCrop(sc, surfaceBounds.width(), surfaceBounds.height()); + } + task.setMainWindowSizeChangeTransaction(sft); + } if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) { // Already calls ensureActivityConfig mService.mRootWindowContainer.ensureActivitiesVisible( diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index e9aff88d0f80..4f1893eb6c13 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -113,6 +113,7 @@ import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT; +import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_IME; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE; import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW; @@ -334,6 +335,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP private boolean mDragResizing; private boolean mDragResizingChangeReported = true; private int mResizeMode; + private boolean mResizeForBlastSyncReported; + /** * Special mode that is intended only for the rounded corner overlay: during rotation * transition, we un-rotate the window token such that the window appears as it did before the @@ -1370,11 +1373,14 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP // variables, because mFrameSizeChanged only tracks the width and height changing. updateLastFrames(); + // Add a window that is using blastSync to the resizing list if it hasn't been reported + // already. This because the window is waiting on a finishDrawing from the client. if (didFrameInsetsChange || winAnimator.mSurfaceResized || configChanged || dragResizingChanged - || mReportOrientationChanged) { + || mReportOrientationChanged + || requestResizeForBlastSync()) { ProtoLog.v(WM_DEBUG_RESIZE, "Resize reasons for w=%s: %s surfaceResized=%b configChanged=%b " + "dragResizingChanged=%b reportOrientationChanged=%b", @@ -3483,6 +3489,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mReportOrientationChanged = false; mDragResizingChangeReported = true; mWinAnimator.mSurfaceResized = false; + mResizeForBlastSyncReported = true; mWindowFrames.resetInsetsChanged(); final Rect frame = mWindowFrames.mCompatFrame; @@ -3553,6 +3560,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP * Called when the insets state changed. */ void notifyInsetsChanged() { + ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this); try { mClient.insetsChanged(getInsetsState()); } catch (RemoteException e) { @@ -3562,6 +3570,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP @Override public void notifyInsetsControlChanged() { + ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this); final InsetsStateController stateController = getDisplayContent().getInsetsStateController(); try { @@ -5500,7 +5509,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } long getFrameNumber() { - return mFrameNumber; + // Return the frame number in which changes requested in this layout will be rendered or + // -1 if we do not expect the frame to be rendered. + return getFrameLw().isEmpty() ? -1 : mFrameNumber; } void setFrameNumber(long frameNumber) { @@ -5733,6 +5744,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP if (!willSync) { return false; } + mResizeForBlastSyncReported = false; mLocalSyncId = mBLASTSyncEngine.startSyncSet(this); addChildrenToSyncSet(mLocalSyncId); @@ -5777,4 +5789,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mWaitingListener = null; return mWinAnimator.finishDrawingLocked(null); } + + private boolean requestResizeForBlastSync() { + return useBLASTSync() && !mResizeForBlastSyncReported; + } } diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java index b30d40824a05..42c21930bdf7 100644 --- a/services/core/java/com/android/server/wm/WindowStateAnimator.java +++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java @@ -904,8 +904,8 @@ class WindowStateAnimator { } if (shouldConsumeMainWindowSizeTransaction()) { - task.getSurfaceControl().deferTransactionUntil(mWin.getClientViewRootSurface(), - mWin.getFrameNumber()); + task.getMainWindowSizeChangeTask().getSurfaceControl().deferTransactionUntil( + mWin.getClientViewRootSurface(), mWin.getFrameNumber()); mSurfaceController.deferTransactionUntil(mWin.getClientViewRootSurface(), mWin.getFrameNumber()); SurfaceControl.mergeToGlobalTransaction(task.getMainWindowSizeChangeTransaction()); diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp index 20139451e4b9..75ec22486021 100644 --- a/services/core/jni/com_android_server_input_InputManagerService.cpp +++ b/services/core/jni/com_android_server_input_InputManagerService.cpp @@ -403,7 +403,8 @@ void NativeInputManager::setDisplayViewports(JNIEnv* env, jobjectArray viewportO DisplayViewport viewport; android_hardware_display_DisplayViewport_toNative(env, viewportObj, &viewport); - ALOGI("Viewport [%d] to add: %s", (int) i, viewport.uniqueId.c_str()); + ALOGI("Viewport [%d] to add: %s, isActive: %s", (int)i, viewport.uniqueId.c_str(), + toString(viewport.isActive)); viewports.push_back(viewport); env->DeleteLocalRef(viewportObj); diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp index e4061b4fc34c..c7dac787c653 100644 --- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp +++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp @@ -337,7 +337,11 @@ JavaObject::JavaObject(JNIEnv* env, jclass clazz, jmethodID defaultCtor) : env_( JavaObject::JavaObject(JNIEnv* env, jclass clazz, jmethodID stringCtor, const char * sz_arg_1) : env_(env), clazz_(clazz) { - object_ = env_->NewObject(clazz_, stringCtor, env->NewStringUTF(sz_arg_1)); + jstring szArg = env->NewStringUTF(sz_arg_1); + object_ = env_->NewObject(clazz_, stringCtor, szArg); + if (szArg) { + env_->DeleteLocalRef(szArg); + } } @@ -724,6 +728,9 @@ Return<void> GnssCallback::gnssNameCb(const android::hardware::hidl_string& name JNIEnv* env = getJniEnv(); jstring jstringName = env->NewStringUTF(name.c_str()); env->CallVoidMethod(mCallbacksObj, method_setGnssHardwareModelName, jstringName); + if (jstringName) { + env->DeleteLocalRef(jstringName); + } checkAndClearExceptionFromCallback(env, __FUNCTION__); return Void(); @@ -827,6 +834,13 @@ Return<void> GnssCallback::gnssSvStatusCbImpl(const T& svStatus) { static_cast<jint>(listSize), svidWithFlagArray, cn0Array, elevArray, azimArray, carrierFreqArray, basebandCn0Array); + env->DeleteLocalRef(svidWithFlagArray); + env->DeleteLocalRef(cn0Array); + env->DeleteLocalRef(elevArray); + env->DeleteLocalRef(azimArray); + env->DeleteLocalRef(carrierFreqArray); + env->DeleteLocalRef(basebandCn0Array); + checkAndClearExceptionFromCallback(env, __FUNCTION__); return Void(); } @@ -1429,13 +1443,18 @@ void GnssMeasurementCallback::translateSingleGnssMeasurement JNIEnv* env = getJniEnv(); translateSingleGnssMeasurement(&(measurement_V2_0->v1_1), object); - SET(CodeType, env->NewStringUTF(measurement_V2_0->codeType.c_str())); + jstring codeType = env->NewStringUTF(measurement_V2_0->codeType.c_str()); + SET(CodeType, codeType); // Overwrite with v2_0.state since v2_0->v1_1->v1_0.state is deprecated. SET(State, static_cast<int32_t>(measurement_V2_0->state)); // Overwrite with v2_0.constellation since v2_0->v1_1->v1_0.constellation is deprecated. SET(ConstellationType, static_cast<int32_t>(measurement_V2_0->constellation)); + + if (codeType) { + env->DeleteLocalRef(codeType); + } } // Preallocate object as: JavaObject object(env, "android/location/GnssMeasurement"); @@ -1515,10 +1534,16 @@ void GnssMeasurementCallback::translateGnssClock( SET(ReferenceConstellationTypeForIsb, static_cast<int32_t>(clock.referenceSignalTypeForIsb.constellation)); SET(ReferenceCarrierFrequencyHzForIsb, clock.referenceSignalTypeForIsb.carrierFrequencyHz); - SET(ReferenceCodeTypeForIsb, - env->NewStringUTF(clock.referenceSignalTypeForIsb.codeType.c_str())); + + jstring referenceCodeTypeForIsb = + env->NewStringUTF(clock.referenceSignalTypeForIsb.codeType.c_str()); + SET(ReferenceCodeTypeForIsb, referenceCodeTypeForIsb); translateGnssClock(object, clock.v1_0); + + if (referenceCodeTypeForIsb) { + env->DeleteLocalRef(referenceCodeTypeForIsb); + } } template<> @@ -1565,7 +1590,9 @@ jobjectArray GnssMeasurementCallback::translateAllGnssMeasurements(JNIEnv* env, for (uint16_t i = 0; i < count; ++i) { JavaObject object(env, class_gnssMeasurement, method_gnssMeasurementCtor); translateSingleGnssMeasurement(&(measurements[i]), object); - env->SetObjectArrayElement(gnssMeasurementArray, i, object.get()); + jobject gnssMeasurement = object.get(); + env->SetObjectArrayElement(gnssMeasurementArray, i, gnssMeasurement); + env->DeleteLocalRef(gnssMeasurement); } return gnssMeasurementArray; diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java index b7a9ba56c013..8d32d7c970bc 100644 --- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java +++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java @@ -11951,11 +11951,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { user); mInjector.getLocationManager().setLocationEnabledForUser(locationEnabled, user); - // make a best effort to only show the notification if the admin is actually changing - // something. this is subject to race conditions with settings changes, but those are + // make a best effort to only show the notification if the admin is actually enabling + // location. this is subject to race conditions with settings changes, but those are // unlikely to realistically interfere - if (wasLocationEnabled != locationEnabled) { - showLocationSettingsChangedNotification(user); + if (locationEnabled && (wasLocationEnabled != locationEnabled)) { + showLocationSettingsEnabledNotification(user); } }); @@ -11968,7 +11968,7 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { .write(); } - private void showLocationSettingsChangedNotification(UserHandle user) { + private void showLocationSettingsEnabledNotification(UserHandle user) { Intent intent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS) .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // Fill the component explicitly to prevent the PendingIntent from being intercepted @@ -12100,8 +12100,11 @@ public class DevicePolicyManagerService extends BaseIDevicePolicyManager { saveSettingsLocked(callingUserId); } mInjector.settingsSecurePutStringForUser(setting, value, callingUserId); - if (setting.equals(Settings.Secure.LOCATION_MODE)) { - showLocationSettingsChangedNotification(UserHandle.of(callingUserId)); + // Notify the user if it's the location mode setting that's been set, to any value + // other than 'off'. + if (setting.equals(Settings.Secure.LOCATION_MODE) + && (Integer.parseInt(value) != 0)) { + showLocationSettingsEnabledNotification(UserHandle.of(callingUserId)); } }); } diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index 847667427593..e790a196ad64 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -118,14 +118,18 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path, } binder::Status BinderIncrementalService::createStorage( - const std::string& path, const content::pm::DataLoaderParamsParcel& params, - const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, - int32_t createMode, int32_t* _aidl_return) { + const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params, + int32_t createMode, + const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener, + const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams, + const ::android::sp<::android::os::incremental::IStorageHealthListener>& healthListener, + int32_t* _aidl_return) { *_aidl_return = mImpl.createStorage(path, const_cast<content::pm::DataLoaderParamsParcel&&>(params), - listener, - android::incremental::IncrementalService::CreateOptions( - createMode)); + android::incremental::IncrementalService::CreateOptions(createMode), + statusListener, + const_cast<StorageHealthCheckParams&&>(healthCheckParams), + healthListener); return ok(); } @@ -276,8 +280,9 @@ binder::Status BinderIncrementalService::startLoading(int32_t storageId, bool* _ binder::Status BinderIncrementalService::configureNativeBinaries( int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath, - const std::string& abi, bool* _aidl_return) { - *_aidl_return = mImpl.configureNativeBinaries(storageId, apkFullPath, libDirRelativePath, abi); + const std::string& abi, bool extractNativeLibs, bool* _aidl_return) { + *_aidl_return = mImpl.configureNativeBinaries(storageId, apkFullPath, libDirRelativePath, abi, + extractNativeLibs); return ok(); } diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h index 5a7d5da56f18..68549f5a8ff8 100644 --- a/services/incremental/BinderIncrementalService.h +++ b/services/incremental/BinderIncrementalService.h @@ -41,8 +41,11 @@ public: binder::Status openStorage(const std::string& path, int32_t* _aidl_return) final; binder::Status createStorage( const ::std::string& path, const ::android::content::pm::DataLoaderParamsParcel& params, - const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, - int32_t createMode, int32_t* _aidl_return) final; + int32_t createMode, + const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& statusListener, + const ::android::os::incremental::StorageHealthCheckParams& healthCheckParams, + const ::android::sp<IStorageHealthListener>& healthListener, + int32_t* _aidl_return) final; binder::Status createLinkedStorage(const std::string& path, int32_t otherStorageId, int32_t createMode, int32_t* _aidl_return) final; binder::Status makeBindMount(int32_t storageId, const std::string& sourcePath, @@ -55,8 +58,7 @@ public: binder::Status makeDirectories(int32_t storageId, const std::string& path, int32_t* _aidl_return) final; binder::Status makeFile(int32_t storageId, const std::string& path, - const ::android::os::incremental::IncrementalNewFileParams& params, - int32_t* _aidl_return) final; + const IncrementalNewFileParams& params, int32_t* _aidl_return) final; binder::Status makeFileFromRange(int32_t storageId, const std::string& targetPath, const std::string& sourcePath, int64_t start, int64_t end, int32_t* _aidl_return) final; @@ -75,7 +77,8 @@ public: binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath, - const std::string& abi, bool* _aidl_return) final; + const std::string& abi, bool extractNativeLibs, + bool* _aidl_return) final; binder::Status waitForNativeBinariesExtraction(int storageId, bool* _aidl_return) final; private: diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index f0dca772adaa..66c7717d7987 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -410,9 +410,12 @@ auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator { } } -StorageId IncrementalService::createStorage( - std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams, - const DataLoaderStatusListener& dataLoaderStatusListener, CreateOptions options) { +StorageId IncrementalService::createStorage(std::string_view mountPoint, + content::pm::DataLoaderParamsParcel&& dataLoaderParams, + CreateOptions options, + const DataLoaderStatusListener& statusListener, + StorageHealthCheckParams&& healthCheckParams, + const StorageHealthListener& healthListener) { LOG(INFO) << "createStorage: " << mountPoint << " | " << int(options); if (!path::isAbsolute(mountPoint)) { LOG(ERROR) << "path is not absolute: " << mountPoint; @@ -545,8 +548,8 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); - auto dataLoaderStub = - prepareDataLoader(*ifs, std::move(dataLoaderParams), &dataLoaderStatusListener); + auto dataLoaderStub = prepareDataLoader(*ifs, std::move(dataLoaderParams), &statusListener, + std::move(healthCheckParams), &healthListener); CHECK(dataLoaderStub); mountIt->second = std::move(ifs); @@ -1254,7 +1257,7 @@ bool IncrementalService::mountExistingImage(std::string_view root) { dataLoaderParams.arguments = loader.arguments(); } - prepareDataLoader(*ifs, std::move(dataLoaderParams), nullptr); + prepareDataLoader(*ifs, std::move(dataLoaderParams)); CHECK(ifs->dataLoaderStub); std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; @@ -1338,14 +1341,18 @@ void IncrementalService::runCmdLooper() { IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader( IncFsMount& ifs, DataLoaderParamsParcel&& params, - const DataLoaderStatusListener* externalListener) { + const DataLoaderStatusListener* statusListener, + StorageHealthCheckParams&& healthCheckParams, const StorageHealthListener* healthListener) { std::unique_lock l(ifs.lock); - prepareDataLoaderLocked(ifs, std::move(params), externalListener); + prepareDataLoaderLocked(ifs, std::move(params), statusListener, std::move(healthCheckParams), + healthListener); return ifs.dataLoaderStub; } void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderParamsParcel&& params, - const DataLoaderStatusListener* externalListener) { + const DataLoaderStatusListener* statusListener, + StorageHealthCheckParams&& healthCheckParams, + const StorageHealthListener* healthListener) { if (ifs.dataLoaderStub) { LOG(INFO) << "Skipped data loader preparation because it already exists"; return; @@ -1360,7 +1367,8 @@ void IncrementalService::prepareDataLoaderLocked(IncFsMount& ifs, DataLoaderPara ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params), std::move(fsControlParcel), - externalListener, path::join(ifs.root, constants().mount)); + statusListener, std::move(healthCheckParams), healthListener, + path::join(ifs.root, constants().mount)); } template <class Duration> @@ -1371,7 +1379,7 @@ static long elapsedMcs(Duration start, Duration end) { // Extract lib files from zip, create new files in incfs and write data to them bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, - std::string_view abi) { + std::string_view abi, bool extractNativeLibs) { auto start = Clock::now(); const auto ifs = getIfs(storage); @@ -1415,6 +1423,21 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ continue; } + if (!extractNativeLibs) { + // ensure the file is properly aligned and unpacked + if (entry.method != kCompressStored) { + LOG(WARNING) << "Library " << fileName << " must be uncompressed to mmap it"; + return false; + } + if ((entry.offset & (constants().blockSize - 1)) != 0) { + LOG(WARNING) << "Library " << fileName + << " must be page-aligned to mmap it, offset = 0x" << std::hex + << entry.offset; + return false; + } + continue; + } + auto startFileTs = Clock::now(); const auto libName = path::basename(fileName); @@ -1680,19 +1703,24 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { IncrementalService::DataLoaderStub::DataLoaderStub(IncrementalService& service, MountId id, DataLoaderParamsParcel&& params, FileSystemControlParcel&& control, - const DataLoaderStatusListener* externalListener, + const DataLoaderStatusListener* statusListener, + StorageHealthCheckParams&& healthCheckParams, + const StorageHealthListener* healthListener, std::string&& healthPath) : mService(service), mId(id), mParams(std::move(params)), mControl(std::move(control)), - mListener(externalListener ? *externalListener : DataLoaderStatusListener()), + mStatusListener(statusListener ? *statusListener : DataLoaderStatusListener()), + mHealthListener(healthListener ? *healthListener : StorageHealthListener()), mHealthPath(std::move(healthPath)) { + // TODO(b/153874006): enable external health listener. + mHealthListener = {}; healthStatusOk(); } IncrementalService::DataLoaderStub::~DataLoaderStub() { - if (mId != kInvalidStorageId) { + if (isValid()) { cleanupResources(); } } @@ -1710,13 +1738,14 @@ void IncrementalService::DataLoaderStub::cleanupResources() { mStatusCondition.wait_until(lock, now + 60s, [this] { return mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED; }); - mListener = {}; + mStatusListener = {}; + mHealthListener = {}; mId = kInvalidStorageId; } sp<content::pm::IDataLoader> IncrementalService::DataLoaderStub::getDataLoader() { sp<IDataLoader> dataloader; - auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); + auto status = mService.mDataLoaderManager->getDataLoader(id(), &dataloader); if (!status.isOk()) { LOG(ERROR) << "Failed to get dataloader: " << status.toString8(); return {}; @@ -1752,15 +1781,15 @@ void IncrementalService::DataLoaderStub::setTargetStatusLocked(int status) { auto oldStatus = mTargetStatus; mTargetStatus = status; mTargetStatusTs = Clock::now(); - LOG(DEBUG) << "Target status update for DataLoader " << mId << ": " << oldStatus << " -> " + LOG(DEBUG) << "Target status update for DataLoader " << id() << ": " << oldStatus << " -> " << status << " (current " << mCurrentStatus << ")"; } bool IncrementalService::DataLoaderStub::bind() { bool result = false; - auto status = mService.mDataLoaderManager->bindToDataLoader(mId, mParams, this, &result); + auto status = mService.mDataLoaderManager->bindToDataLoader(id(), mParams, this, &result); if (!status.isOk() || !result) { - LOG(ERROR) << "Failed to bind a data loader for mount " << mId; + LOG(ERROR) << "Failed to bind a data loader for mount " << id(); return false; } return true; @@ -1771,9 +1800,9 @@ bool IncrementalService::DataLoaderStub::create() { if (!dataloader) { return false; } - auto status = dataloader->create(mId, mParams, mControl, this); + auto status = dataloader->create(id(), mParams, mControl, this); if (!status.isOk()) { - LOG(ERROR) << "Failed to start DataLoader: " << status.toString8(); + LOG(ERROR) << "Failed to create DataLoader: " << status.toString8(); return false; } return true; @@ -1784,7 +1813,7 @@ bool IncrementalService::DataLoaderStub::start() { if (!dataloader) { return false; } - auto status = dataloader->start(mId); + auto status = dataloader->start(id()); if (!status.isOk()) { LOG(ERROR) << "Failed to start DataLoader: " << status.toString8(); return false; @@ -1793,7 +1822,7 @@ bool IncrementalService::DataLoaderStub::start() { } bool IncrementalService::DataLoaderStub::destroy() { - return mService.mDataLoaderManager->unbindFromDataLoader(mId).isOk(); + return mService.mDataLoaderManager->unbindFromDataLoader(id()).isOk(); } bool IncrementalService::DataLoaderStub::fsmStep() { @@ -1852,8 +1881,8 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount return binder::Status:: fromServiceSpecificError(-EINVAL, "onStatusChange came to invalid DataLoaderStub"); } - if (mId != mountId) { - LOG(ERROR) << "Mount ID mismatch: expected " << mId << ", but got: " << mountId; + if (id() != mountId) { + LOG(ERROR) << "Mount ID mismatch: expected " << id() << ", but got: " << mountId; return binder::Status::fromServiceSpecificError(-EPERM, "Mount ID mismatch."); } @@ -1869,7 +1898,7 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount mCurrentStatus = newStatus; targetStatus = mTargetStatus; - listener = mListener; + listener = mStatusListener; if (mCurrentStatus == IDataLoaderStatusListener::DATA_LOADER_UNAVAILABLE) { // For unavailable, unbind from DataLoader to ensure proper re-commit. @@ -1877,7 +1906,7 @@ binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mount } } - LOG(DEBUG) << "Current status update for DataLoader " << mId << ": " << oldStatus << " -> " + LOG(DEBUG) << "Current status update for DataLoader " << id() << ": " << oldStatus << " -> " << newStatus << " (target " << targetStatus << ")"; if (listener) { diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index f3fde2a413e8..05f62b977a85 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -21,6 +21,8 @@ #include <android/content/pm/FileSystemControlParcel.h> #include <android/content/pm/IDataLoaderStatusListener.h> #include <android/os/incremental/BnIncrementalServiceConnector.h> +#include <android/os/incremental/BnStorageHealthListener.h> +#include <android/os/incremental/StorageHealthCheckParams.h> #include <binder/IAppOpsCallback.h> #include <utils/String16.h> #include <utils/StrongPointer.h> @@ -56,10 +58,15 @@ using RawMetadata = incfs::RawMetadata; using Clock = std::chrono::steady_clock; using TimePoint = std::chrono::time_point<Clock>; using Seconds = std::chrono::seconds; +using BootClockTsUs = uint64_t; using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener; using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>; +using StorageHealthCheckParams = ::android::os::incremental::StorageHealthCheckParams; +using IStorageHealthListener = ::android::os::incremental::IStorageHealthListener; +using StorageHealthListener = ::android::sp<IStorageHealthListener>; + class IncrementalService final { public: explicit IncrementalService(ServiceManagerWrapper&& sm, std::string_view rootDir); @@ -72,6 +79,8 @@ public: static constexpr StorageId kInvalidStorageId = -1; static constexpr StorageId kMaxStorageId = std::numeric_limits<int>::max(); + static constexpr BootClockTsUs kMaxBootClockTsUs = std::numeric_limits<BootClockTsUs>::max(); + enum CreateOptions { TemporaryBind = 1, PermanentBind = 2, @@ -97,8 +106,9 @@ public: StorageId createStorage(std::string_view mountPoint, content::pm::DataLoaderParamsParcel&& dataLoaderParams, - const DataLoaderStatusListener& dataLoaderStatusListener, - CreateOptions options = CreateOptions::Default); + CreateOptions options, const DataLoaderStatusListener& statusListener, + StorageHealthCheckParams&& healthCheckParams, + const StorageHealthListener& healthListener); StorageId createLinkedStorage(std::string_view mountPoint, StorageId linkedStorage, CreateOptions options = CreateOptions::Default); StorageId openStorage(std::string_view path); @@ -128,7 +138,8 @@ public: bool startLoading(StorageId storage) const; bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, - std::string_view libDirRelativePath, std::string_view abi); + std::string_view libDirRelativePath, std::string_view abi, + bool extractNativeLibs); bool waitForNativeBinariesExtraction(StorageId storage); class AppOpsListener : public android::BnAppOpsCallback { @@ -161,7 +172,9 @@ private: DataLoaderStub(IncrementalService& service, MountId id, content::pm::DataLoaderParamsParcel&& params, content::pm::FileSystemControlParcel&& control, - const DataLoaderStatusListener* externalListener, std::string&& healthPath); + const DataLoaderStatusListener* statusListener, + StorageHealthCheckParams&& healthCheckParams, + const StorageHealthListener* healthListener, std::string&& healthPath); ~DataLoaderStub(); // Cleans up the internal state and invalidates DataLoaderStub. Any subsequent calls will // result in an error. @@ -212,7 +225,8 @@ private: MountId mId = kInvalidStorageId; content::pm::DataLoaderParamsParcel mParams; content::pm::FileSystemControlParcel mControl; - DataLoaderStatusListener mListener; + DataLoaderStatusListener mStatusListener; + StorageHealthListener mHealthListener; std::condition_variable mStatusCondition; int mCurrentStatus = content::pm::IDataLoaderStatusListener::DATA_LOADER_DESTROYED; @@ -291,9 +305,13 @@ private: DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params, - const DataLoaderStatusListener* externalListener = nullptr); + const DataLoaderStatusListener* statusListener = nullptr, + StorageHealthCheckParams&& healthCheckParams = {}, + const StorageHealthListener* healthListener = nullptr); void prepareDataLoaderLocked(IncFsMount& ifs, content::pm::DataLoaderParamsParcel&& params, - const DataLoaderStatusListener* externalListener = nullptr); + const DataLoaderStatusListener* statusListener = nullptr, + StorageHealthCheckParams&& healthCheckParams = {}, + const StorageHealthListener* healthListener = nullptr); BindPathMap::const_iterator findStorageLocked(std::string_view path) const; StorageId findStorageId(std::string_view path) const; diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 08fb486c8058..a76aa625ebc6 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -175,6 +175,10 @@ public: ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const final { return incfs::writeBlocks({blocks.data(), size_t(blocks.size())}); } + WaitResult waitForPendingReads(const Control& control, std::chrono::milliseconds timeout, + std::vector<incfs::ReadInfo>* pendingReadsBuffer) const final { + return incfs::waitForPendingReads(control, timeout, pendingReadsBuffer); + } }; RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env) diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index abbf2f4c4424..a935ab99267e 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -69,6 +69,7 @@ public: using Control = incfs::Control; using FileId = incfs::FileId; using ErrorCode = incfs::ErrorCode; + using WaitResult = incfs::WaitResult; using ExistingMountCallback = std::function<void(std::string_view root, std::string_view backingDir, @@ -90,6 +91,9 @@ public: virtual ErrorCode unlink(const Control& control, std::string_view path) const = 0; virtual base::unique_fd openForSpecialOps(const Control& control, FileId id) const = 0; virtual ErrorCode writeBlocks(std::span<const incfs::DataBlock> blocks) const = 0; + virtual WaitResult waitForPendingReads( + const Control& control, std::chrono::milliseconds timeout, + std::vector<incfs::ReadInfo>* pendingReadsBuffer) const = 0; }; class AppOpsManagerWrapper { diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 2e4625cf85a1..2948b6a0f293 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -284,6 +284,9 @@ public: MOCK_CONST_METHOD2(unlink, ErrorCode(const Control& control, std::string_view path)); MOCK_CONST_METHOD2(openForSpecialOps, base::unique_fd(const Control& control, FileId id)); MOCK_CONST_METHOD1(writeBlocks, ErrorCode(std::span<const DataBlock> blocks)); + MOCK_CONST_METHOD3(waitForPendingReads, + WaitResult(const Control& control, std::chrono::milliseconds timeout, + std::vector<incfs::ReadInfo>* pendingReadsBuffer)); MockIncFs() { ON_CALL(*this, listExistingMounts(_)).WillByDefault(Return()); } @@ -292,12 +295,23 @@ public: void openMountSuccess() { ON_CALL(*this, openMount(_)).WillByDefault(Invoke(this, &MockIncFs::openMountForHealth)); } + void waitForPendingReadsSuccess() { + ON_CALL(*this, waitForPendingReads(_, _, _)) + .WillByDefault(Invoke(this, &MockIncFs::waitForPendingReadsForHealth)); + } static constexpr auto kPendingReadsFd = 42; Control openMountForHealth(std::string_view) { return UniqueControl(IncFs_CreateControl(-1, kPendingReadsFd, -1)); } + WaitResult waitForPendingReadsForHealth( + const Control& control, std::chrono::milliseconds timeout, + std::vector<incfs::ReadInfo>* pendingReadsBuffer) const { + pendingReadsBuffer->push_back({.bootClockTsUs = 0}); + return android::incfs::WaitResult::HaveData; + } + RawMetadata getMountInfoMetadata(const Control& control, std::string_view path) { metadata::Mount m; m.mutable_storage()->set_id(100); @@ -499,9 +513,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) { mVold->mountIncFsFails(); EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_LT(storageId, 0); } @@ -510,9 +524,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) EXPECT_CALL(*mDataLoaderManager, bindToDataLoader(_, _, _, _)).Times(0); EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_LT(storageId, 0); } @@ -523,9 +537,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) { EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_LT(storageId, 0); } @@ -537,9 +551,9 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) { EXPECT_CALL(*mDataLoaderManager, unbindFromDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_LT(storageId, 0); } @@ -555,9 +569,9 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_LT(storageId, 0); } @@ -574,9 +588,9 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); mIncrementalService->deleteStorage(storageId); } @@ -594,9 +608,9 @@ TEST_F(IncrementalServiceTest, testDataLoaderDestroyed) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); // Simulated crash/other connection breakage. mDataLoaderManager->setDataLoaderStatusDestroyed(); @@ -616,9 +630,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreate) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusCreated(); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); @@ -639,9 +653,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderPendingStart) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); ASSERT_TRUE(mIncrementalService->startLoading(storageId)); mDataLoaderManager->setDataLoaderStatusCreated(); @@ -661,9 +675,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderCreateUnavailable) { EXPECT_CALL(*mDataLoader, destroy(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusUnavailable(); } @@ -672,6 +686,7 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) { mVold->mountIncFsSuccess(); mIncFs->makeFileSuccess(); mIncFs->openMountSuccess(); + mIncFs->waitForPendingReadsSuccess(); mVold->bindMountSuccess(); mDataLoader->initializeCreateOkNoStatus(); mDataLoaderManager->bindToDataLoaderSuccess(); @@ -685,9 +700,9 @@ TEST_F(IncrementalServiceTest, testStartDataLoaderRecreateOnPendingReads) { EXPECT_CALL(*mLooper, addFd(MockIncFs::kPendingReadsFd, _, _, _, _)).Times(1); EXPECT_CALL(*mLooper, removeFd(MockIncFs::kPendingReadsFd)).Times(1); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); mDataLoaderManager->setDataLoaderStatusUnavailable(); ASSERT_NE(nullptr, mLooper->mCallback); @@ -712,9 +727,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccess) { // Not expecting callback removal. EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); ASSERT_GE(mDataLoader->setStorageParams(true), 0); } @@ -739,9 +754,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsSuccessAndPermissionChang // After callback is called, disable read logs and remove callback. EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(1); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); ASSERT_GE(mDataLoader->setStorageParams(true), 0); ASSERT_NE(nullptr, mAppOpsManager->mStoredCallback.get()); @@ -762,9 +777,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsCheckPermissionFails) { EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0); EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); ASSERT_LT(mDataLoader->setStorageParams(true), 0); } @@ -785,9 +800,9 @@ TEST_F(IncrementalServiceTest, testSetIncFsMountOptionsFails) { EXPECT_CALL(*mAppOpsManager, startWatchingMode(_, _, _)).Times(0); EXPECT_CALL(*mAppOpsManager, stopWatchingMode(_)).Times(0); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); ASSERT_GE(storageId, 0); ASSERT_LT(mDataLoader->setStorageParams(true), 0); } @@ -799,9 +814,9 @@ TEST_F(IncrementalServiceTest, testMakeDirectory) { mDataLoaderManager->bindToDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); std::string dir_path("test"); // Expecting incfs to call makeDir on a path like: @@ -823,9 +838,9 @@ TEST_F(IncrementalServiceTest, testMakeDirectories) { mDataLoaderManager->bindToDataLoaderSuccess(); mDataLoaderManager->getDataLoaderSuccess(); TemporaryDir tempDir; - int storageId = - mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, - IncrementalService::CreateOptions::CreateNew); + int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), + IncrementalService::CreateOptions::CreateNew, + {}, {}, {}); auto first = "first"sv; auto second = "second"sv; auto third = "third"sv; diff --git a/services/people/java/com/android/server/people/data/ConversationInfo.java b/services/people/java/com/android/server/people/data/ConversationInfo.java index dc3fa2a048f6..17378285276f 100644 --- a/services/people/java/com/android/server/people/data/ConversationInfo.java +++ b/services/people/java/com/android/server/people/data/ConversationInfo.java @@ -142,9 +142,12 @@ public class ConversationInfo { return hasShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED); } - /** Whether the shortcut for this conversation is cached in Shortcut Service. */ - public boolean isShortcutCached() { - return hasShortcutFlags(ShortcutInfo.FLAG_CACHED); + /** + * Whether the shortcut for this conversation is cached in Shortcut Service, with cache owner + * set as notifications. + */ + public boolean isShortcutCachedForNotification() { + return hasShortcutFlags(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); } /** Whether this conversation is marked as important by the user. */ @@ -223,7 +226,7 @@ public class ConversationInfo { if (isShortcutLongLived()) { sb.append("Liv"); } - if (isShortcutCached()) { + if (isShortcutCachedForNotification()) { sb.append("Cac"); } sb.append("]"); diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java index bbb0215788fb..63b716206313 100644 --- a/services/people/java/com/android/server/people/data/DataManager.java +++ b/services/people/java/com/android/server/people/data/DataManager.java @@ -294,14 +294,14 @@ public class DataManager { if (notificationListener != null) { String packageName = packageData.getPackageName(); packageData.forAllConversations(conversationInfo -> { - if (conversationInfo.isShortcutCached() + if (conversationInfo.isShortcutCachedForNotification() && conversationInfo.getNotificationChannelId() == null && !notificationListener.hasActiveNotifications( packageName, conversationInfo.getShortcutId())) { mShortcutServiceInternal.uncacheShortcuts(userId, mContext.getPackageName(), packageName, Collections.singletonList(conversationInfo.getShortcutId()), - userId); + userId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); } }); } @@ -821,12 +821,12 @@ public class DataManager { // The shortcut was cached by Notification Manager synchronously when the // associated notification was posted. Uncache it here when all the // associated notifications are removed. - if (conversationInfo.isShortcutCached() + if (conversationInfo.isShortcutCachedForNotification() && conversationInfo.getNotificationChannelId() == null) { mShortcutServiceInternal.uncacheShortcuts(mUserId, mContext.getPackageName(), sbn.getPackageName(), Collections.singletonList(conversationInfo.getShortcutId()), - mUserId); + mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); } } else { mActiveNotifCounts.put(conversationKey, count); @@ -891,12 +891,12 @@ public class DataManager { ConversationInfo conversationInfo = packageData != null ? packageData.getConversationInfo(shortcutId) : null; if (conversationInfo != null - && conversationInfo.isShortcutCached() + && conversationInfo.isShortcutCachedForNotification() && conversationInfo.getNotificationChannelId() == null) { mShortcutServiceInternal.uncacheShortcuts(mUserId, mContext.getPackageName(), packageName, Collections.singletonList(shortcutId), - mUserId); + mUserId, ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); } } } diff --git a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java index d338b587e059..7446289cd498 100644 --- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java @@ -19,7 +19,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealM 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; -import static com.android.server.blob.BlobStoreConfig.SESSION_EXPIRY_TIMEOUT_MILLIS; +import static com.android.server.blob.BlobStoreConfig.DeviceConfigProperties.SESSION_EXPIRY_TIMEOUT_MS; import static com.google.common.truth.Truth.assertThat; @@ -93,6 +93,7 @@ public class BlobStoreManagerServiceTest { doReturn(true).when(mBlobsDir).exists(); doReturn(new File[0]).when(mBlobsDir).listFiles(); doReturn(true).when(() -> BlobStoreConfig.hasLeaseWaitTimeElapsed(anyLong())); + doCallRealMethod().when(() -> BlobStoreConfig.hasSessionExpired(anyLong())); mContext = InstrumentationRegistry.getTargetContext(); mHandler = new TestHandler(Looper.getMainLooper()); @@ -236,7 +237,7 @@ public class BlobStoreManagerServiceTest { public void testHandleIdleMaintenance_deleteStaleSessions() throws Exception { // Setup sessions final File sessionFile1 = mock(File.class); - doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS + 1000) + doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS + 1000) .when(sessionFile1).lastModified(); final long sessionId1 = 342; final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(), @@ -256,7 +257,7 @@ public class BlobStoreManagerServiceTest { mUserSessions.append(sessionId2, session2); final File sessionFile3 = mock(File.class); - doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MILLIS - 2000) + doReturn(System.currentTimeMillis() - SESSION_EXPIRY_TIMEOUT_MS - 2000) .when(sessionFile3).lastModified(); final long sessionId3 = 9484; final BlobHandle blobHandle3 = BlobHandle.createWithSha256("digest3".getBytes(), @@ -371,6 +372,7 @@ public class BlobStoreManagerServiceTest { doReturn(sessionId).when(session).getSessionId(); doReturn(sessionFile).when(session).getSessionFile(); doReturn(blobHandle).when(session).getBlobHandle(); + doCallRealMethod().when(session).isExpired(); return session; } diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java index 724048b1b8ee..4a774898e1b5 100644 --- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java @@ -1997,19 +1997,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_GLOBAL_RESTRICTIONS = Sets.newSet( - UserManager.DISALLOW_CONFIG_DATE_TIME, - UserManager.DISALLOW_BLUETOOTH_SHARING, - UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, - UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, - UserManager.DISALLOW_CONFIG_PRIVATE_DNS, - UserManager.DISALLOW_CONFIG_TETHERING, - UserManager.DISALLOW_DATA_ROAMING, - UserManager.DISALLOW_SAFE_BOOT, - UserManager.DISALLOW_SMS, - UserManager.DISALLOW_USB_FILE_TRANSFER, UserManager.DISALLOW_AIRPLANE_MODE, - UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, - UserManager.DISALLOW_UNMUTE_MICROPHONE + UserManager.DISALLOW_CONFIG_DATE_TIME, + UserManager.DISALLOW_CONFIG_PRIVATE_DNS ); private static final Set<String> PROFILE_OWNER_ORGANIZATION_OWNED_LOCAL_RESTRICTIONS = @@ -2021,7 +2011,17 @@ public class DevicePolicyManagerTest extends DpmTestBase { UserManager.DISALLOW_CONTENT_SUGGESTIONS, UserManager.DISALLOW_DEBUGGING_FEATURES, UserManager.DISALLOW_SHARE_LOCATION, - UserManager.DISALLOW_OUTGOING_CALLS + UserManager.DISALLOW_OUTGOING_CALLS, + UserManager.DISALLOW_BLUETOOTH_SHARING, + UserManager.DISALLOW_CONFIG_CELL_BROADCASTS, + UserManager.DISALLOW_CONFIG_MOBILE_NETWORKS, + UserManager.DISALLOW_CONFIG_TETHERING, + UserManager.DISALLOW_DATA_ROAMING, + UserManager.DISALLOW_SAFE_BOOT, + UserManager.DISALLOW_SMS, + UserManager.DISALLOW_USB_FILE_TRANSFER, + UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, + UserManager.DISALLOW_UNMUTE_MICROPHONE ); public void testSetUserRestriction_asPoOfOrgOwnedDevice() throws Exception { @@ -2045,8 +2045,9 @@ public class DevicePolicyManagerTest extends DpmTestBase { parentDpm.setCameraDisabled(admin1, true); verify(getServices().userManagerInternal).setDevicePolicyUserRestrictions( eq(CALLER_USER_HANDLE), - MockUtils.checkUserRestrictions(UserManager.DISALLOW_CAMERA), - MockUtils.checkUserRestrictions(CALLER_USER_HANDLE), + MockUtils.checkUserRestrictions(), + MockUtils.checkUserRestrictions(UserHandle.USER_SYSTEM, + UserManager.DISALLOW_CAMERA), eq(false)); DpmTestUtils.assertRestrictions( DpmTestUtils.newRestrictions(UserManager.DISALLOW_CAMERA), diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java index f35eecf05f32..b7692f912e39 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplRebootTests.java @@ -44,9 +44,9 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testUpdateOverlaysForUser() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); - installTargetPackage("some.other.target", USER); - installOverlayPackage(OVERLAY, TARGET, USER); + addSystemPackage(target(TARGET), USER); + addSystemPackage(target("some.other.target"), USER);; + addSystemPackage(overlay(OVERLAY, TARGET), USER); // do nothing, expect no change final List<String> a = impl.updateOverlaysForUser(USER); @@ -54,8 +54,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(a.contains(TARGET)); // upgrade overlay, keep target - beginUpgradeOverlayPackage(OVERLAY, USER); - endUpgradeOverlayPackage(OVERLAY, TARGET, USER); + addSystemPackage(overlay(OVERLAY, TARGET), USER); final List<String> b = impl.updateOverlaysForUser(USER); assertEquals(1, b.size()); @@ -67,7 +66,7 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI assertTrue(c.contains(TARGET)); // upgrade overlay, switch to new target - addOverlayPackage(OVERLAY, "some.other.target", USER, true, false, 0); + addSystemPackage(overlay(OVERLAY, "some.other.target"), USER); final List<String> d = impl.updateOverlaysForUser(USER); assertEquals(2, d.size()); assertTrue(d.containsAll(Arrays.asList(TARGET, "some.other.target"))); @@ -81,23 +80,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testImmutableEnabledChange() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); - addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0); + configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o1); assertFalse(o1.isEnabled()); assertFalse(o1.isMutable); - addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0); + configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o2); assertTrue(o2.isEnabled()); assertFalse(o2.isMutable); - addOverlayPackage(OVERLAY, TARGET, USER, false, false, 0); + configureSystemOverlay(OVERLAY, false /* mutable */, false /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o3); @@ -108,23 +108,24 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testMutableEnabledChangeHasNoEffect() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); + configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); - addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0); impl.updateOverlaysForUser(USER); final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o1); assertFalse(o1.isEnabled()); assertTrue(o1.isMutable); - addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0); + configureSystemOverlay(OVERLAY, true /* mutable */, true /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o2); assertFalse(o2.isEnabled()); assertTrue(o2.isMutable); - addOverlayPackage(OVERLAY, TARGET, USER, true, false, 0); + configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o3); @@ -135,15 +136,16 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testMutableEnabledToImmutableEnabled() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); final BiConsumer<Boolean, Boolean> setOverlay = (mutable, enabled) -> { - addOverlayPackage(OVERLAY, TARGET, USER, mutable, enabled, 0); + configureSystemOverlay(OVERLAY, mutable, enabled, 0 /* priority */); impl.updateOverlaysForUser(USER); - final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); - assertNotNull(o1); - assertEquals(enabled, o1.isEnabled()); - assertEquals(mutable, o1.isMutable); + final OverlayInfo o = impl.getOverlayInfo(OVERLAY, USER); + assertNotNull(o); + assertEquals(enabled, o.isEnabled()); + assertEquals(mutable, o.isMutable); }; // Immutable/enabled -> mutable/enabled @@ -178,70 +180,76 @@ public class OverlayManagerServiceImplRebootTests extends OverlayManagerServiceI @Test public void testMutablePriorityChange() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); - addOverlayPackage(OVERLAY, TARGET, USER, true, true, 0); - addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 1); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); + installNewPackage(overlay(OVERLAY2, TARGET), USER); + configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 0 /* priority */); + configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 1 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o1); assertEquals(0, o1.priority); + assertFalse(o1.isEnabled()); final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER); assertNotNull(o2); assertEquals(1, o2.priority); + assertFalse(o2.isEnabled()); // Overlay priority changing between reboots should not affect enable state of mutable - // overlays + // overlays. impl.setEnabled(OVERLAY, true, USER); // Reorder the overlays - addOverlayPackage(OVERLAY, TARGET, USER, true, true, 1); - addOverlayPackage(OVERLAY2, TARGET, USER, true, true, 0); + configureSystemOverlay(OVERLAY, true /* mutable */, false /* enabled */, 1 /* priority */); + configureSystemOverlay(OVERLAY2, true /* mutable */, false /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o3); assertEquals(1, o3.priority); + assertTrue(o3.isEnabled()); final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER); assertNotNull(o4); assertEquals(0, o4.priority); - assertTrue(o1.isEnabled()); + assertFalse(o4.isEnabled()); } @Test public void testImmutablePriorityChange() { final OverlayManagerServiceImpl impl = getImpl(); - installTargetPackage(TARGET, USER); - addOverlayPackage(OVERLAY, TARGET, USER, false, true, 0); - addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 1); + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); + installNewPackage(overlay(OVERLAY2, TARGET), USER); + configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 0 /* priority */); + configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 1 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o1); assertEquals(0, o1.priority); + assertTrue(o1.isEnabled()); final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER); assertNotNull(o2); assertEquals(1, o2.priority); - - // Overlay priority changing between reboots should not affect enable state of mutable - // overlays - impl.setEnabled(OVERLAY, true, USER); + assertTrue(o2.isEnabled()); // Reorder the overlays - addOverlayPackage(OVERLAY, TARGET, USER, false, true, 1); - addOverlayPackage(OVERLAY2, TARGET, USER, false, true, 0); + configureSystemOverlay(OVERLAY, false /* mutable */, true /* enabled */, 1 /* priority */); + configureSystemOverlay(OVERLAY2, false /* mutable */, true /* enabled */, 0 /* priority */); impl.updateOverlaysForUser(USER); final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY, USER); assertNotNull(o3); assertEquals(1, o3.priority); + assertTrue(o3.isEnabled()); final OverlayInfo o4 = impl.getOverlayInfo(OVERLAY2, USER); assertNotNull(o4); assertEquals(0, o4.priority); - assertTrue(o1.isEnabled()); + assertTrue(o4.isEnabled()); } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java index cd7343235750..b25af0543829 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTests.java @@ -26,6 +26,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import android.content.om.OverlayInfo; +import android.os.OverlayablePolicy; import androidx.test.runner.AndroidJUnit4; @@ -49,11 +50,9 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes private static final String OVERLAY3 = OVERLAY + "3"; private static final int USER3 = USER2 + 1; - // tests: basics - @Test - public void testGetOverlayInfo() throws Exception { - installOverlayPackage(OVERLAY, TARGET, USER); + public void testGetOverlayInfo() { + installNewPackage(overlay(OVERLAY, TARGET), USER); final OverlayManagerServiceImpl impl = getImpl(); final OverlayInfo oi = impl.getOverlayInfo(OVERLAY, USER); @@ -64,10 +63,10 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testGetOverlayInfosForTarget() throws Exception { - installOverlayPackage(OVERLAY, TARGET, USER); - installOverlayPackage(OVERLAY2, TARGET, USER); - installOverlayPackage(OVERLAY3, TARGET, USER2); + public void testGetOverlayInfosForTarget() { + installNewPackage(overlay(OVERLAY, TARGET), USER); + installNewPackage(overlay(OVERLAY2, TARGET), USER); + installNewPackage(overlay(OVERLAY3, TARGET), USER2); final OverlayManagerServiceImpl impl = getImpl(); final List<OverlayInfo> ois = impl.getOverlayInfosForTarget(TARGET, USER); @@ -89,11 +88,11 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testGetOverlayInfosForUser() throws Exception { - installTargetPackage(TARGET, USER); - installOverlayPackage(OVERLAY, TARGET, USER); - installOverlayPackage(OVERLAY2, TARGET, USER); - installOverlayPackage(OVERLAY3, TARGET2, USER); + public void testGetOverlayInfosForUser() { + installNewPackage(target(TARGET), USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); + installNewPackage(overlay(OVERLAY2, TARGET), USER); + installNewPackage(overlay(OVERLAY3, TARGET2), USER); final OverlayManagerServiceImpl impl = getImpl(); final Map<String, List<OverlayInfo>> everything = impl.getOverlaysForUser(USER); @@ -116,91 +115,86 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes } @Test - public void testPriority() throws Exception { - installOverlayPackage(OVERLAY, TARGET, USER); - installOverlayPackage(OVERLAY2, TARGET, USER); - installOverlayPackage(OVERLAY3, TARGET, USER); + public void testPriority() { + installNewPackage(overlay(OVERLAY, TARGET), USER); + installNewPackage(overlay(OVERLAY2, TARGET), USER); + installNewPackage(overlay(OVERLAY3, TARGET), USER); final OverlayManagerServiceImpl impl = getImpl(); final OverlayInfo o1 = impl.getOverlayInfo(OVERLAY, USER); final OverlayInfo o2 = impl.getOverlayInfo(OVERLAY2, USER); final OverlayInfo o3 = impl.getOverlayInfo(OVERLAY3, USER); - assertOverlayInfoList(TARGET, USER, o1, o2, o3); + assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3); assertTrue(impl.setLowestPriority(OVERLAY3, USER)); - assertOverlayInfoList(TARGET, USER, o3, o1, o2); + assertOverlayInfoForTarget(TARGET, USER, o3, o1, o2); assertTrue(impl.setHighestPriority(OVERLAY3, USER)); - assertOverlayInfoList(TARGET, USER, o1, o2, o3); + assertOverlayInfoForTarget(TARGET, USER, o1, o2, o3); assertTrue(impl.setPriority(OVERLAY, OVERLAY2, USER)); - assertOverlayInfoList(TARGET, USER, o2, o1, o3); + assertOverlayInfoForTarget(TARGET, USER, o2, o1, o3); } @Test - public void testOverlayInfoStateTransitions() throws Exception { + public void testOverlayInfoStateTransitions() { final OverlayManagerServiceImpl impl = getImpl(); assertNull(impl.getOverlayInfo(OVERLAY, USER)); - installOverlayPackage(OVERLAY, TARGET, USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); assertState(STATE_MISSING_TARGET, OVERLAY, USER); - installTargetPackage(TARGET, USER); + final DummyDeviceState.PackageBuilder target = target(TARGET); + installNewPackage(target, USER); assertState(STATE_DISABLED, OVERLAY, USER); impl.setEnabled(OVERLAY, true, USER); assertState(STATE_ENABLED, OVERLAY, USER); // target upgrades do not change the state of the overlay - beginUpgradeTargetPackage(TARGET, USER); - assertState(STATE_ENABLED, OVERLAY, USER); - - endUpgradeTargetPackage(TARGET, USER); + upgradePackage(target, USER); assertState(STATE_ENABLED, OVERLAY, USER); - uninstallTargetPackage(TARGET, USER); + uninstallPackage(TARGET, USER); assertState(STATE_MISSING_TARGET, OVERLAY, USER); - installTargetPackage(TARGET, USER); + installNewPackage(target, USER); assertState(STATE_ENABLED, OVERLAY, USER); } @Test - public void testOnOverlayPackageUpgraded() throws Exception { - final OverlayManagerServiceImpl impl = getImpl(); + public void testOnOverlayPackageUpgraded() { final DummyListener listener = getListener(); - installTargetPackage(TARGET, USER); - installOverlayPackage(OVERLAY, TARGET, USER); - impl.onOverlayPackageReplacing(OVERLAY, USER); + final DummyDeviceState.PackageBuilder target = target(TARGET); + final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET); + installNewPackage(target, USER); + installNewPackage(overlay, USER); listener.count = 0; - impl.onOverlayPackageReplaced(OVERLAY, USER); - assertEquals(1, listener.count); + upgradePackage(overlay, USER); + assertEquals(2, listener.count); // upgrade to a version where the overlay has changed its target - beginUpgradeOverlayPackage(OVERLAY, USER); - listener.count = 0; - endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER); // expect once for the old target package, once for the new target package - assertEquals(2, listener.count); + listener.count = 0; + final DummyDeviceState.PackageBuilder overlay2 = overlay(OVERLAY, "some.other.target"); + upgradePackage(overlay2, USER); + assertEquals(3, listener.count); - beginUpgradeOverlayPackage(OVERLAY, USER); listener.count = 0; - endUpgradeOverlayPackage(OVERLAY, "some.other.target", USER); - assertEquals(1, listener.count); + upgradePackage(overlay2, USER); + assertEquals(2, listener.count); } - // tests: listener interface - @Test - public void testListener() throws Exception { + public void testListener() { final OverlayManagerServiceImpl impl = getImpl(); final DummyListener listener = getListener(); - installOverlayPackage(OVERLAY, TARGET, USER); + installNewPackage(overlay(OVERLAY, TARGET), USER); assertEquals(1, listener.count); listener.count = 0; - installTargetPackage(TARGET, USER); + installNewPackage(target(TARGET), USER); assertEquals(1, listener.count); listener.count = 0; @@ -211,4 +205,49 @@ public class OverlayManagerServiceImplTests extends OverlayManagerServiceImplTes impl.setEnabled(OVERLAY, true, USER); assertEquals(0, listener.count); } + + @Test + public void testConfigurator() { + final DummyPackageManagerHelper packageManager = getPackageManager(); + packageManager.overlayableConfigurator = "actor"; + packageManager.overlayableConfiguratorTargets = new String[]{TARGET}; + reinitializeImpl(); + + installNewPackage(target("actor").setCertificate("one"), USER); + installNewPackage(target(TARGET) + .addOverlayable("TestResources") + .setCertificate("two"), USER); + + final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources") + .setCertificate("one"); + installNewPackage(overlay, USER); + + final DummyIdmapDaemon idmapDaemon = getIdmapDaemon(); + final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath); + assertNotNull(idmap); + assertEquals(OverlayablePolicy.ACTOR_SIGNATURE, + idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE); + } + + @Test + public void testConfiguratorDifferentSignatures() { + final DummyPackageManagerHelper packageManager = getPackageManager(); + packageManager.overlayableConfigurator = "actor"; + packageManager.overlayableConfiguratorTargets = new String[]{TARGET}; + reinitializeImpl(); + + installNewPackage(target("actor").setCertificate("one"), USER); + installNewPackage(target(TARGET) + .addOverlayable("TestResources") + .setCertificate("two"), USER); + + final DummyDeviceState.PackageBuilder overlay = overlay(OVERLAY, TARGET, "TestResources") + .setCertificate("two"); + installNewPackage(overlay, USER); + + final DummyIdmapDaemon idmapDaemon = getIdmapDaemon(); + final DummyIdmapDaemon.IdmapHeader idmap = idmapDaemon.getIdmap(overlay.build().apkPath); + assertNotNull(idmap); + assertEquals(0, idmap.policies & OverlayablePolicy.ACTOR_SIGNATURE); + } } diff --git a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java index 9eda718ed922..ec6a48182a25 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -17,6 +17,7 @@ package com.android.server.om; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -26,17 +27,19 @@ import android.content.om.OverlayInfo.State; import android.content.om.OverlayableInfo; import android.content.pm.ApplicationInfo; import android.content.pm.PackageInfo; +import android.util.ArrayMap; import android.util.ArraySet; import androidx.annotation.Nullable; import com.android.internal.content.om.OverlayConfig; +import org.junit.Assert; import org.junit.Before; import java.util.ArrayList; import java.util.Arrays; -import java.util.Iterator; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Set; @@ -47,29 +50,48 @@ class OverlayManagerServiceImplTestsBase { private OverlayManagerServiceImpl mImpl; private DummyDeviceState mState; private DummyListener mListener; + private DummyPackageManagerHelper mPackageManager; + private DummyIdmapDaemon mIdmapDaemon; + private OverlayConfig mOverlayConfig; @Before public void setUp() { mState = new DummyDeviceState(); mListener = new DummyListener(); - final DummyPackageManagerHelper pmh = new DummyPackageManagerHelper(mState); + mPackageManager = new DummyPackageManagerHelper(mState); + mIdmapDaemon = new DummyIdmapDaemon(mState); + mOverlayConfig = mock(OverlayConfig.class); + when(mOverlayConfig.getPriority(any())).thenReturn(OverlayConfig.DEFAULT_PRIORITY); + when(mOverlayConfig.isEnabled(any())).thenReturn(false); + when(mOverlayConfig.isMutable(any())).thenReturn(true); + reinitializeImpl(); + } - mImpl = new OverlayManagerServiceImpl(pmh, - new DummyIdmapManager(mState, pmh), + void reinitializeImpl() { + mImpl = new OverlayManagerServiceImpl(mPackageManager, + new IdmapManager(mIdmapDaemon, mPackageManager), new OverlayManagerSettings(), - mState.mOverlayConfig, + mOverlayConfig, new String[0], mListener); } - public OverlayManagerServiceImpl getImpl() { + OverlayManagerServiceImpl getImpl() { return mImpl; } - public DummyListener getListener() { + DummyListener getListener() { return mListener; } + DummyPackageManagerHelper getPackageManager() { + return mPackageManager; + } + + DummyIdmapDaemon getIdmapDaemon() { + return mIdmapDaemon; + } + void assertState(@State int expected, final String overlayPackageName, int userId) { final OverlayInfo info = mImpl.getOverlayInfo(overlayPackageName, userId); if (info == null) { @@ -81,7 +103,7 @@ class OverlayManagerServiceImplTestsBase { assertEquals(msg, expected, info.state); } - void assertOverlayInfoList(final String targetPackageName, int userId, + void assertOverlayInfoForTarget(final String targetPackageName, int userId, OverlayInfo... overlayInfos) { final List<OverlayInfo> expected = mImpl.getOverlayInfosForTarget(targetPackageName, userId); @@ -89,198 +111,202 @@ class OverlayManagerServiceImplTestsBase { assertEquals(expected, actual); } - /** - * Creates an overlay configured through {@link OverlayConfig}. - * - * @throws IllegalStateException if the package is already installed - */ - void addOverlayPackage(String packageName, String targetPackageName, int userId, - boolean mutable, boolean enabled, int priority) { - mState.addOverlay(packageName, targetPackageName, userId, mutable, enabled, priority); + DummyDeviceState.PackageBuilder target(String packageName) { + return new DummyDeviceState.PackageBuilder(packageName, null /* targetPackageName */, + null /* targetOverlayableName */); } - /** - * Adds the target package to the device. - * - * This corresponds to when the OMS receives the - * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast. - * - * @throws IllegalStateException if the package is not currently installed - */ - void installTargetPackage(String packageName, int userId) { - if (mState.select(packageName, userId) != null) { - throw new IllegalStateException("package already installed"); - } - mState.addTarget(packageName, userId); - mImpl.onTargetPackageAdded(packageName, userId); + DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName) { + return overlay(packageName, targetPackageName, null /* targetOverlayableName */); } - /** - * Begins upgrading the target package. - * - * This corresponds to when the OMS receives the - * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the - * {@link android.content.Intent#EXTRA_REPLACING} extra. - * - * @throws IllegalStateException if the package is not currently installed - */ - void beginUpgradeTargetPackage(String packageName, int userId) { - if (mState.select(packageName, userId) == null) { - throw new IllegalStateException("package not installed"); - } - mImpl.onTargetPackageReplacing(packageName, userId); + DummyDeviceState.PackageBuilder overlay(String packageName, String targetPackageName, + String targetOverlayableName) { + return new DummyDeviceState.PackageBuilder(packageName, targetPackageName, + targetOverlayableName); } - /** - * Ends upgrading the target package. - * - * This corresponds to when the OMS receives the - * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the - * {@link android.content.Intent#EXTRA_REPLACING} extra. - * - * @throws IllegalStateException if the package is not currently installed - */ - void endUpgradeTargetPackage(String packageName, int userId) { - if (mState.select(packageName, userId) == null) { - throw new IllegalStateException("package not installed"); - } - mState.addTarget(packageName, userId); - mImpl.onTargetPackageReplaced(packageName, userId); + void addSystemPackage(DummyDeviceState.PackageBuilder pkg, int userId) { + mState.add(pkg, userId); } - /** - * Removes the target package from the device. - * - * This corresponds to when the OMS receives the - * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast. - * - * @throws IllegalStateException if the package is not currently installed - */ - void uninstallTargetPackage(String packageName, int userId) { - if (mState.select(packageName, userId) == null) { - throw new IllegalStateException("package not installed"); - } - mState.remove(packageName, userId); - mImpl.onTargetPackageRemoved(packageName, userId); + void configureSystemOverlay(String packageName, boolean mutable, boolean enabled, + int priority) { + when(mOverlayConfig.getPriority(packageName)).thenReturn(priority); + when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled); + when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable); } /** - * Adds the overlay package to the device. + * Adds the package to the device. * * This corresponds to when the OMS receives the * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast. * - * @throws IllegalStateException if the package is already installed + * @throws IllegalStateException if the package is currently installed */ - void installOverlayPackage(String packageName, String targetPackageName, int userId) { - if (mState.select(packageName, userId) != null) { - throw new IllegalStateException("package already installed"); + void installNewPackage(DummyDeviceState.PackageBuilder pkg, int userId) { + if (mState.select(pkg.packageName, userId) != null) { + throw new IllegalStateException("package " + pkg.packageName + " already installed"); + } + mState.add(pkg, userId); + if (pkg.targetPackage == null) { + mImpl.onTargetPackageAdded(pkg.packageName, userId); + } else { + mImpl.onOverlayPackageAdded(pkg.packageName, userId); } - mState.addOverlay(packageName, targetPackageName, userId); - mImpl.onOverlayPackageAdded(packageName, userId); } /** - * Begins upgrading the overlay package. + * Begins upgrading the package. * * This corresponds to when the OMS receives the * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast with the + * {@link android.content.Intent#EXTRA_REPLACING} extra and then receives the + * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the * {@link android.content.Intent#EXTRA_REPLACING} extra. * * @throws IllegalStateException if the package is not currently installed */ - void beginUpgradeOverlayPackage(String packageName, int userId) { - if (mState.select(packageName, userId) == null) { - throw new IllegalStateException("package not installed, cannot upgrade"); + void upgradePackage(DummyDeviceState.PackageBuilder pkg, int userId) { + final DummyDeviceState.Package replacedPackage = mState.select(pkg.packageName, userId); + if (replacedPackage == null) { + throw new IllegalStateException("package " + pkg.packageName + " not installed"); + } + if (replacedPackage.targetPackageName != null) { + mImpl.onOverlayPackageReplacing(pkg.packageName, userId); } - mImpl.onOverlayPackageReplacing(packageName, userId); + mState.add(pkg, userId); + if (pkg.targetPackage == null) { + mImpl.onTargetPackageReplaced(pkg.packageName, userId); + } else { + mImpl.onOverlayPackageReplaced(pkg.packageName, userId); + } } /** - * Ends upgrading the overlay package, potentially changing its target package. + * Removes the package from the device. * * This corresponds to when the OMS receives the - * {@link android.content.Intent#ACTION_PACKAGE_ADDED} broadcast with the - * {@link android.content.Intent#EXTRA_REPLACING} extra. + * {@link android.content.Intent#ACTION_PACKAGE_REMOVED} broadcast. * * @throws IllegalStateException if the package is not currently installed */ - void endUpgradeOverlayPackage(String packageName, String targetPackageName, int userId) { - if (mState.select(packageName, userId) == null) { - throw new IllegalStateException("package not installed, cannot upgrade"); + void uninstallPackage(String packageName, int userId) { + final DummyDeviceState.Package pkg = mState.select(packageName, userId); + if (pkg == null) { + throw new IllegalStateException("package " + packageName+ " not installed"); + } + mState.remove(pkg.packageName); + if (pkg.targetPackageName == null) { + mImpl.onTargetPackageRemoved(pkg.packageName, userId); + } else { + mImpl.onOverlayPackageRemoved(pkg.packageName, userId); } - - mState.addOverlay(packageName, targetPackageName, userId); - mImpl.onOverlayPackageReplaced(packageName, userId); } - private static final class DummyDeviceState { - private List<Package> mPackages = new ArrayList<>(); - private OverlayConfig mOverlayConfig = mock(OverlayConfig.class); - - /** Adds a non-overlay to the device. */ - public void addTarget(String packageName, int userId) { - remove(packageName, userId); - mPackages.add(new Package(packageName, userId, null, false, false, 0)); - } - - /** Adds an overlay to the device. */ - public void addOverlay(String packageName, String targetPackageName, int userId) { - addOverlay(packageName, targetPackageName, userId, true, false, OverlayConfig.DEFAULT_PRIORITY); - } - - /** Adds a configured overlay to the device. */ - public void addOverlay(String packageName, String targetPackageName, int userId, - boolean mutable, boolean enabled, int priority) { - remove(packageName, userId); - mPackages.add(new Package(packageName, userId, targetPackageName, mutable, enabled, - priority)); - when(mOverlayConfig.getPriority(packageName)).thenReturn(priority); - when(mOverlayConfig.isEnabled(packageName)).thenReturn(enabled); - when(mOverlayConfig.isMutable(packageName)).thenReturn(mutable); - } - - /** Remove a package from the device. */ - public void remove(String packageName, int userId) { - final Iterator<Package> iter = mPackages.iterator(); - while (iter.hasNext()) { - final Package pkg = iter.next(); - if (pkg.packageName.equals(packageName) && pkg.userId == userId) { - iter.remove(); - return; - } + /** Represents the state of packages installed on a fake device. */ + static class DummyDeviceState { + private ArrayMap<String, Package> mPackages = new ArrayMap<>(); + + void add(PackageBuilder pkgBuilder, int userId) { + final Package pkg = pkgBuilder.build(); + final Package previousPkg = select(pkg.packageName, userId); + mPackages.put(pkg.packageName, pkg); + + pkg.installedUserIds.add(userId); + if (previousPkg != null) { + pkg.installedUserIds.addAll(previousPkg.installedUserIds); } } - /** Retrieves all packages on device for a particular user. */ - public List<Package> select(int userId) { - return mPackages.stream().filter(p -> p.userId == userId).collect(Collectors.toList()); + void remove(String packageName) { + mPackages.remove(packageName); + } + + void uninstall(String packageName, int userId) { + final Package pkg = mPackages.get(packageName); + if (pkg != null) { + pkg.installedUserIds.remove(userId); + } + } + + List<Package> select(int userId) { + return mPackages.values().stream().filter(p -> p.installedUserIds.contains(userId)) + .collect(Collectors.toList()); + } + + Package select(String packageName, int userId) { + final Package pkg = mPackages.get(packageName); + return pkg != null && pkg.installedUserIds.contains(userId) ? pkg : null; } - /** Retrieves the package with the specified package name for a particular user. */ - public Package select(String packageName, int userId) { - return mPackages.stream().filter( - p -> p.packageName.equals(packageName) && p.userId == userId) - .findFirst().orElse(null); + private Package selectFromPath(String path) { + return mPackages.values().stream() + .filter(p -> p.apkPath.equals(path)).findFirst().orElse(null); } - private static final class Package { - public final String packageName; - public final int userId; - public final String targetPackageName; - public final boolean mutable; - public final boolean enabled; - public final int priority; + static final class PackageBuilder { + private String packageName; + private String targetPackage; + private String certificate = "[default]"; + private int version = 0; + private ArrayList<String> overlayableNames = new ArrayList<>(); + private String targetOverlayableName; - private Package(String packageName, int userId, String targetPackageName, - boolean mutable, boolean enabled, int priority) { + private PackageBuilder(String packageName, String targetPackage, + String targetOverlayableName) { + this.packageName = packageName; + this.targetPackage = targetPackage; + this.targetOverlayableName = targetOverlayableName; + } + + PackageBuilder setCertificate(String certificate) { + this.certificate = certificate; + return this; + } + + PackageBuilder addOverlayable(String overlayableName) { + overlayableNames.add(overlayableName); + return this; + } + + PackageBuilder setVersion(int version) { + this.version = version; + return this; + } + + Package build() { + final String apkPath = String.format("%s/%s/base.apk", + targetPackage == null ? "/system/app/:" : "/vendor/overlay/:", + packageName); + final Package newPackage = new Package(packageName, targetPackage, + targetOverlayableName, version, apkPath, certificate); + newPackage.overlayableNames.addAll(overlayableNames); + return newPackage; + } + } + + static final class Package { + final String packageName; + final String targetPackageName; + final String targetOverlayableName; + final int versionCode; + final String apkPath; + final String certificate; + final ArrayList<String> overlayableNames = new ArrayList<>(); + private final ArraySet<Integer> installedUserIds = new ArraySet<>(); + + private Package(String packageName, String targetPackageName, + String targetOverlayableName, int versionCode, String apkPath, + String certificate) { this.packageName = packageName; - this.userId = userId; this.targetPackageName = targetPackageName; - this.mutable = mutable; - this.enabled = enabled; - this.priority = priority; + this.targetOverlayableName = targetOverlayableName; + this.versionCode = versionCode; + this.apkPath = apkPath; + this.certificate = certificate; } } } @@ -288,6 +314,8 @@ class OverlayManagerServiceImplTestsBase { static final class DummyPackageManagerHelper implements PackageManagerHelper, OverlayableInfoCallback { private final DummyDeviceState mState; + String[] overlayableConfiguratorTargets = new String[0]; + String overlayableConfigurator = ""; private DummyPackageManagerHelper(DummyDeviceState state) { mState = state; @@ -300,13 +328,12 @@ class OverlayManagerServiceImplTestsBase { return null; } final ApplicationInfo ai = new ApplicationInfo(); - ai.sourceDir = String.format("%s/%s/base.apk", - pkg.targetPackageName == null ? "/system/app/" : "/vendor/overlay/", - pkg.packageName); + ai.sourceDir = pkg.apkPath; PackageInfo pi = new PackageInfo(); pi.applicationInfo = ai; pi.packageName = pkg.packageName; pi.overlayTarget = pkg.targetPackageName; + pi.targetOverlayableName = pkg.targetOverlayableName; pi.overlayCategory = "dummy-category-" + pkg.targetPackageName; return pi; } @@ -314,14 +341,16 @@ class OverlayManagerServiceImplTestsBase { @Override public boolean signaturesMatching(@NonNull String packageName1, @NonNull String packageName2, int userId) { - return false; + final DummyDeviceState.Package pkg1 = mState.select(packageName1, userId); + final DummyDeviceState.Package pkg2 = mState.select(packageName2, userId); + return pkg1 != null && pkg2 != null && pkg1.certificate.equals(pkg2.certificate); } @Override public List<PackageInfo> getOverlayPackages(int userId) { return mState.select(userId).stream() .filter(p -> p.targetPackageName != null) - .map(p -> getPackageInfo(p.packageName, p.userId)) + .map(p -> getPackageInfo(p.packageName, userId)) .collect(Collectors.toList()); } @@ -329,7 +358,11 @@ class OverlayManagerServiceImplTestsBase { @Override public OverlayableInfo getOverlayableForTarget(@NonNull String packageName, @NonNull String targetOverlayableName, int userId) { - throw new UnsupportedOperationException(); + final DummyDeviceState.Package pkg = mState.select(packageName, userId); + if (pkg == null || !pkg.overlayableNames.contains(targetOverlayableName)) { + return null; + } + return new OverlayableInfo(targetOverlayableName, null /* actor */); } @Nullable @@ -341,69 +374,98 @@ class OverlayManagerServiceImplTestsBase { @NonNull @Override public Map<String, Map<String, String>> getNamedActors() { - throw new UnsupportedOperationException(); + return Collections.emptyMap(); } @Override public boolean doesTargetDefineOverlayable(String targetPackageName, int userId) { - throw new UnsupportedOperationException(); + final DummyDeviceState.Package pkg = mState.select(targetPackageName, userId); + return pkg != null && pkg.overlayableNames.contains(targetPackageName); } @Override public void enforcePermission(String permission, String message) throws SecurityException { throw new UnsupportedOperationException(); } + + @Override + public String[] getOverlayableConfiguratorTargets() { + return overlayableConfiguratorTargets; + } + + @Override + public String getOverlayableConfigurator() { + return overlayableConfigurator; + } } - static class DummyIdmapManager extends IdmapManager { + static class DummyIdmapDaemon extends IdmapDaemon { private final DummyDeviceState mState; - private Set<String> mIdmapFiles = new ArraySet<>(); + private final ArrayMap<String, IdmapHeader> mIdmapFiles = new ArrayMap<>(); - private DummyIdmapManager(DummyDeviceState state, - DummyPackageManagerHelper packageManagerHelper) { - super(packageManagerHelper); - mState = state; + DummyIdmapDaemon(DummyDeviceState state) { + this.mState = state; + } + + private int getCrc(@NonNull final String path) { + final DummyDeviceState.Package pkg = mState.selectFromPath(path); + Assert.assertNotNull(pkg); + return pkg.versionCode; } @Override - boolean createIdmap(@NonNull final PackageInfo targetPackage, - @NonNull final PackageInfo overlayPackage, int userId) { - final DummyDeviceState.Package t = mState.select(targetPackage.packageName, userId); - if (t == null) { - return false; - } - final DummyDeviceState.Package o = mState.select(overlayPackage.packageName, userId); - if (o == null) { - return false; - } - final String key = createKey(overlayPackage.packageName, userId); - return mIdmapFiles.add(key); + String createIdmap(String targetPath, String overlayPath, int policies, boolean enforce, + int userId) { + mIdmapFiles.put(overlayPath, new IdmapHeader(getCrc(targetPath), + getCrc(overlayPath), targetPath, policies, enforce)); + return overlayPath; + } + + @Override + boolean removeIdmap(String overlayPath, int userId) { + return mIdmapFiles.remove(overlayPath) != null; } @Override - boolean removeIdmap(@NonNull final OverlayInfo oi, final int userId) { - final String key = createKey(oi.packageName, oi.userId); - if (!mIdmapFiles.contains(key)) { + boolean verifyIdmap(String targetPath, String overlayPath, int policies, boolean enforce, + int userId) { + final IdmapHeader idmap = mIdmapFiles.get(overlayPath); + if (idmap == null) { return false; } - mIdmapFiles.remove(key); - return true; + return idmap.isUpToDate(getCrc(targetPath), getCrc(overlayPath), targetPath); } @Override - boolean idmapExists(@NonNull final OverlayInfo oi) { - final String key = createKey(oi.packageName, oi.userId); - return mIdmapFiles.contains(key); + boolean idmapExists(String overlayPath, int userId) { + return mIdmapFiles.containsKey(overlayPath); } - @Override - boolean idmapExists(@NonNull final PackageInfo overlayPackage, final int userId) { - final String key = createKey(overlayPackage.packageName, userId); - return mIdmapFiles.contains(key); + IdmapHeader getIdmap(String overlayPath) { + return mIdmapFiles.get(overlayPath); } - private String createKey(@NonNull final String packageName, final int userId) { - return String.format("%s:%d", packageName, userId); + static class IdmapHeader { + private final int targetCrc; + private final int overlayCrc; + final String targetPath; + final int policies; + final boolean enforceOverlayable; + + private IdmapHeader(int targetCrc, int overlayCrc, String targetPath, int policies, + boolean enforceOverlayable) { + this.targetCrc = targetCrc; + this.overlayCrc = overlayCrc; + this.targetPath = targetPath; + this.policies = policies; + this.enforceOverlayable = enforceOverlayable; + } + + private boolean isUpToDate(int expectedTargetCrc, int expectedOverlayCrc, + String expectedTargetPath) { + return expectedTargetCrc == targetCrc && expectedOverlayCrc == overlayCrc + && expectedTargetPath.equals(targetPath); + } } } diff --git a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java index 70d6cf81c3b0..c5d94875b684 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/ConversationInfoTest.java @@ -46,7 +46,8 @@ public final class ConversationInfoTest { .setContactUri(CONTACT_URI) .setContactPhoneNumber(PHONE_NUMBER) .setNotificationChannelId(NOTIFICATION_CHANNEL_ID) - .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED | ShortcutInfo.FLAG_CACHED) + .setShortcutFlags(ShortcutInfo.FLAG_LONG_LIVED + | ShortcutInfo.FLAG_CACHED_NOTIFICATIONS) .setImportant(true) .setNotificationSilenced(true) .setBubbled(true) @@ -62,7 +63,7 @@ public final class ConversationInfoTest { assertEquals(PHONE_NUMBER, conversationInfo.getContactPhoneNumber()); assertEquals(NOTIFICATION_CHANNEL_ID, conversationInfo.getNotificationChannelId()); assertTrue(conversationInfo.isShortcutLongLived()); - assertTrue(conversationInfo.isShortcutCached()); + assertTrue(conversationInfo.isShortcutCachedForNotification()); assertTrue(conversationInfo.isImportant()); assertTrue(conversationInfo.isNotificationSilenced()); assertTrue(conversationInfo.isBubbled()); @@ -84,7 +85,7 @@ public final class ConversationInfoTest { assertNull(conversationInfo.getContactPhoneNumber()); assertNull(conversationInfo.getNotificationChannelId()); assertFalse(conversationInfo.isShortcutLongLived()); - assertFalse(conversationInfo.isShortcutCached()); + assertFalse(conversationInfo.isShortcutCachedForNotification()); assertFalse(conversationInfo.isImportant()); assertFalse(conversationInfo.isNotificationSilenced()); assertFalse(conversationInfo.isBubbled()); diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java index 1a2032ac15d0..b2f7abbf84df 100644 --- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java @@ -405,7 +405,7 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, buildPerson()); - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); NotificationListenerService listenerService = @@ -419,7 +419,8 @@ public final class DataManagerTest { assertEquals(1, activeNotificationOpenTimeSlots.size()); verify(mShortcutServiceInternal).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test @@ -434,7 +435,7 @@ public final class DataManagerTest { mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); // Post one notification. - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); listenerService.onNotificationPosted(mStatusBarNotification); @@ -445,14 +446,15 @@ public final class DataManagerTest { listenerService.onNotificationRemoved(mStatusBarNotification, null, NotificationListenerService.REASON_CANCEL); verify(mShortcutServiceInternal, never()).uncacheShortcuts( - anyInt(), any(), anyString(), any(), anyInt()); + anyInt(), any(), anyString(), any(), anyInt(), anyInt()); // Removing the second notification un-caches the shortcut. listenerService.onNotificationRemoved(mStatusBarNotification, null, NotificationListenerService.REASON_CANCEL_ALL); verify(mShortcutServiceInternal).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test @@ -467,7 +469,7 @@ public final class DataManagerTest { mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); listenerService.onNotificationPosted(mStatusBarNotification); - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), @@ -477,7 +479,8 @@ public final class DataManagerTest { NotificationListenerService.REASON_CANCEL_ALL); verify(mShortcutServiceInternal, never()).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test @@ -569,13 +572,14 @@ public final class DataManagerTest { mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); listenerService.onNotificationPosted(mStatusBarNotification); - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); mShutdownBroadcastReceiver.onReceive(mContext, new Intent()); verify(mShortcutServiceInternal).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test @@ -590,7 +594,7 @@ public final class DataManagerTest { mDataManager.getNotificationListenerServiceForTesting(USER_ID_PRIMARY); listenerService.onNotificationPosted(mStatusBarNotification); - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); listenerService.onNotificationChannelModified(TEST_PKG_NAME, UserHandle.of(USER_ID_PRIMARY), @@ -599,7 +603,8 @@ public final class DataManagerTest { mShutdownBroadcastReceiver.onReceive(mContext, new Intent()); verify(mShortcutServiceInternal, never()).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test @@ -767,14 +772,15 @@ public final class DataManagerTest { ShortcutInfo shortcut = buildShortcutInfo(TEST_PKG_NAME, USER_ID_PRIMARY, TEST_SHORTCUT_ID, buildPerson()); - shortcut.setCached(); + shortcut.setCached(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS); mDataManager.addOrUpdateConversationInfo(shortcut); mDataManager.pruneDataForUser(USER_ID_PRIMARY, mCancellationSignal); verify(mShortcutServiceInternal).uncacheShortcuts( anyInt(), any(), eq(TEST_PKG_NAME), - eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY)); + eq(Collections.singletonList(TEST_SHORTCUT_ID)), eq(USER_ID_PRIMARY), + eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); } @Test diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java index db02524e6fab..90989b9eda84 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest1.java @@ -137,6 +137,9 @@ import java.util.function.BiConsumer; @SmallTest public class ShortcutManagerTest1 extends BaseShortcutManagerTest { + private static final int CACHE_OWNER_0 = LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; + private static final int CACHE_OWNER_1 = LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; + @Override protected void tearDown() throws Exception { deleteUriFile("file32x32.jpg"); @@ -487,7 +490,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { mManager.pushDynamicShortcut(s8); assertEquals(4, getCallerShortcut("s8").getRank()); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s8"), HANDLE_USER_0, + CACHE_OWNER_0); }); mManager.pushDynamicShortcut(s9); @@ -1452,8 +1456,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Cache 1 and 2 runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), - HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), + HANDLE_USER_0, CACHE_OWNER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), + HANDLE_USER_0, CACHE_OWNER_1); }); setCaller(CALLING_PACKAGE_1); @@ -1532,8 +1538,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Cache some, but non long lived shortcuts will be ignored. runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s4"), - HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), + HANDLE_USER_0, CACHE_OWNER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"), + HANDLE_USER_0, CACHE_OWNER_1); }); setCaller(CALLING_PACKAGE_1); @@ -1555,10 +1563,18 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s4"); + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s4"), + HANDLE_USER_0, CACHE_OWNER_0); + }); + // s2 still cached by owner1. s4 wasn't cached by owner0 so didn't get removed. + assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), + "s2", "s4"); + // uncache a non-dynamic shortcut. Should be removed. runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s4"), - HANDLE_USER_0); + HANDLE_USER_0, CACHE_OWNER_1); }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2"); @@ -1566,7 +1582,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Cache another shortcut runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), - HANDLE_USER_0); + HANDLE_USER_0, CACHE_OWNER_0); }); assertShortcutIds(mManager.getShortcuts(ShortcutManager.FLAG_MATCH_CACHED), "s2", "s3"); @@ -1594,7 +1610,7 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { // Cache All runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3", "s4"), - HANDLE_USER_0); + HANDLE_USER_0, CACHE_OWNER_0); }); setCaller(CALLING_PACKAGE_1); @@ -1792,8 +1808,10 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { setCaller(LAUNCHER_1); // Cache some shortcuts. Only long lived shortcuts can get cached. - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser()); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser()); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), getCallingUser(), + CACHE_OWNER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_3, list("s3"), getCallingUser(), + CACHE_OWNER_0); // Cached ones only assertShortcutIds(assertAllNotKeyFieldsOnly( @@ -8732,7 +8750,8 @@ public class ShortcutManagerTest1 extends BaseShortcutManagerTest { assertTrue(mInternal.isSharingShortcut(USER_0, LAUNCHER_1, CALLING_PACKAGE_1, "s3", USER_0, filter_any)); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { diff --git a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java index 621966535306..6a2b8e0da2d2 100644 --- a/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java +++ b/services/tests/servicestests/src/com/android/server/pm/ShortcutManagerTest11.java @@ -25,6 +25,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.content.ComponentName; +import android.content.pm.LauncherApps; import android.content.pm.LauncherApps.ShortcutChangeCallback; import android.content.pm.LauncherApps.ShortcutQuery; import android.content.pm.ShortcutInfo; @@ -46,6 +47,9 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { private static final ShortcutQuery QUERY_MATCH_ALL = createShortcutQuery( ShortcutQuery.FLAG_MATCH_ALL_KINDS_WITH_ALL_PINNED); + private static final int CACHE_OWNER_0 = LauncherApps.FLAG_CACHE_NOTIFICATION_SHORTCUTS; + private static final int CACHE_OWNER_1 = LauncherApps.FLAG_CACHE_BUBBLE_SHORTCUTS; + private final TestLooper mTestLooper = new TestLooper(); public void testShortcutChangeCallback_setDynamicShortcuts() { @@ -113,7 +117,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); }); ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); @@ -211,7 +216,42 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + CACHE_OWNER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + CACHE_OWNER_1); + }); + + mTestLooper.dispatchAll(); + + ArgumentCaptor<List> shortcuts = ArgumentCaptor.forClass(List.class); + verify(callback, times(2)).onShortcutsAddedOrUpdated( + eq(CALLING_PACKAGE_1), shortcuts.capture(), eq(HANDLE_USER_0)); + verify(callback, times(0)).onShortcutsRemoved(any(), any(), any()); + + assertWith(shortcuts.getValue()) + .areAllWithKeyFieldsOnly() + .haveIds("s1", "s3"); + } + + public void testShortcutChangeCallback_cacheShortcuts_alreadyCached() { + runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { + assertTrue(mManager.setDynamicShortcuts(list(makeLongLivedShortcut("s1"), + makeLongLivedShortcut("s2"), makeLongLivedShortcut("s3")))); + }); + + ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); + runWithCaller(LAUNCHER_1, USER_0, () -> { + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + CACHE_OWNER_0); + mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, + mTestLooper.getNewExecutor()); + // Should not cause any callback events + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + CACHE_OWNER_0); + // Should cause a change event + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s3"), HANDLE_USER_0, + CACHE_OWNER_1); }); mTestLooper.dispatchAll(); @@ -234,10 +274,12 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); }); mTestLooper.dispatchAll(); @@ -259,8 +301,11 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { }); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s1"), HANDLE_USER_0, + CACHE_OWNER_1); }); runWithCaller(CALLING_PACKAGE_1, USER_0, () -> { @@ -271,7 +316,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { runWithCaller(LAUNCHER_1, USER_0, () -> { mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); - mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s2", "s3"), HANDLE_USER_0); + mLauncherApps.uncacheShortcuts(CALLING_PACKAGE_1, list("s1", "s2", "s3"), HANDLE_USER_0, + CACHE_OWNER_0); }); mTestLooper.dispatchAll(); @@ -284,9 +330,10 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { verify(callback, times(1)).onShortcutsRemoved( eq(CALLING_PACKAGE_1), removedShortcuts.capture(), eq(HANDLE_USER_0)); + // s1 is still cached for owner1, s2 is pinned. assertWith(changedShortcuts.getValue()) .areAllWithKeyFieldsOnly() - .haveIds("s2"); + .haveIds("s1", "s2"); assertWith(removedShortcuts.getValue()) .areAllWithKeyFieldsOnly() @@ -453,7 +500,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); }); @@ -511,7 +559,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); @@ -547,7 +596,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { }); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); }); @@ -614,7 +664,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); @@ -680,7 +731,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); @@ -747,7 +799,8 @@ public class ShortcutManagerTest11 extends BaseShortcutManagerTest { ShortcutChangeCallback callback = mock(ShortcutChangeCallback.class); runWithCaller(LAUNCHER_1, USER_0, () -> { - mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0); + mLauncherApps.cacheShortcuts(CALLING_PACKAGE_1, list("s2"), HANDLE_USER_0, + CACHE_OWNER_0); mLauncherApps.pinShortcuts(CALLING_PACKAGE_1, list("s3"), HANDLE_USER_0); mLauncherApps.registerShortcutChangeCallback(callback, QUERY_MATCH_ALL, mTestLooper.getNewExecutor()); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java index 38b71b707196..13457f0a284c 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/BubbleExtractorTest.java @@ -26,6 +26,8 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE; import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static junit.framework.Assert.assertFalse; +import static junit.framework.Assert.assertNotNull; +import static junit.framework.Assert.assertNull; import static junit.framework.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; @@ -166,6 +168,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_ALL /* app */, ALLOW_BUBBLE_OFF /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -178,6 +182,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_ALL /* app */, DEFAULT_ALLOW_BUBBLE /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -190,6 +196,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_ALL /* app */, ALLOW_BUBBLE_ON /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -202,6 +210,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(false /* feature */, BUBBLE_PREFERENCE_ALL /* app */, ALLOW_BUBBLE_ON /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -215,6 +225,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_NONE /* app */, ALLOW_BUBBLE_ON /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -228,6 +240,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_NONE /* app */, DEFAULT_ALLOW_BUBBLE /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -241,6 +255,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_SELECTED /* app */, DEFAULT_ALLOW_BUBBLE /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -254,6 +270,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_SELECTED /* app */, ALLOW_BUBBLE_OFF /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -267,6 +285,9 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(true /* feature */, BUBBLE_PREFERENCE_SELECTED /* app */, ALLOW_BUBBLE_ON /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -279,6 +300,9 @@ public class BubbleExtractorTest extends UiServiceTestCase { setUpBubblesEnabled(false /* feature */, BUBBLE_PREFERENCE_SELECTED /* app */, ALLOW_BUBBLE_ON /* channel */); + when(mActivityManager.isLowRamDevice()).thenReturn(false); + setUpShortcutBubble(true /* isValid */); + NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); @@ -305,6 +329,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { mBubbleExtractor.process(r); assertTrue(r.canBubble()); + assertNotNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -320,6 +345,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { mBubbleExtractor.process(r); assertTrue(r.canBubble()); + assertNotNull(r.getNotification().getBubbleMetadata()); assertTrue(r.getNotification().isBubbleNotification()); } @@ -335,6 +361,7 @@ public class BubbleExtractorTest extends UiServiceTestCase { mBubbleExtractor.process(r); assertTrue(r.canBubble()); + assertNotNull(r.getNotification().getBubbleMetadata()); assertTrue(r.getNotification().isBubbleNotification()); } @@ -350,7 +377,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { r.setShortcutInfo(null); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -366,7 +394,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { r.setShortcutInfo(null); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -381,7 +410,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -395,7 +425,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { NotificationRecord r = getNotificationRecord(false /* bubble */); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -414,7 +445,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -429,7 +461,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -445,7 +478,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } @@ -462,7 +496,8 @@ public class BubbleExtractorTest extends UiServiceTestCase { NotificationRecord r = getNotificationRecord(true /* bubble */); mBubbleExtractor.process(r); - assertTrue(r.canBubble()); + assertFalse(r.canBubble()); + assertNull(r.getNotification().getBubbleMetadata()); assertFalse(r.getNotification().isBubbleNotification()); } } 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 ced780475fb7..cf636823d5f7 100755 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java @@ -6135,8 +6135,6 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { "tag", mUid, 0, nb.build(), new UserHandle(mUid), null, 0); NotificationRecord nr = new NotificationRecord(mContext, sbn, mTestNotificationChannel); - - // Test: Send the bubble notification mBinderService.enqueueNotificationWithTag(PKG, PKG, nr.getSbn().getTag(), nr.getSbn().getId(), nr.getSbn().getNotification(), nr.getSbn().getUserId()); @@ -6154,7 +6152,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Make sure the shortcut is cached. verify(mShortcutServiceInternal).cacheShortcuts( anyInt(), any(), eq(PKG), eq(Collections.singletonList(VALID_CONVO_SHORTCUT_ID)), - eq(USER_SYSTEM)); + eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); // Test: Remove the shortcut when(mLauncherApps.getShortcuts(any(), any())).thenReturn(null); @@ -6168,12 +6166,12 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { verify(mLauncherApps, times(1)).unregisterCallback(launcherAppsCallback.getValue()); // We're no longer a bubble - Notification notif2 = mService.getNotificationRecord( - nr.getSbn().getKey()).getNotification(); - assertFalse(notif2.isBubbleNotification()); + NotificationRecord notif2 = mService.getNotificationRecord( + nr.getSbn().getKey()); + assertNull(notif2.getShortcutInfo()); + assertFalse(notif2.getNotification().isBubbleNotification()); } - @Test public void testNotificationBubbles_shortcut_stopListeningWhenNotifRemoved() throws RemoteException { @@ -6227,7 +6225,7 @@ public class NotificationManagerServiceTest extends UiServiceTestCase { // Make sure the shortcut is cached. verify(mShortcutServiceInternal).cacheShortcuts( anyInt(), any(), eq(PKG), eq(Collections.singletonList(shortcutId)), - eq(USER_SYSTEM)); + eq(USER_SYSTEM), eq(ShortcutInfo.FLAG_CACHED_NOTIFICATIONS)); // Test: Remove the notification mBinderService.cancelNotificationWithTag(PKG, PKG, nr.getSbn().getTag(), diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java index 6df3c7b69d15..976f40896b78 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java @@ -1191,4 +1191,56 @@ public class NotificationRecordTest extends UiServiceTestCase { assertFalse(record.isConversation()); } + + @Test + public void isConversation_pkgAllowed_isMsgType() { + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + sbn.getNotification().category = Notification.CATEGORY_MESSAGE; + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + record.setPkgAllowedAsConvo(true); + + assertTrue(record.isConversation()); + } + + @Test + public void isConversation_pkgAllowed_isMNotsgType() { + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + sbn.getNotification().category = Notification.CATEGORY_ALARM; + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + record.setPkgAllowedAsConvo(true); + + assertFalse(record.isConversation()); + } + + @Test + public void isConversation_pkgNotAllowed_isMsgType() { + StatusBarNotification sbn = getNotification(PKG_N_MR1, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + sbn.getNotification().category = Notification.CATEGORY_MESSAGE; + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + record.setPkgAllowedAsConvo(false); + + assertFalse(record.isConversation()); + } + + @Test + public void isConversation_pkgAllowed_isMsgType_targetsR() { + StatusBarNotification sbn = getNotification(PKG_R, true /* noisy */, + true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */, + false /* lights */, false /* defaultLights */, null /* group */); + sbn.getNotification().category = Notification.CATEGORY_MESSAGE; + NotificationRecord record = new NotificationRecord(mMockContext, sbn, defaultChannel); + + record.setPkgAllowedAsConvo(true); + + assertFalse(record.isConversation()); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 078c21e04512..1d6f8233b7b4 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -31,6 +31,7 @@ import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED; import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE; import static com.android.server.notification.PreferencesHelper.NOTIFICATION_CHANNEL_COUNT_LIMIT; +import static com.android.server.notification.PreferencesHelper.UNKNOWN_UID; import static com.google.common.truth.Truth.assertThat; @@ -2511,6 +2512,26 @@ public class PreferencesHelperTest extends UiServiceTestCase { } @Test + public void testBubblePrefence_noSAWCheckForUnknownUid() throws Exception { + final String xml = "<ranking version=\"1\">\n" + + "<package name=\"" + PKG_O + "\" uid=\"" + UNKNOWN_UID + "\">\n" + + "<channel id=\"someId\" name=\"hi\"" + + " importance=\"3\"/>" + + "</package>" + + "</ranking>"; + XmlPullParser parser = Xml.newPullParser(); + parser.setInput(new BufferedInputStream(new ByteArrayInputStream(xml.getBytes())), + null); + parser.nextTag(); + mHelper.readXml(parser, false, UserHandle.USER_ALL); + + assertEquals(DEFAULT_BUBBLE_PREFERENCE, mHelper.getBubblePreference(PKG_O, UID_O)); + assertEquals(0, mHelper.getAppLockedFields(PKG_O, UID_O)); + verify(mAppOpsManager, never()).noteOpNoThrow(eq(OP_SYSTEM_ALERT_WINDOW), anyInt(), + anyString(), eq(null), anyString()); + } + + @Test public void testBubblePreference_xml() throws Exception { mHelper.setBubblesAllowed(PKG_O, UID_O, BUBBLE_PREFERENCE_NONE); assertEquals(mHelper.getBubblePreference(PKG_O, UID_O), BUBBLE_PREFERENCE_NONE); diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java index eb2d9fed197f..c700a090fa2e 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/ShortcutHelperTest.java @@ -48,6 +48,7 @@ import org.mockito.Mock; import org.mockito.MockitoAnnotations; import java.util.ArrayList; +import java.util.Collections; import java.util.List; @SmallTest @@ -73,6 +74,8 @@ public class ShortcutHelperTest extends UiServiceTestCase { StatusBarNotification mSbn; @Mock Notification.BubbleMetadata mBubbleMetadata; + @Mock + ShortcutInfo mShortcutInfo; ShortcutHelper mShortcutHelper; @@ -86,13 +89,13 @@ public class ShortcutHelperTest extends UiServiceTestCase { when(mNr.getSbn()).thenReturn(mSbn); when(mSbn.getPackageName()).thenReturn(PKG); when(mNr.getNotification()).thenReturn(mNotif); + when(mNr.getShortcutInfo()).thenReturn(mShortcutInfo); + when(mShortcutInfo.getId()).thenReturn(SHORTCUT_ID); when(mNotif.getBubbleMetadata()).thenReturn(mBubbleMetadata); when(mBubbleMetadata.getShortcutId()).thenReturn(SHORTCUT_ID); } private LauncherApps.Callback addShortcutBubbleAndVerifyListener() { - when(mNotif.isBubbleNotification()).thenReturn(true); - mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr, false /* removed */, null /* handler */); @@ -124,12 +127,40 @@ public class ShortcutHelperTest extends UiServiceTestCase { } @Test - public void testBubbleNoLongerBubble_listenerRemoved() { + public void testBubbleNoLongerHasBubbleMetadata_listenerRemoved() { // First set it up to listen addShortcutBubbleAndVerifyListener(); // Then make it not a bubble - when(mNotif.isBubbleNotification()).thenReturn(false); + when(mNotif.getBubbleMetadata()).thenReturn(null); + mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr, + false /* removed */, + null /* handler */); + + verify(mLauncherApps, times(1)).unregisterCallback(any()); + } + + @Test + public void testBubbleNoLongerHasShortcutId_listenerRemoved() { + // First set it up to listen + addShortcutBubbleAndVerifyListener(); + + // Clear out shortcutId + when(mBubbleMetadata.getShortcutId()).thenReturn(null); + mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr, + false /* removed */, + null /* handler */); + + verify(mLauncherApps, times(1)).unregisterCallback(any()); + } + + @Test + public void testNotifNoLongerHasShortcut_listenerRemoved() { + // First set it up to listen + addShortcutBubbleAndVerifyListener(); + + // Clear out shortcutId + when(mNr.getShortcutInfo()).thenReturn(null); mShortcutHelper.maybeListenForShortcutChangesForBubbles(mNr, false /* removed */, null /* handler */); @@ -138,6 +169,17 @@ public class ShortcutHelperTest extends UiServiceTestCase { } @Test + public void testOnShortcutsChanged_listenerRemoved() { + // First set it up to listen + LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener(); + + // App shortcuts are removed: + callback.onShortcutsChanged(PKG, Collections.emptyList(), mock(UserHandle.class)); + + verify(mLauncherApps, times(1)).unregisterCallback(any()); + } + + @Test public void testListenerNotifiedOnShortcutRemoved() { LauncherApps.Callback callback = addShortcutBubbleAndVerifyListener(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 063568d0380c..4f14cd0b6fd9 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -1412,7 +1412,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // The launching rotated app should not be cleared when waiting for remote rotation. display.continueUpdateOrientationForDiffOrienLaunchingApp(); - assertNotNull(display.getFixedRotationLaunchingApp()); + assertTrue(display.isFixedRotationLaunchingApp(mActivity)); // Simulate the rotation has been updated to previous one, e.g. sensor updates before the // remote rotation is completed. @@ -1441,7 +1441,7 @@ public class ActivityRecordTests extends ActivityTestsBase { display.setFixedRotationLaunchingAppUnchecked(mActivity); display.sendNewConfiguration(); - assertNull(display.getFixedRotationLaunchingApp()); + assertFalse(display.hasTopFixedRotationLaunchingApp()); assertFalse(mActivity.hasFixedRotationTransform()); } @@ -1497,7 +1497,7 @@ public class ActivityRecordTests extends ActivityTestsBase { // rotation should be applied when creating snapshot surface if the display rotation may be // changed according to the activity orientation. assertTrue(mActivity.hasFixedRotationTransform()); - assertEquals(mActivity, mActivity.mDisplayContent.getFixedRotationLaunchingApp()); + assertTrue(mActivity.mDisplayContent.isFixedRotationLaunchingApp(mActivity)); } /** diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java index 07050d9666d5..36d4888fa56e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenTests.java @@ -35,6 +35,7 @@ import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN; import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.doCallRealMethod; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.server.wm.WindowStateAnimator.STACK_CLIP_AFTER_ANIM; @@ -47,6 +48,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.reset; import static org.mockito.Mockito.verify; @@ -390,6 +392,46 @@ public class AppWindowTokenTests extends WindowTestsBase { onAnimationFinishedCallback)); } + @Test + public void testTransferStartingWindowFromFinishingActivity() { + mActivity.addStartingWindow(mPackageName, android.R.style.Theme, null /* compatInfo */, + "Test", 0 /* labelRes */, 0 /* icon */, 0 /* logo */, 0 /* windowFlags */, + null /* transferFrom */, true /* newTask */, true /* taskSwitch */, + false /* processRunning */, false /* allowTaskSnapshot */, + false /* activityCreate */); + waitUntilHandlersIdle(); + assertHasStartingWindow(mActivity); + mActivity.mStartingWindowState = ActivityRecord.STARTING_WINDOW_SHOWN; + + doCallRealMethod().when(mStack).startActivityLocked( + any(), any(), anyBoolean(), anyBoolean(), any()); + // Make mVisibleSetFromTransferredStartingWindow true. + final ActivityRecord middle = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService) + .setTask(mTask).build(); + mStack.startActivityLocked(middle, null /* focusedTopActivity */, + false /* newTask */, false /* keepCurTransition */, null /* options */); + middle.makeFinishingLocked(); + + assertNull(mActivity.startingWindow); + assertHasStartingWindow(middle); + + final ActivityRecord top = new ActivityTestsBase.ActivityBuilder(mWm.mAtmService) + .setTask(mTask).build(); + // Expect the visibility should be updated to true when transferring starting window from + // a visible activity. + top.setVisible(false); + // The finishing middle should be able to transfer starting window to top. + mStack.startActivityLocked(top, null /* focusedTopActivity */, + false /* newTask */, false /* keepCurTransition */, null /* options */); + + assertNull(middle.startingWindow); + assertHasStartingWindow(top); + assertTrue(top.isVisible()); + // The activity was visible by mVisibleSetFromTransferredStartingWindow, so after its + // starting window is transferred, it should restore to invisible. + assertFalse(middle.isVisible()); + } + private ActivityRecord createIsolatedTestActivityRecord() { final ActivityStack taskStack = createTaskStackOnDisplay(mDisplayContent); final Task task = createTaskInStack(taskStack, 0 /* userId */); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 4e82ceb882a8..7be2b732ac62 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -57,6 +57,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.same; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; +import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_FIXED_TRANSFORM; import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowManagerService.UPDATE_FOCUS_NORMAL; @@ -1060,6 +1061,11 @@ public class DisplayContentTests extends WindowTestsBase { @Test public void testApplyTopFixedRotationTransform() { mWm.mIsFixedRotationTransformEnabled = true; + final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy(); + // Only non-movable (gesture) navigation bar will be animated by fixed rotation animation. + doReturn(false).when(displayPolicy).navigationBarCanMove(); + displayPolicy.addWindowLw(mStatusBarWindow, mStatusBarWindow.mAttrs); + displayPolicy.addWindowLw(mNavBarWindow, mNavBarWindow.mAttrs); final Configuration config90 = new Configuration(); mDisplayContent.computeScreenConfiguration(config90, ROTATION_90); @@ -1080,6 +1086,12 @@ public class DisplayContentTests extends WindowTestsBase { ROTATION_0 /* oldRotation */, ROTATION_90 /* newRotation */, false /* forceUpdate */)); + assertNotNull(mDisplayContent.getFixedRotationAnimationController()); + assertTrue(mStatusBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS, + ANIMATION_TYPE_FIXED_TRANSFORM)); + assertTrue(mNavBarWindow.getParent().isAnimating(WindowContainer.AnimationFlags.PARENTS, + ANIMATION_TYPE_FIXED_TRANSFORM)); + final Rect outFrame = new Rect(); final Rect outInsets = new Rect(); final Rect outStableInsets = new Rect(); @@ -1132,6 +1144,25 @@ public class DisplayContentTests extends WindowTestsBase { assertFalse(app.hasFixedRotationTransform()); assertFalse(app2.hasFixedRotationTransform()); assertEquals(config90.orientation, mDisplayContent.getConfiguration().orientation); + assertNull(mDisplayContent.getFixedRotationAnimationController()); + } + + @Test + public void testRotateSeamlesslyWithFixedRotation() { + final DisplayRotation displayRotation = mDisplayContent.getDisplayRotation(); + final ActivityRecord app = mAppWindow.mActivityRecord; + mDisplayContent.setFixedRotationLaunchingAppUnchecked(app); + mAppWindow.mAttrs.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_ROTATE; + + // Use seamless rotation if the top app is rotated. + assertTrue(displayRotation.shouldRotateSeamlessly(ROTATION_0 /* oldRotation */, + ROTATION_90 /* newRotation */, false /* forceUpdate */)); + + mDisplayContent.mFixedRotationTransitionListener.onStartRecentsAnimation(app); + + // Use normal rotation because animating recents is an intermediate state. + assertFalse(displayRotation.shouldRotateSeamlessly(ROTATION_0 /* oldRotation */, + ROTATION_90 /* newRotation */, false /* forceUpdate */)); } @Test @@ -1310,7 +1341,7 @@ public class DisplayContentTests extends WindowTestsBase { } private static int getRotatedOrientation(DisplayContent dc) { - return dc.getLastOrientation() == SCREEN_ORIENTATION_LANDSCAPE + return dc.mBaseDisplayWidth > dc.mBaseDisplayHeight ? SCREEN_ORIENTATION_PORTRAIT : SCREEN_ORIENTATION_LANDSCAPE; } diff --git a/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java new file mode 100644 index 000000000000..ca739c0dd389 --- /dev/null +++ b/services/tests/wmtests/src/com/android/server/wm/ImeInsetsSourceProviderTest.java @@ -0,0 +1,59 @@ +/* + * 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.wm; + +import static android.view.InsetsState.ITYPE_IME; +import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION; + +import static org.junit.Assert.assertTrue; + +import android.graphics.PixelFormat; +import android.platform.test.annotations.Presubmit; +import android.view.InsetsSource; + +import androidx.test.filters.SmallTest; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +@SmallTest +@Presubmit +@RunWith(WindowTestRunner.class) +public class ImeInsetsSourceProviderTest extends WindowTestsBase { + + private InsetsSource mImeSource = new InsetsSource(ITYPE_IME); + private ImeInsetsSourceProvider mImeProvider; + + @Before + public void setUp() throws Exception { + mImeSource.setVisible(true); + mImeProvider = new ImeInsetsSourceProvider(mImeSource, + mDisplayContent.getInsetsStateController(), mDisplayContent); + } + + @Test + public void testTransparentControlTargetWindowCanShowIme() { + final WindowState appWin = createWindow(null, TYPE_APPLICATION, "app"); + final WindowState popup = createWindow(appWin, TYPE_APPLICATION, "popup"); + mDisplayContent.mInputMethodControlTarget = popup; + mDisplayContent.mInputMethodTarget = appWin; + popup.mAttrs.format = PixelFormat.TRANSPARENT; + mImeProvider.scheduleShowImePostLayout(appWin); + assertTrue(mImeProvider.isImeTargetFromDisplayContentAndImeSame()); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java index f330f0fc9f0b..ca6679d1eece 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java @@ -343,7 +343,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { initializeRecentsAnimationController(mController, homeActivity); - assertEquals(homeActivity, mDefaultDisplay.getFixedRotationLaunchingApp()); + assertTrue(mDefaultDisplay.isFixedRotationLaunchingApp(homeActivity)); // Check that the home app is in portrait assertEquals(Configuration.ORIENTATION_PORTRAIT, @@ -353,7 +353,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // top rotated record should be cleared. mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); assertFalse(homeActivity.hasFixedRotationTransform()); - assertNull(mDefaultDisplay.getFixedRotationLaunchingApp()); + assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); } @Test @@ -367,7 +367,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { (mDefaultDisplay.getRotation() + 1) % 4); assertTrue(activity.hasFixedRotationTransform()); - assertEquals(activity, mDefaultDisplay.getFixedRotationLaunchingApp()); + assertTrue(mDefaultDisplay.isFixedRotationLaunchingApp(activity)); // Before the transition is done, the recents animation is triggered. initializeRecentsAnimationController(mController, homeActivity); @@ -377,7 +377,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { mController.cleanupAnimation(REORDER_MOVE_TO_ORIGINAL_POSITION); // The rotation transform should be cleared after updating orientation with display. assertFalse(activity.hasFixedRotationTransform()); - assertNull(mDefaultDisplay.getFixedRotationLaunchingApp()); + assertFalse(mDefaultDisplay.hasTopFixedRotationLaunchingApp()); } @Test @@ -436,7 +436,7 @@ public class RecentsAnimationControllerTest extends WindowTestsBase { // The transform state should keep because we expect to listen the signal from the // transition executed by moving the task to front. assertTrue(homeActivity.hasFixedRotationTransform()); - assertEquals(homeActivity, mDefaultDisplay.getFixedRotationLaunchingApp()); + assertTrue(mDefaultDisplay.isFixedRotationLaunchingApp(homeActivity)); mDefaultDisplay.mFixedRotationTransitionListener.onAppTransitionFinishedLocked( homeActivity.token); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java index 8ce5daa635f2..e9ed20bd9683 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowStateTests.java @@ -603,6 +603,29 @@ public class WindowStateTests extends WindowTestsBase { } @Test + public void testRequestResizeForBlastSync() { + final WindowState win = mChildAppWindowAbove; + makeWindowVisible(win, win.getParentWindow()); + win.mLayoutSeq = win.getDisplayContent().mLayoutSeq; + win.reportResized(); + win.updateResizingWindowIfNeeded(); + assertThat(mWm.mResizingWindows).doesNotContain(win); + + // Check that the window is in resizing if using blast sync. + win.reportResized(); + win.prepareForSync(mock(BLASTSyncEngine.TransactionReadyListener.class), 1); + win.updateResizingWindowIfNeeded(); + assertThat(mWm.mResizingWindows).contains(win); + + // Don't re-add the window again if it's been reported to the client and still waiting on + // the client draw for blast sync. + win.reportResized(); + mWm.mResizingWindows.remove(win); + win.updateResizingWindowIfNeeded(); + assertThat(mWm.mResizingWindows).doesNotContain(win); + } + + @Test public void testGetTransformationMatrix() { final int PARENT_WINDOW_OFFSET = 1; final int DISPLAY_IN_PARENT_WINDOW_OFFSET = 2; diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java index ef282ba110c5..cf07221917cc 100644 --- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerService.java @@ -56,6 +56,8 @@ import android.os.Parcel; import android.os.RemoteCallback; import android.os.RemoteCallbackList; import android.os.RemoteException; +import android.os.ResultReceiver; +import android.os.ShellCallback; import android.os.Trace; import android.os.UserHandle; import android.os.UserManagerInternal; @@ -1391,6 +1393,13 @@ public class VoiceInteractionManagerService extends SystemService { } @Override + public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, + String[] args, ShellCallback callback, ResultReceiver resultReceiver) { + new VoiceInteractionManagerServiceShellCommand(mServiceStub) + .exec(this, in, out, err, args, callback, resultReceiver); + } + + @Override public void setUiHints(Bundle hints) { synchronized (this) { enforceIsCurrentVoiceInteractionService(); diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java new file mode 100644 index 000000000000..3f4ddb6846ab --- /dev/null +++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceShellCommand.java @@ -0,0 +1,135 @@ +/* + * 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.voiceinteraction; + +import android.os.Bundle; +import android.os.RemoteException; +import android.os.ShellCommand; +import android.util.Slog; + +import com.android.internal.app.IVoiceInteractionSessionShowCallback; +import com.android.server.voiceinteraction.VoiceInteractionManagerService.VoiceInteractionManagerServiceStub; + +import java.io.PrintWriter; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; + +/** + * Shell command for {@link VoiceInteractionManagerService}. + */ +final class VoiceInteractionManagerServiceShellCommand extends ShellCommand { + private static final String TAG = "VoiceInteractionManager"; + private static final long TIMEOUT_MS = 5_000; + + private final VoiceInteractionManagerServiceStub mService; + + VoiceInteractionManagerServiceShellCommand(VoiceInteractionManagerServiceStub service) { + mService = service; + } + + @Override + public int onCommand(String cmd) { + if (cmd == null) { + return handleDefaultCommands(cmd); + } + PrintWriter pw = getOutPrintWriter(); + switch (cmd) { + case "show": + return requestShow(pw); + case "hide": + return requestHide(pw); + default: + return handleDefaultCommands(cmd); + } + } + + @Override + public void onHelp() { + try (PrintWriter pw = getOutPrintWriter();) { + pw.println("VoiceInteraction Service (voiceinteraction) commands:"); + pw.println(" help"); + pw.println(" Prints this help text."); + pw.println(""); + pw.println(" show"); + pw.println(" Shows a session for the active service"); + pw.println(""); + pw.println(" hide"); + pw.println(" Hides the current session"); + pw.println(""); + } + } + + private int requestShow(PrintWriter pw) { + Slog.i(TAG, "requestShow()"); + CountDownLatch latch = new CountDownLatch(1); + AtomicInteger result = new AtomicInteger(); + + IVoiceInteractionSessionShowCallback callback = + new IVoiceInteractionSessionShowCallback.Stub() { + @Override + public void onFailed() throws RemoteException { + Slog.w(TAG, "onFailed()"); + pw.println("callback failed"); + result.set(1); + latch.countDown(); + } + + @Override + public void onShown() throws RemoteException { + Slog.d(TAG, "onShown()"); + result.set(0); + latch.countDown(); + } + }; + + try { + Bundle args = new Bundle(); + boolean ok = mService.showSessionForActiveService(args, /* sourceFlags= */ 0, callback, + /* activityToken= */ null); + + if (!ok) { + pw.println("showSessionForActiveService() returned false"); + return 1; + } + + if (!latch.await(TIMEOUT_MS, TimeUnit.MILLISECONDS)) { + pw.printf("Callback not called in %d ms\n", TIMEOUT_MS); + return 1; + } + } catch (Exception e) { + return handleError(pw, "showSessionForActiveService()", e); + } + + return 0; + } + + private int requestHide(PrintWriter pw) { + Slog.i(TAG, "requestHide()"); + try { + mService.hideCurrentSession(); + } catch (Exception e) { + return handleError(pw, "requestHide()", e); + } + return 0; + } + + private static int handleError(PrintWriter pw, String message, Exception e) { + Slog.e(TAG, "error calling " + message, e); + pw.printf("Error calling %s: %s\n", message, e); + return 1; + } +} diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java index f5ed64ebf3fb..fadebaa7bb8a 100644 --- a/telephony/java/android/telephony/TelephonyManager.java +++ b/telephony/java/android/telephony/TelephonyManager.java @@ -12716,7 +12716,6 @@ public class TelephonyManager { @Nullable String mvnoMatchData) { try { if (!mccmnc.equals(getSimOperator())) { - Log.d(TAG, "The mccmnc does not match"); return false; } ITelephony service = getITelephony(); diff --git a/telephony/java/android/telephony/ims/ImsMmTelManager.java b/telephony/java/android/telephony/ims/ImsMmTelManager.java index 43db1d9ce8a4..f6c14e67306b 100644 --- a/telephony/java/android/telephony/ims/ImsMmTelManager.java +++ b/telephony/java/android/telephony/ims/ImsMmTelManager.java @@ -518,9 +518,6 @@ public class ImsMmTelManager implements RegistrationManager { * @param executor The executor the callback events should be run on. * @param c The MmTel {@link CapabilityCallback} to be registered. * @see #unregisterMmTelCapabilityCallback(CapabilityCallback) - * @throws IllegalArgumentException if the subscription associated with this callback is not - * active (SIM is not inserted, ESIM inactive) or invalid, or a null {@link Executor} or - * {@link CapabilityCallback} callback. * @throws ImsException if the subscription associated with this callback is valid, but * the {@link ImsService} associated with the subscription is not available. This can happen if * the service crashed, for example. See {@link ImsException#getCode()} for a more detailed @@ -543,18 +540,13 @@ public class ImsMmTelManager implements RegistrationManager { ITelephony iTelephony = getITelephony(); if (iTelephony == null) { throw new ImsException("Could not find Telephony Service.", - ImsException.CODE_ERROR_INVALID_SUBSCRIPTION); + ImsException.CODE_ERROR_SERVICE_UNAVAILABLE); } try { iTelephony.registerMmTelCapabilityCallback(mSubId, c.getBinder()); } catch (ServiceSpecificException e) { - if (e.errorCode == ImsException.CODE_ERROR_INVALID_SUBSCRIPTION) { - // Rethrow as runtime error to keep API compatible. - throw new IllegalArgumentException(e.getMessage()); - } else { - throw new ImsException(e.getMessage(), e.errorCode); - } + throw new ImsException(e.getMessage(), e.errorCode); } catch (RemoteException e) { throw e.rethrowAsRuntimeException(); } catch (IllegalStateException e) { diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java index 7d750b7bf690..1a58f17ef6a0 100644 --- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java +++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java @@ -115,7 +115,7 @@ public class AppLaunch extends InstrumentationTestCase { private static final int BETWEEN_LAUNCH_SLEEP_TIMEOUT = 3000; // 3s between launching apps private static final int PROFILE_SAVE_SLEEP_TIMEOUT = 1000; // Allow 1s for the profile to save private static final int IORAP_TRACE_DURATION_TIMEOUT = 7000; // Allow 7s for trace to complete. - private static final int IORAP_TRIAL_LAUNCH_ITERATIONS = 3; // min 3 launches to merge traces. + private static final int IORAP_TRIAL_LAUNCH_ITERATIONS = 5; // min 5 launches to merge traces. private static final int IORAP_COMPILE_CMD_TIMEOUT = 60; // in seconds: 1 minutes private static final int IORAP_COMPILE_MIN_TRACES = 1; // configure iorapd to need 1 trace. private static final int IORAP_COMPILE_RETRIES = 3; // retry compiler 3 times if it fails. diff --git a/tests/BlobStoreTestUtils/Android.bp b/tests/BlobStoreTestUtils/Android.bp index 829c883913e1..53d36389a52a 100644 --- a/tests/BlobStoreTestUtils/Android.bp +++ b/tests/BlobStoreTestUtils/Android.bp @@ -15,6 +15,10 @@ java_library { name: "BlobStoreTestUtils", srcs: ["src/**/*.java"], - static_libs: ["truth-prebuilt"], + static_libs: [ + "truth-prebuilt", + "androidx.test.uiautomator_uiautomator", + "androidx.test.ext.junit", + ], sdk_version: "test_current", }
\ No newline at end of file diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java index 371375c0d932..4a0ca664049a 100644 --- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java +++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/DummyBlobData.java @@ -42,6 +42,7 @@ public class DummyBlobData { private final File mFile; private final long mFileSize; private final CharSequence mLabel; + private final long mExpiryDurationMs; byte[] mFileDigest; long mExpiryTimeMs; @@ -51,6 +52,7 @@ public class DummyBlobData { mFile = new File(builder.getContext().getFilesDir(), builder.getFileName()); mFileSize = builder.getFileSize(); mLabel = builder.getLabel(); + mExpiryDurationMs = builder.getExpiryDurationMs(); } public static class Builder { @@ -59,6 +61,7 @@ public class DummyBlobData { private long mFileSize = DEFAULT_SIZE_BYTES; private CharSequence mLabel = "Test label"; private String mFileName = "blob_" + System.nanoTime(); + private long mExpiryDurationMs = TimeUnit.DAYS.toMillis(1); public Builder(Context context) { mContext = context; @@ -104,6 +107,15 @@ public class DummyBlobData { return mFileName; } + public Builder setExpiryDurationMs(long durationMs) { + mExpiryDurationMs = durationMs; + return this; + } + + public long getExpiryDurationMs() { + return mExpiryDurationMs; + } + public DummyBlobData build() { return new DummyBlobData(this); } @@ -114,7 +126,7 @@ public class DummyBlobData { writeRandomData(file, mFileSize); } mFileDigest = FileUtils.digest(mFile, "SHA-256"); - mExpiryTimeMs = System.currentTimeMillis() + TimeUnit.DAYS.toMillis(1); + mExpiryTimeMs = System.currentTimeMillis() + mExpiryDurationMs; } public BlobHandle getBlobHandle() throws Exception { diff --git a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java index 6927e86213d8..b9bd661dfd67 100644 --- a/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java +++ b/tests/BlobStoreTestUtils/src/com/android/utils/blob/Utils.java @@ -24,6 +24,10 @@ import android.app.blob.LeaseInfo; import android.content.Context; import android.content.res.Resources; import android.os.ParcelFileDescriptor; +import android.util.Log; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.uiautomator.UiDevice; import java.io.FileInputStream; import java.io.FileOutputStream; @@ -32,6 +36,8 @@ import java.io.InputStream; import java.io.OutputStream; public class Utils { + public static final String TAG = "BlobStoreTest"; + public static final int BUFFER_SIZE_BYTES = 16 * 1024; public static final long KB_IN_BYTES = 1000; @@ -68,7 +74,8 @@ public class Utils { public static void assertLeasedBlobs(BlobStoreManager blobStoreManager, BlobHandle... expectedBlobHandles) throws IOException { - assertThat(blobStoreManager.getLeasedBlobs()).containsExactly(expectedBlobHandles); + assertThat(blobStoreManager.getLeasedBlobs()).containsExactly( + (Object[]) expectedBlobHandles); } public static void assertNoLeasedBlobs(BlobStoreManager blobStoreManager) @@ -141,4 +148,16 @@ public class Utils { assertThat(leaseInfo.getDescriptionResId()).isEqualTo(descriptionResId); assertThat(leaseInfo.getDescription()).isEqualTo(description); } + + public static void triggerIdleMaintenance() throws IOException { + runShellCmd("cmd blob_store idle-maintenance"); + } + + public static String runShellCmd(String cmd) throws IOException { + final UiDevice uiDevice = UiDevice.getInstance( + InstrumentationRegistry.getInstrumentation()); + final String result = uiDevice.executeShellCommand(cmd).trim(); + Log.i(TAG, "Output of '" + cmd + "': '" + result + "'"); + return result; + } } diff --git a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java index d011dbbbe5db..ae93a81f274e 100644 --- a/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java +++ b/tests/PackageWatchdog/src/com/android/server/PackageWatchdogTest.java @@ -1113,6 +1113,7 @@ public class PackageWatchdogTest { mTestLooper.dispatchAll(); List<Set> expectedSyncRequests = List.of( + Set.of(), Set.of(APP_A), Set.of(APP_A, APP_B), Set.of(APP_A, APP_B, APP_C), diff --git a/tests/net/java/android/net/NetworkStatsTest.java b/tests/net/java/android/net/NetworkStatsTest.java index 98f705f45e98..735fa7cf3751 100644 --- a/tests/net/java/android/net/NetworkStatsTest.java +++ b/tests/net/java/android/net/NetworkStatsTest.java @@ -909,8 +909,8 @@ public class NetworkStatsTest { 13805 /* txPackets */, 0 /* operations */); - // Traffic measured for the root uid on the base interface if eBPF is in use. - final NetworkStats.Entry ebpfRootUidEntry = new NetworkStats.Entry( + // Traffic measured for the root uid on the base interface. + final NetworkStats.Entry rootUidEntry = new NetworkStats.Entry( baseIface, rootUid, SET_DEFAULT, TAG_NONE, 163577 /* rxBytes */, 187 /* rxPackets */, @@ -918,17 +918,6 @@ public class NetworkStatsTest { 97 /* txPackets */, 0 /* operations */); - // Traffic measured for the root uid on the base interface if xt_qtaguid is in use. - // Incorrectly includes appEntry's bytes and packets, plus IPv4-IPv6 translation - // overhead (20 bytes per packet), in rx direction. - final NetworkStats.Entry xtRootUidEntry = new NetworkStats.Entry( - baseIface, rootUid, SET_DEFAULT, TAG_NONE, - 31113087 /* rxBytes */, - 22588 /* rxPackets */, - 17607 /* txBytes */, - 97 /* txPackets */, - 0 /* operations */); - final NetworkStats.Entry otherEntry = new NetworkStats.Entry( otherIface, appUid, SET_DEFAULT, TAG_NONE, 2600 /* rxBytes */, @@ -937,21 +926,14 @@ public class NetworkStatsTest { 3 /* txPackets */, 0 /* operations */); - final NetworkStats statsXt = new NetworkStats(TEST_START, 3) - .insertEntry(appEntry) - .insertEntry(xtRootUidEntry) - .insertEntry(otherEntry); - - final NetworkStats statsEbpf = new NetworkStats(TEST_START, 3) + final NetworkStats stats = new NetworkStats(TEST_START, 3) .insertEntry(appEntry) - .insertEntry(ebpfRootUidEntry) + .insertEntry(rootUidEntry) .insertEntry(otherEntry); - statsXt.apply464xlatAdjustments(stackedIface, false); - statsEbpf.apply464xlatAdjustments(stackedIface, true); + stats.apply464xlatAdjustments(stackedIface); - assertEquals(3, statsXt.size()); - assertEquals(3, statsEbpf.size()); + assertEquals(3, stats.size()); final NetworkStats.Entry expectedAppUid = new NetworkStats.Entry( v4Iface, appUid, SET_DEFAULT, TAG_NONE, 30949510, @@ -966,12 +948,9 @@ public class NetworkStatsTest { 17607, 97, 0); - assertEquals(expectedAppUid, statsXt.getValues(0, null)); - assertEquals(expectedRootUid, statsXt.getValues(1, null)); - assertEquals(otherEntry, statsXt.getValues(2, null)); - assertEquals(expectedAppUid, statsEbpf.getValues(0, null)); - assertEquals(expectedRootUid, statsEbpf.getValues(1, null)); - assertEquals(otherEntry, statsEbpf.getValues(2, null)); + assertEquals(expectedAppUid, stats.getValues(0, null)); + assertEquals(expectedRootUid, stats.getValues(1, null)); + assertEquals(otherEntry, stats.getValues(2, null)); } @Test @@ -996,7 +975,7 @@ public class NetworkStatsTest { .insertEntry(secondEntry); // Empty map: no adjustment - stats.apply464xlatAdjustments(new ArrayMap<>(), false); + stats.apply464xlatAdjustments(new ArrayMap<>()); assertEquals(2, stats.size()); assertEquals(firstEntry, stats.getValues(0, null)); diff --git a/tests/net/java/com/android/internal/net/VpnProfileTest.java b/tests/net/java/com/android/internal/net/VpnProfileTest.java index ceca6f028866..e5daa71c30ea 100644 --- a/tests/net/java/com/android/internal/net/VpnProfileTest.java +++ b/tests/net/java/com/android/internal/net/VpnProfileTest.java @@ -33,7 +33,9 @@ import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.JUnit4; +import java.util.ArrayList; import java.util.Arrays; +import java.util.List; /** Unit tests for {@link VpnProfile}. */ @SmallTest @@ -41,6 +43,9 @@ import java.util.Arrays; public class VpnProfileTest { private static final String DUMMY_PROFILE_KEY = "Test"; + private static final int ENCODED_INDEX_AUTH_PARAMS_INLINE = 23; + private static final int ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS = 24; + @Test public void testDefaults() throws Exception { final VpnProfile p = new VpnProfile(DUMMY_PROFILE_KEY); @@ -67,10 +72,11 @@ public class VpnProfileTest { assertFalse(p.isMetered); assertEquals(1360, p.maxMtu); assertFalse(p.areAuthParamsInline); + assertFalse(p.isRestrictedToTestNetworks); } private VpnProfile getSampleIkev2Profile(String key) { - final VpnProfile p = new VpnProfile(key); + final VpnProfile p = new VpnProfile(key, true /* isRestrictedToTestNetworks */); p.name = "foo"; p.type = VpnProfile.TYPE_IKEV2_IPSEC_USER_PASS; @@ -116,7 +122,7 @@ public class VpnProfileTest { @Test public void testParcelUnparcel() { - assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 22); + assertParcelSane(getSampleIkev2Profile(DUMMY_PROFILE_KEY), 23); } @Test @@ -159,14 +165,41 @@ public class VpnProfileTest { assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooManyValues)); } + private String getEncodedDecodedIkev2ProfileMissingValues(int... missingIndices) { + // Sort to ensure when we remove, we can do it from greatest first. + Arrays.sort(missingIndices); + + final String encoded = new String(getSampleIkev2Profile(DUMMY_PROFILE_KEY).encode()); + final List<String> parts = + new ArrayList<>(Arrays.asList(encoded.split(VpnProfile.VALUE_DELIMITER))); + + // Remove from back first to ensure indexing is consistent. + for (int i = missingIndices.length - 1; i >= 0; i--) { + parts.remove(missingIndices[i]); + } + + return String.join(VpnProfile.VALUE_DELIMITER, parts.toArray(new String[0])); + } + @Test public void testEncodeDecodeInvalidNumberOfValues() { - final VpnProfile profile = getSampleIkev2Profile(DUMMY_PROFILE_KEY); - final String encoded = new String(profile.encode()); - final byte[] tooFewValues = - encoded.substring(0, encoded.lastIndexOf(VpnProfile.VALUE_DELIMITER)).getBytes(); + final String tooFewValues = + getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_AUTH_PARAMS_INLINE, + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); - assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues)); + assertNull(VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes())); + } + + @Test + public void testEncodeDecodeMissingIsRestrictedToTestNetworks() { + final String tooFewValues = + getEncodedDecodedIkev2ProfileMissingValues( + ENCODED_INDEX_RESTRICTED_TO_TEST_NETWORKS /* missingIndices */); + + // Verify decoding without isRestrictedToTestNetworks defaults to false + final VpnProfile decoded = VpnProfile.decode(DUMMY_PROFILE_KEY, tooFewValues.getBytes()); + assertFalse(decoded.isRestrictedToTestNetworks); } @Test diff --git a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java index 4473492d7972..e4996d981fac 100644 --- a/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java +++ b/tests/net/java/com/android/server/net/NetworkStatsFactoryTest.java @@ -446,7 +446,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { assertStatsEntry(stats, "v4-wlan0", 1000, SET_DEFAULT, 0x0, 30812L, 2310L); assertStatsEntry(stats, "v4-wlan0", 10102, SET_DEFAULT, 0x0, 10022L, 3330L); assertStatsEntry(stats, "v4-wlan0", 10060, SET_DEFAULT, 0x0, 9532772L, 254112L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 15229L, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, 0L, 0L); assertStatsEntry(stats, "wlan0", 1000, SET_DEFAULT, 0x0, 6126L, 2013L); assertStatsEntry(stats, "wlan0", 10013, SET_DEFAULT, 0x0, 0L, 144L); assertStatsEntry(stats, "wlan0", 10018, SET_DEFAULT, 0x0, 5980263L, 167667L); @@ -468,9 +468,7 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { long appRxBytesAfter = 439237478L; assertEquals("App traffic should be ~100MB", 110553449, appRxBytesAfter - appRxBytesBefore); - long rootRxBytesBefore = 1394011L; - long rootRxBytesAfter = 1398634L; - assertEquals("UID 0 traffic should be ~0", 4623, rootRxBytesAfter - rootRxBytesBefore); + long rootRxBytes = 330187296L; mFactory.noteStackedIface("v4-wlan0", "wlan0"); NetworkStats stats; @@ -478,12 +476,12 @@ public class NetworkStatsFactoryTest extends NetworkStatsBaseTest { // Stats snapshot before the download stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_before); assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesBefore, 5199872L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesBefore, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L); // Stats snapshot after the download stats = parseDetailedStats(R.raw.xt_qtaguid_with_clat_100mb_download_after); assertStatsEntry(stats, "v4-wlan0", 10106, SET_FOREGROUND, 0x0, appRxBytesAfter, 7867488L); - assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytesAfter, 0L); + assertStatsEntry(stats, "wlan0", 0, SET_DEFAULT, 0x0, rootRxBytes, 0L); } /** diff --git a/tests/net/res/raw/xt_qtaguid_with_clat b/tests/net/res/raw/xt_qtaguid_with_clat index 6cd7499545be..f04b32f08332 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat +++ b/tests/net/res/raw/xt_qtaguid_with_clat @@ -7,7 +7,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 7 v4-wlan0 0x0 10060 1 1448660 1041 31192 753 1448660 1041 0 0 0 0 31192 753 0 0 0 0 8 v4-wlan0 0x0 10102 0 9702 16 2870 23 9702 16 0 0 0 0 2870 23 0 0 0 0 9 v4-wlan0 0x0 10102 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -10 wlan0 0x0 0 0 11058671 7892 0 0 11043898 7811 13117 61 1656 20 0 0 0 0 0 0 +10 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 11 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 12 wlan0 0x0 1000 0 6126 13 2013 16 5934 11 192 2 0 0 1821 14 192 2 0 0 13 wlan0 0x0 1000 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 @@ -41,5 +41,3 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 41 dummy0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 lo 0x0 0 0 1288 16 1288 16 0 0 532 8 756 8 0 0 532 8 756 8 43 lo 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -44 wlan0 0x0 1029 0 0 0 312046 5113 0 0 0 0 0 0 306544 5046 3230 38 2272 29 -45 wlan0 0x0 1029 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
\ No newline at end of file diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after index 9f86153a33cf..12d98ca29f57 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after +++ b/tests/net/res/raw/xt_qtaguid_with_clat_100mb_download_after @@ -9,7 +9,7 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packe 9 v4-wlan0 0x0 10057 1 728 7 392 7 0 0 728 7 0 0 0 0 392 7 0 0 10 v4-wlan0 0x0 10106 0 2232 18 2232 18 0 0 2232 18 0 0 0 0 2232 18 0 0 11 v4-wlan0 0x0 10106 1 432952718 314238 5442288 121260 432950238 314218 2480 20 0 0 5433900 121029 8388 231 0 0 -12 wlan0 0x0 0 0 440746376 329772 0 0 439660007 315369 232001 1276 854368 13127 0 0 0 0 0 0 +12 wlan0 0x0 0 0 330187296 250652 0 0 329106990 236273 226202 1255 854104 13124 0 0 0 0 0 0 13 wlan0 0x0 0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 14 wlan0 0x0 1000 0 77113 272 56151 575 77113 272 0 0 0 0 19191 190 36960 385 0 0 15 wlan0 0x0 1000 1 20227 80 8356 72 18539 74 1688 6 0 0 7562 66 794 6 0 0 diff --git a/tests/net/res/raw/xt_qtaguid_with_clat_simple b/tests/net/res/raw/xt_qtaguid_with_clat_simple index b37fae6d2a3d..a1d6d411bad8 100644 --- a/tests/net/res/raw/xt_qtaguid_with_clat_simple +++ b/tests/net/res/raw/xt_qtaguid_with_clat_simple @@ -1,5 +1,4 @@ idx iface acct_tag_hex uid_tag_int cnt_set rx_bytes rx_packets tx_bytes tx_packets rx_tcp_bytes rx_tcp_packets rx_udp_bytes rx_udp_packets rx_other_bytes rx_other_packets tx_tcp_bytes tx_tcp_packets tx_udp_bytes tx_udp_packets tx_other_bytes tx_other_packets 2 v4-wlan0 0x0 10060 0 42600 213 4100 41 42600 213 0 0 0 0 4100 41 0 0 0 0 3 v4-wlan0 0x0 10060 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 -4 wlan0 0x0 0 0 46860 213 0 0 46860 213 0 0 0 0 0 0 0 0 0 0 -5 wlan0 0x0 1029 0 0 0 4920 41 0 0 0 0 0 0 4920 41 0 0 0 0 +4 wlan0 0x0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 diff --git a/wifi/Android.bp b/wifi/Android.bp index 1e2c81a60178..fe1938d07533 100644 --- a/wifi/Android.bp +++ b/wifi/Android.bp @@ -120,6 +120,8 @@ java_library { "android.hardware.wifi", "android.net.wifi", "android.x.net.wifi", + // Created by jarjar rules. + "com.android.wifi.x", ], } |