diff options
311 files changed, 5883 insertions, 2549 deletions
diff --git a/StubLibraries.bp b/StubLibraries.bp index 60f6174740df..f06f2792e0d7 100644 --- a/StubLibraries.bp +++ b/StubLibraries.bp @@ -256,18 +256,16 @@ droidstubs { ///////////////////////////////////////////////////////////////////// java_defaults { - name: "framework-stubs-default", + name: "android_defaults_stubs_current", libs: [ "stub-annotations" ], static_libs: [ "private-stub-annotations-jar" ], - sdk_version: "core_current", errorprone: { javacflags: [ "-XepDisableAllChecks", ], }, - java_resources: [ - ":notices-for-framework-stubs", - ], + java_resources: [":notices-for-framework-stubs"], + sdk_version: "none", system_modules: "none", java_version: "1.8", compile_dex: true, @@ -276,25 +274,25 @@ java_defaults { java_library_static { name: "android_stubs_current", srcs: [ ":api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_system_stubs_current", srcs: [ ":system-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_test_stubs_current", srcs: [ ":test-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], } java_library_static { name: "android_module_lib_stubs_current", srcs: [ ":module-lib-api-stubs-docs" ], - defaults: ["framework-stubs-default"], + defaults: ["android_defaults_stubs_current"], libs: ["android_system_stubs_current"], } diff --git a/apex/Android.bp b/apex/Android.bp index 5f418d47f090..67cd0d7fcd1e 100644 --- a/apex/Android.bp +++ b/apex/Android.bp @@ -67,7 +67,7 @@ stubs_defaults { name: "framework-module-stubs-defaults-publicapi", args: mainline_framework_stubs_args, installable: false, - sdk_version: "current", + sdk_version: "module_current", filter_packages: framework_packages_to_document, check_api: { current: { @@ -86,7 +86,7 @@ stubs_defaults { args: mainline_framework_stubs_args + priv_apps, libs: ["framework-annotations-lib"], installable: false, - sdk_version: "system_current", + sdk_version: "module_current", filter_packages: framework_packages_to_document, check_api: { current: { diff --git a/apex/blobstore/framework/java/android/app/blob/XmlTags.java b/apex/blobstore/framework/java/android/app/blob/XmlTags.java index e64edc393769..dbfdcba05a73 100644 --- a/apex/blobstore/framework/java/android/app/blob/XmlTags.java +++ b/apex/blobstore/framework/java/android/app/blob/XmlTags.java @@ -48,6 +48,7 @@ public final class XmlTags { // For committer public static final String TAG_COMMITTER = "c"; + public static final String ATTR_COMMIT_TIME_MS = "cmt"; // For leasee public static final String TAG_LEASEE = "l"; 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 c8ca44b6ef74..49b3ec1d113b 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java @@ -15,6 +15,7 @@ */ package com.android.server.blob; +import static android.app.blob.XmlTags.ATTR_COMMIT_TIME_MS; import static android.app.blob.XmlTags.ATTR_DESCRIPTION; import static android.app.blob.XmlTags.ATTR_DESCRIPTION_RES_NAME; import static android.app.blob.XmlTags.ATTR_EXPIRY_TIME; @@ -30,6 +31,7 @@ import static android.os.Process.INVALID_UID; import static android.system.OsConstants.O_RDONLY; import static com.android.server.blob.BlobStoreConfig.TAG; +import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_COMMIT_TIME; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_DESC_RES_NAME; import static com.android.server.blob.BlobStoreConfig.XML_VERSION_ADD_STRING_DESC; import static com.android.server.blob.BlobStoreConfig.hasLeaseWaitTimeElapsed; @@ -54,6 +56,7 @@ import android.util.Slog; import android.util.SparseArray; import com.android.internal.annotations.GuardedBy; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.XmlUtils; import com.android.server.blob.BlobStoreManagerService.DumpArgs; @@ -125,7 +128,7 @@ class BlobMetadata { } } - void addCommitters(ArraySet<Committer> committers) { + void setCommitters(ArraySet<Committer> committers) { synchronized (mMetadataLock) { mCommitters.clear(); mCommitters.addAll(committers); @@ -153,11 +156,16 @@ class BlobMetadata { } @Nullable - Committer getExistingCommitter(@NonNull Committer newCommitter) { + Committer getExistingCommitter(@NonNull String packageName, int uid) { synchronized (mCommitters) { - final int index = mCommitters.indexOf(newCommitter); - return index >= 0 ? mCommitters.valueAt(index) : null; + for (int i = 0, size = mCommitters.size(); i < size; ++i) { + final Committer committer = mCommitters.valueAt(i); + if (committer.uid == uid && committer.packageName.equals(packageName)) { + return committer; + } + } } + return null; } void addOrReplaceLeasee(String callingPackage, int callingUid, int descriptionResId, @@ -172,7 +180,7 @@ class BlobMetadata { } } - void addLeasees(ArraySet<Leasee> leasees) { + void setLeasees(ArraySet<Leasee> leasees) { synchronized (mMetadataLock) { mLeasees.clear(); mLeasees.addAll(leasees); @@ -380,8 +388,7 @@ class BlobMetadata { } // Blobs with no active leases - // TODO: Track commit time instead of using last modified time. - if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsed(getBlobFile().lastModified())) + if ((!respectLeaseWaitTime || hasLeaseWaitTimeElapsedForAll()) && !hasLeases()) { return true; } @@ -389,6 +396,17 @@ class BlobMetadata { return false; } + @VisibleForTesting + boolean hasLeaseWaitTimeElapsedForAll() { + for (int i = 0, size = mCommitters.size(); i < size; ++i) { + final Committer committer = mCommitters.valueAt(i); + if (!hasLeaseWaitTimeElapsed(committer.getCommitTimeMs())) { + return false; + } + } + return true; + } + void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) { fout.println("blobHandle:"); fout.increaseIndent(); @@ -492,20 +510,28 @@ class BlobMetadata { } final BlobMetadata blobMetadata = new BlobMetadata(context, blobId, blobHandle, userId); - blobMetadata.addCommitters(committers); - blobMetadata.addLeasees(leasees); + blobMetadata.setCommitters(committers); + blobMetadata.setLeasees(leasees); return blobMetadata; } static final class Committer extends Accessor { public final BlobAccessMode blobAccessMode; + public final long commitTimeMs; - Committer(String packageName, int uid, BlobAccessMode blobAccessMode) { + Committer(String packageName, int uid, BlobAccessMode blobAccessMode, long commitTimeMs) { super(packageName, uid); this.blobAccessMode = blobAccessMode; + this.commitTimeMs = commitTimeMs; + } + + long getCommitTimeMs() { + return commitTimeMs; } void dump(IndentingPrintWriter fout) { + fout.println("commit time: " + + (commitTimeMs == 0 ? "<null>" : BlobStoreUtils.formatTime(commitTimeMs))); fout.println("accessMode:"); fout.increaseIndent(); blobAccessMode.dump(fout); @@ -515,6 +541,7 @@ class BlobMetadata { void writeToXml(@NonNull XmlSerializer out) throws IOException { XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, packageName); XmlUtils.writeIntAttribute(out, ATTR_UID, uid); + XmlUtils.writeLongAttribute(out, ATTR_COMMIT_TIME_MS, commitTimeMs); out.startTag(null, TAG_ACCESS_MODE); blobAccessMode.writeToXml(out); @@ -526,6 +553,9 @@ class BlobMetadata { throws XmlPullParserException, IOException { final String packageName = XmlUtils.readStringAttribute(in, ATTR_PACKAGE); final int uid = XmlUtils.readIntAttribute(in, ATTR_UID); + final long commitTimeMs = version >= XML_VERSION_ADD_COMMIT_TIME + ? XmlUtils.readLongAttribute(in, ATTR_COMMIT_TIME_MS) + : 0; final int depth = in.getDepth(); BlobAccessMode blobAccessMode = null; @@ -538,7 +568,7 @@ class BlobMetadata { Slog.wtf(TAG, "blobAccessMode should be available"); return null; } - return new Committer(packageName, uid, blobAccessMode); + return new Committer(packageName, uid, blobAccessMode, commitTimeMs); } } 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 f2c158658562..6af1178b55f1 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreConfig.java @@ -45,8 +45,9 @@ class BlobStoreConfig { // Added a string variant of lease description. 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_CURRENT = XML_VERSION_ADD_DESC_RES_NAME; + public static final int XML_VERSION_CURRENT = XML_VERSION_ADD_COMMIT_TIME; private static final String ROOT_DIR_NAME = "blobstore"; private static final String BLOBS_DIR_NAME = "blobs"; @@ -100,6 +101,18 @@ class BlobStoreConfig { public static long LEASE_ACQUISITION_WAIT_DURATION_MS = DEFAULT_LEASE_ACQUISITION_WAIT_DURATION_MS; + /** + * Denotes the duration from the time a blob is committed that any new commits of the same + * data blob from the same committer will be treated as if they occurred at the earlier + * commit time. + */ + public static final String KEY_COMMIT_COOL_OFF_DURATION_MS = + "commit_cool_off_duration_ms"; + public static final long DEFAULT_COMMIT_COOL_OFF_DURATION_MS = + TimeUnit.HOURS.toMillis(48); + public static long COMMIT_COOL_OFF_DURATION_MS = + DEFAULT_COMMIT_COOL_OFF_DURATION_MS; + static void refresh(Properties properties) { if (!NAMESPACE_BLOBSTORE.equals(properties.getNamespace())) { return; @@ -163,6 +176,27 @@ class BlobStoreConfig { < System.currentTimeMillis(); } + /** + * Returns an adjusted commit time depending on whether commit cool-off period has elapsed. + * + * If this is the initial commit or the earlier commit cool-off period has elapsed, then + * the new commit time is used. Otherwise, the earlier commit time is used. + */ + public static long getAdjustedCommitTimeMs(long oldCommitTimeMs, long newCommitTimeMs) { + if (oldCommitTimeMs == 0 || hasCommitCoolOffPeriodElapsed(oldCommitTimeMs)) { + return newCommitTimeMs; + } + return oldCommitTimeMs; + } + + /** + * Returns whether the commit cool-off period has elapsed. + */ + private static boolean hasCommitCoolOffPeriodElapsed(long commitTimeMs) { + return commitTimeMs + DeviceConfigProperties.COMMIT_COOL_OFF_DURATION_MS + < System.currentTimeMillis(); + } + @Nullable public static File prepareBlobFile(long sessionId) { final File blobsDir = prepareBlobsDir(); 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 e472d052f32f..35a2436702da 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java @@ -31,6 +31,7 @@ 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; import static com.android.server.blob.BlobStoreSession.STATE_ABANDONED; import static com.android.server.blob.BlobStoreSession.STATE_COMMITTED; import static com.android.server.blob.BlobStoreSession.STATE_VERIFIED_INVALID; @@ -566,13 +567,18 @@ public class BlobStoreManagerService extends SystemService { userId); BlobMetadata blob = userBlobs.get(session.getBlobHandle()); if (blob == null) { - blob = new BlobMetadata(mContext, - session.getSessionId(), session.getBlobHandle(), userId); + blob = new BlobMetadata(mContext, session.getSessionId(), + session.getBlobHandle(), userId); addBlobForUserLocked(blob, userBlobs); } + final Committer existingCommitter = blob.getExistingCommitter( + session.getOwnerPackageName(), session.getOwnerUid()); + final long existingCommitTimeMs = + (existingCommitter == null) ? 0 : existingCommitter.getCommitTimeMs(); final Committer newCommitter = new Committer(session.getOwnerPackageName(), - session.getOwnerUid(), session.getBlobAccessMode()); - final Committer existingCommitter = blob.getExistingCommitter(newCommitter); + session.getOwnerUid(), session.getBlobAccessMode(), + getAdjustedCommitTimeMs(existingCommitTimeMs, + System.currentTimeMillis())); blob.addOrReplaceCommitter(newCommitter); try { writeBlobsInfoLocked(); diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java index fabce766c237..1d07e88773c3 100644 --- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java +++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreUtils.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.content.Context; import android.content.pm.PackageManager; import android.content.res.Resources; +import android.text.format.TimeMigrationUtils; import android.util.Slog; class BlobStoreUtils { @@ -56,4 +57,9 @@ class BlobStoreUtils { ? Resources.ID_NULL : getDescriptionResourceId(resources, resourceEntryName, packageName); } + + @NonNull + static String formatTime(long timeMs) { + return TimeMigrationUtils.formatMillisWithFixedFormat(timeMs); + } } diff --git a/apex/statsd/aidl/android/os/IStatsd.aidl b/apex/statsd/aidl/android/os/IStatsd.aidl index d5b5949cd032..80308d26a430 100644 --- a/apex/statsd/aidl/android/os/IStatsd.aidl +++ b/apex/statsd/aidl/android/os/IStatsd.aidl @@ -31,6 +31,11 @@ interface IStatsd { oneway void systemRunning(); /** + * Tell the stats daemon that the android system has finished booting. + */ + oneway void bootCompleted(); + + /** * Tell the stats daemon that the StatsCompanionService is up and running. * Two-way binder call so that caller knows message received. */ @@ -182,10 +187,15 @@ interface IStatsd { */ void sendAppBreadcrumbAtom(int label, int state); - /** - * Registers a puller callback function that, when invoked, pulls the data - * for the specified atom tag. - */ + /** + * Tell the stats daemon that all the pullers registered during boot have been sent. + */ + oneway void allPullersFromBootRegistered(); + + /** + * Registers a puller callback function that, when invoked, pulls the data + * for the specified atom tag. + */ oneway void registerPullAtomCallback(int uid, int atomTag, long coolDownMillis, long timeoutMillis,in int[] additiveFields, IPullAtomCallback pullerCallback); diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java index c1ba73f03c06..dc477a5590ea 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanion.java @@ -87,6 +87,9 @@ public class StatsCompanion { if (phase == PHASE_THIRD_PARTY_APPS_CAN_START) { mStatsCompanionService.systemReady(); } + if (phase == PHASE_BOOT_COMPLETED) { + mStatsCompanionService.bootCompleted(); + } } } diff --git a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java index 66e41cca96a7..ce5309e4df52 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java @@ -112,6 +112,18 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { private final HashMap<Long, String> mDeletedFiles = new HashMap<>(); private final CompanionHandler mHandler; + // Flag that is set when PHASE_BOOT_COMPLETED is triggered in the StatsCompanion lifecycle. This + // and the flag mSentBootComplete below is used for synchronization to ensure that the boot + // complete signal is only ever sent once to statsd. Two signals are needed because + // #sayHiToStatsd can be called from both statsd and #onBootPhase + // PHASE_THIRD_PARTY_APPS_CAN_START. + @GuardedBy("sStatsdLock") + private boolean mBootCompleted = false; + // Flag that is set when IStatsd#bootCompleted is called. This flag ensures that boot complete + // signal is only ever sent once. + @GuardedBy("sStatsdLock") + private boolean mSentBootComplete = false; + public StatsCompanionService(Context context) { super(); mContext = context; @@ -688,6 +700,19 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { List.of(appUpdateReceiver, userUpdateReceiver, shutdownEventReceiver)); final long token = Binder.clearCallingIdentity(); + + // Used so we can call statsd.bootComplete() outside of the lock. + boolean shouldSendBootComplete = false; + synchronized (sStatsdLock) { + if (mBootCompleted && !mSentBootComplete) { + mSentBootComplete = true; + shouldSendBootComplete = true; + } + } + if (shouldSendBootComplete) { + statsd.bootCompleted(); + } + try { // Pull the latest state of UID->app name, version mapping when // statsd starts. @@ -749,6 +774,7 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mContext.unregisterReceiver(receiver); } statsdNotReadyLocked(); + mSentBootComplete = false; } } } @@ -758,6 +784,28 @@ public class StatsCompanionService extends IStatsCompanionService.Stub { mStatsManagerService.statsdNotReady(); } + void bootCompleted() { + IStatsd statsd = getStatsdNonblocking(); + synchronized (sStatsdLock) { + mBootCompleted = true; + if (mSentBootComplete) { + // do not send a boot complete a second time. + return; + } + if (statsd == null) { + // Statsd is not yet ready. + // Delay the boot completed ping to {@link #sayHiToStatsd()} + return; + } + mSentBootComplete = true; + } + try { + statsd.bootCompleted(); + } catch (RemoteException e) { + Log.e(TAG, "Failed to notify statsd that boot completed"); + } + } + @Override protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) { if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP) diff --git a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java index 58c78da5cea7..90764b0bd426 100644 --- a/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java +++ b/apex/statsd/service/java/com/android/server/stats/StatsManagerService.java @@ -600,6 +600,7 @@ public class StatsManagerService extends IStatsManagerService.Stub { statsd.registerPullAtomCallback(key.getUid(), key.getAtom(), value.getCoolDownMillis(), value.getTimeoutMillis(), value.getAdditiveFields(), value.getCallback()); } + statsd.allPullersFromBootRegistered(); } // Pre-condition: the Binder calling identity has already been cleared diff --git a/cmds/idmap2/TEST_MAPPING b/cmds/idmap2/TEST_MAPPING index 26ccf038cba2..9e0fb84c7949 100644 --- a/cmds/idmap2/TEST_MAPPING +++ b/cmds/idmap2/TEST_MAPPING @@ -3,5 +3,10 @@ { "name" : "idmap2_tests" } + ], + "imports": [ + { + "path": "frameworks/base/services/core/java/com/android/server/om" + } ] } diff --git a/cmds/idmap2/idmap2d/Idmap2Service.cpp b/cmds/idmap2/idmap2d/Idmap2Service.cpp index e55ea6c00545..75fc7f714ce3 100644 --- a/cmds/idmap2/idmap2d/Idmap2Service.cpp +++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp @@ -149,15 +149,21 @@ Status Idmap2Service::createIdmap(const std::string& target_apk_path, return error(idmap.GetErrorMessage()); } + // idmap files are mapped with mmap in libandroidfw. Deleting and recreating the idmap guarantees + // that existing memory maps will continue to be valid and unaffected. + unlink(idmap_path.c_str()); + umask(kIdmapFilePermissionMask); std::ofstream fout(idmap_path); if (fout.fail()) { return error("failed to open idmap path " + idmap_path); } + BinaryStreamVisitor visitor(fout); (*idmap)->accept(&visitor); fout.close(); if (fout.fail()) { + unlink(idmap_path.c_str()); return error("failed to write to idmap path " + idmap_path); } diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp index 65061d0c9bda..b3579045b6a5 100644 --- a/cmds/statsd/Android.bp +++ b/cmds/statsd/Android.bp @@ -301,6 +301,8 @@ cc_test { "-Wno-unused-parameter", ], + require_root: true, + srcs: [ // atom_field_options.proto needs field_options.proto, but that is // not included in libprotobuf-cpp-lite, so compile it here. @@ -373,10 +375,6 @@ cc_test { include_dirs: ["external/protobuf/src"], }, - shared_libs: [ - "libprotobuf-cpp-lite", - ], - } //############################# diff --git a/cmds/statsd/TEST_MAPPING b/cmds/statsd/TEST_MAPPING new file mode 100644 index 000000000000..8dee073aca22 --- /dev/null +++ b/cmds/statsd/TEST_MAPPING @@ -0,0 +1,7 @@ +{ + "presubmit" : [ + { + "name" : "statsd_test" + } + ] +}
\ No newline at end of file diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp index 9169eb1778d9..dd1d40083a6b 100644 --- a/cmds/statsd/src/StatsService.cpp +++ b/cmds/statsd/src/StatsService.cpp @@ -1054,6 +1054,14 @@ Status StatsService::statsCompanionReady() { return Status::ok(); } +Status StatsService::bootCompleted() { + ENFORCE_UID(AID_SYSTEM); + + VLOG("StatsService::bootCompleted was called"); + + return Status::ok(); +} + void StatsService::Startup() { mConfigManager->Startup(); mProcessor->LoadActiveConfigsFromDisk(); @@ -1215,6 +1223,14 @@ Status StatsService::sendAppBreadcrumbAtom(int32_t label, int32_t state) { return Status::ok(); } +Status StatsService::allPullersFromBootRegistered() { + ENFORCE_UID(AID_SYSTEM); + + VLOG("StatsService::allPullersFromBootRegistered was called"); + + return Status::ok(); +} + Status StatsService::registerPullAtomCallback(int32_t uid, int32_t atomTag, int64_t coolDownMillis, int64_t timeoutMillis, const std::vector<int32_t>& additiveFields, diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h index 114c84f953c8..23d4c1bd199d 100644 --- a/cmds/statsd/src/StatsService.h +++ b/cmds/statsd/src/StatsService.h @@ -64,6 +64,7 @@ public: virtual Status systemRunning(); virtual Status statsCompanionReady(); + virtual Status bootCompleted(); virtual Status informAnomalyAlarmFired(); virtual Status informPollAlarmFired(); virtual Status informAlarmForSubscriberTriggeringFired(); @@ -165,6 +166,11 @@ public: virtual Status sendAppBreadcrumbAtom(int32_t label, int32_t state) override; /** + * Binder call to notify statsd that all pullers from boot have been registered. + */ + virtual Status allPullersFromBootRegistered(); + + /** * Binder call to register a callback function for a pulled atom. */ virtual Status registerPullAtomCallback( diff --git a/cmds/statsd/src/stats_log.proto b/cmds/statsd/src/stats_log.proto index ed98f50bcc48..f4247eca6e23 100644 --- a/cmds/statsd/src/stats_log.proto +++ b/cmds/statsd/src/stats_log.proto @@ -181,12 +181,15 @@ message GaugeBucketInfo { message GaugeMetricData { optional DimensionsValue dimensions_in_what = 1; - optional DimensionsValue dimensions_in_condition = 2 [deprecated = true]; + // Currently unsupported + repeated StateValue slice_by_state = 6; repeated GaugeBucketInfo bucket_info = 3; repeated DimensionsValue dimension_leaf_values_in_what = 4; + optional DimensionsValue dimensions_in_condition = 2 [deprecated = true]; + repeated DimensionsValue dimension_leaf_values_in_condition = 5 [deprecated = true]; } diff --git a/cmds/statsd/tests/StatsLogProcessor_test.cpp b/cmds/statsd/tests/StatsLogProcessor_test.cpp index 9e7b7c820e0d..d29394b1c5a6 100644 --- a/cmds/statsd/tests/StatsLogProcessor_test.cpp +++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp @@ -1564,7 +1564,7 @@ TEST(StatsLogProcessorTest, TestActivationsPersistAcrossSystemServerRestart) { // Trigger Activation 1 for Metric 1. Should activate on boot. // Trigger Activation 4 for Metric 2. Should activate immediately. - long configAddedTimeNs = metricsManager1->mLastReportTimeNs; + int64_t configAddedTimeNs = metricsManager1->mLastReportTimeNs; std::vector<int> attributionUids = {111}; std::vector<string> attributionTags = {"App1"}; std::unique_ptr<LogEvent> event1 = CreateAcquireWakelockEvent( diff --git a/cmds/statsd/tests/StatsService_test.cpp b/cmds/statsd/tests/StatsService_test.cpp index 86f786ef4b15..cc38c4a4067a 100644 --- a/cmds/statsd/tests/StatsService_test.cpp +++ b/cmds/statsd/tests/StatsService_test.cpp @@ -65,7 +65,6 @@ TEST(StatsServiceTest, TestGetUidFromArgs) { args.push(String8("-1")); args.push(String8("0")); args.push(String8("1")); - args.push(String8("9999999999999999999999999999999999")); args.push(String8("a1")); args.push(String8("")); @@ -85,14 +84,11 @@ TEST(StatsServiceTest, TestGetUidFromArgs) { EXPECT_TRUE(service->getUidFromArgs(args, 2, uid)); EXPECT_EQ(1, uid); - // "999999999999999999" - EXPECT_FALSE(service->getUidFromArgs(args, 3, uid)); - // "a1" - EXPECT_FALSE(service->getUidFromArgs(args, 4, uid)); + EXPECT_FALSE(service->getUidFromArgs(args, 3, uid)); // "" - EXPECT_FALSE(service->getUidFromArgs(args, 5, uid)); + EXPECT_FALSE(service->getUidFromArgs(args, 4, uid)); // For a non-userdebug, uid "1" cannot be impersonated. service->mEngBuild = false; diff --git a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp index 69326cb3b2d9..a5da9c8a6f56 100644 --- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp @@ -141,36 +141,38 @@ TEST(CountMetricE2eTest, TestSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(3, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, + data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_UNKNOWN, - data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_OFF, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::view::DisplayStateEnum::DISPLAY_STATE_ON, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); } /** @@ -191,7 +193,9 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { auto syncStartMatcher = CreateSyncStartAtomMatcher(); *config.add_atom_matcher() = syncStartMatcher; - auto state = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto state = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = state; // Create count metric that slices by screen state with on/off map. @@ -321,11 +325,13 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(3, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -333,23 +339,23 @@ TEST(CountMetricE2eTest, TestSlicedStateWithMap) { EXPECT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(4, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(4, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); } /** @@ -499,50 +505,52 @@ TEST(CountMetricE2eTest, TestSlicedStateWithPrimaryFields) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(5, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1 /* StateTracker::kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(2, data.bucket_info(1).count()); - data = reports.reports(0).metrics(0).count_metrics().data(3); + data = countMetrics.data(3); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(4); + data = countMetrics.data(4); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - EXPECT_EQ(2, data.bucket_info(1).count()); } TEST(CountMetricE2eTest, TestMultipleSlicedStates) { @@ -554,7 +562,9 @@ TEST(CountMetricE2eTest, TestMultipleSlicedStates) { CreateSimpleAtomMatcher("APP_CRASH_OCCURRED", util::APP_CRASH_OCCURRED); *config.add_atom_matcher() = appCrashMatcher; - auto state1 = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto state1 = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = state1; auto state2 = CreateUidProcessState(); *config.add_state() = state2; @@ -725,76 +735,78 @@ TEST(CountMetricE2eTest, TestMultipleSlicedStates) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_count_metrics()); - EXPECT_EQ(6, reports.reports(0).metrics(0).count_metrics().data_size()); + StatsLogReport::CountMetricDataWrapper countMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); + EXPECT_EQ(6, countMetrics.data_size()); // For each CountMetricData, check StateValue info is correct and buckets // have correct counts. - auto data = reports.reports(0).metrics(0).count_metrics().data(0); + auto data = countMetrics.data(0); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); - EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_TRUE(data.slice_by_state(0).has_value()); + EXPECT_EQ(-1, data.slice_by_state(0).value()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(1); + data = countMetrics.data(1); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); - EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1, data.slice_by_state(0).value()); + EXPECT_TRUE(data.slice_by_state(0).has_group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(2); + data = countMetrics.data(2); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(2, data.bucket_info(0).count()); - EXPECT_EQ(1, data.bucket_info(1).count()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(3); + data = countMetrics.data(3); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(1, data.bucket_info(0).count()); + EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(2, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(4); + data = countMetrics.data(4); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(1).value()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(1, data.bucket_info(0).count()); - data = reports.reports(0).metrics(0).count_metrics().data(5); + data = countMetrics.data(5); EXPECT_EQ(2, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(1).atom_id()); EXPECT_TRUE(data.slice_by_state(1).has_value()); - EXPECT_EQ(android::app::PROCESS_STATE_TOP, data.slice_by_state(1).value()); - EXPECT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(android::app::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(1).value()); + ASSERT_EQ(2, data.bucket_info_size()); EXPECT_EQ(2, data.bucket_info(0).count()); + EXPECT_EQ(1, data.bucket_info(1).count()); } } // namespace statsd diff --git a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp index 2659944684e1..ba09a353e8b6 100644 --- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp @@ -98,8 +98,9 @@ TEST(DurationMetricE2eTest, TestOneBucket) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -180,8 +181,9 @@ TEST(DurationMetricE2eTest, TestTwoBuckets) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -350,8 +352,9 @@ TEST(DurationMetricE2eTest, TestWithActivation) { EXPECT_EQ(metricId, reports.reports(0).metrics(0).metric_id()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - const StatsLogReport::DurationMetricDataWrapper& durationMetrics = - reports.reports(0).metrics(0).duration_metrics(); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); EXPECT_EQ(1, durationMetrics.data_size()); DurationMetricData data = durationMetrics.data(0); @@ -433,9 +436,12 @@ TEST(DurationMetricE2eTest, TestWithCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate bucket info. EXPECT_EQ(1, data.bucket_info_size()); @@ -532,9 +538,12 @@ TEST(DurationMetricE2eTest, TestWithSlicedCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate dimension value. ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED, appUid); @@ -690,9 +699,12 @@ TEST(DurationMetricE2eTest, TestWithActivationAndSlicedCondition) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(1, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(1, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); // Validate dimension value. ValidateAttributionUidDimension(data.dimensions_in_what(), util::WAKELOCK_STATE_CHANGED, appUid); @@ -811,9 +823,12 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(3, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -826,7 +841,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -839,7 +854,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(370 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); + data = durationMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -970,9 +985,12 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(3, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(3, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -985,7 +1003,7 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -998,7 +1016,7 @@ TEST(DurationMetricE2eTest, TestWithConditionAndSlicedState) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(420 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(2); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); @@ -1020,7 +1038,9 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { auto batterySaverModePredicate = CreateBatterySaverModePredicate(); *config.add_predicate() = batterySaverModePredicate; - auto screenStateWithMap = CreateScreenStateWithOnOffMap(); + int64_t screenOnId = 4444; + int64_t screenOffId = 9876; + auto screenStateWithMap = CreateScreenStateWithOnOffMap(screenOnId, screenOffId); *config.add_state() = screenStateWithMap; // Create duration metric that slices by mapped screen state. @@ -1123,13 +1143,16 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(2, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(2, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_ON"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOnId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); EXPECT_EQ(130 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); @@ -1138,11 +1161,11 @@ TEST(DurationMetricE2eTest, TestWithSlicedStateMapped) { EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); EXPECT_EQ(500 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(SCREEN_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_group_id()); - EXPECT_EQ(StringToId("SCREEN_OFF"), data.slice_by_state(0).group_id()); + EXPECT_EQ(screenOffId, data.slice_by_state(0).group_id()); EXPECT_EQ(2, data.bucket_info_size()); EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); @@ -1314,117 +1337,120 @@ TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) { EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); EXPECT_TRUE(reports.reports(0).metrics(0).has_duration_metrics()); - EXPECT_EQ(9, reports.reports(0).metrics(0).duration_metrics().data_size()); + StatsLogReport::DurationMetricDataWrapper durationMetrics; + sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).duration_metrics(), + &durationMetrics); + EXPECT_EQ(9, durationMetrics.data_size()); - DurationMetricData data = reports.reports(0).metrics(0).duration_metrics().data(0); + DurationMetricData data = durationMetrics.data(0); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(1); + data = durationMetrics.data(1); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); + EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(2); - ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, - "wakelock1"); + data = durationMetrics.data(2); + ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(35 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(3); + data = durationMetrics.data(3); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock1"); + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(240 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(140 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); - EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); - EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(4); + data = durationMetrics.data(4); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, - data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(5); + data = durationMetrics.data(5); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, - "wakelock2"); + "wakelock1"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(2, data.bucket_info_size()); - EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(1, data.bucket_info_size()); + EXPECT_EQ(50 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); - EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); - EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(6); + data = durationMetrics.data(6); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(-1 /* StateTracker:: kStateUnknown */, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(15 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(7); - ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1, - "wakelock1"); + data = durationMetrics.data(7); + ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, + "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); EXPECT_EQ(UID_PROCESS_STATE_ATOM_ID, data.slice_by_state(0).atom_id()); EXPECT_TRUE(data.slice_by_state(0).has_value()); - EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_FOREGROUND, + EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); - EXPECT_EQ(40 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); + ASSERT_EQ(2, data.bucket_info_size()); + EXPECT_EQ(180 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); + EXPECT_EQ(20 * NS_PER_SEC, data.bucket_info(1).duration_nanos()); + EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(1).start_bucket_elapsed_nanos()); + EXPECT_EQ(330 * NS_PER_SEC, data.bucket_info(1).end_bucket_elapsed_nanos()); - data = reports.reports(0).metrics(0).duration_metrics().data(8); + data = durationMetrics.data(8); ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2, "wakelock2"); EXPECT_EQ(1, data.slice_by_state_size()); @@ -1432,7 +1458,7 @@ TEST(DurationMetricE2eTest, TestWithSlicedStatePrimaryFieldsSubset) { EXPECT_TRUE(data.slice_by_state(0).has_value()); EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND, data.slice_by_state(0).value()); - EXPECT_EQ(1, data.bucket_info_size()); + ASSERT_EQ(1, data.bucket_info_size()); EXPECT_EQ(70 * NS_PER_SEC, data.bucket_info(0).duration_nanos()); EXPECT_EQ(10 * NS_PER_SEC, data.bucket_info(0).start_bucket_elapsed_nanos()); EXPECT_EQ(310 * NS_PER_SEC, data.bucket_info(0).end_bucket_elapsed_nanos()); diff --git a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp index f1e2744181ce..ba8d283cabe1 100644 --- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp +++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp @@ -391,7 +391,6 @@ TEST(MetricActivationE2eTest, TestCountMetric) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(4, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -699,7 +698,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithOneDeactivation) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1033,7 +1031,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoDeactivations) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1257,7 +1254,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithSameDeactivation) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(1, reports.reports(0).metrics_size()); - EXPECT_EQ(3, reports.reports(0).metrics(0).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; sortMetricDataByDimensionsValue(reports.reports(0).metrics(0).count_metrics(), &countMetrics); @@ -1695,8 +1691,6 @@ TEST(MetricActivationE2eTest, TestCountMetricWithTwoMetricsTwoDeactivations) { backfillStartEndTimestamp(&reports); EXPECT_EQ(1, reports.reports_size()); EXPECT_EQ(2, reports.reports(0).metrics_size()); - EXPECT_EQ(5, reports.reports(0).metrics(0).count_metrics().data_size()); - EXPECT_EQ(5, reports.reports(0).metrics(1).count_metrics().data_size()); StatsLogReport::CountMetricDataWrapper countMetrics; diff --git a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp index 009e49a5523f..3b4d646f0f2f 100644 --- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp +++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp @@ -3726,7 +3726,8 @@ TEST(ValueMetricProducerTest, TestSlicedStateWithMap) { return true; })); - const StateMap& stateMap = CreateScreenStateOnOffMap(); + const StateMap& stateMap = + CreateScreenStateOnOffMap(/*screen on id=*/321, /*screen off id=*/123); const StateMap_StateGroup screenOnGroup = stateMap.group(0); const StateMap_StateGroup screenOffGroup = stateMap.group(1); diff --git a/cmds/statsd/tests/statsd_test_util.cpp b/cmds/statsd/tests/statsd_test_util.cpp index ed3cf5b96b42..687014f6a298 100644 --- a/cmds/statsd/tests/statsd_test_util.cpp +++ b/cmds/statsd/tests/statsd_test_util.cpp @@ -324,40 +324,29 @@ State CreateOverlayState() { return state; } -State CreateScreenStateWithOnOffMap() { +State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId) { State state; state.set_id(StringToId("ScreenStateOnOff")); state.set_atom_id(util::SCREEN_STATE_CHANGED); - auto map = CreateScreenStateOnOffMap(); + auto map = CreateScreenStateOnOffMap(screenOnId, screenOffId); *state.mutable_map() = map; return state; } -State CreateScreenStateWithInDozeMap() { - State state; - state.set_id(StringToId("ScreenStateInDoze")); - state.set_atom_id(util::SCREEN_STATE_CHANGED); - - auto map = CreateScreenStateInDozeMap(); - *state.mutable_map() = map; - - return state; -} - -StateMap_StateGroup CreateScreenStateOnGroup() { +StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId) { StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_ON")); + group.set_group_id(screenOnId); group.add_value(2); group.add_value(5); group.add_value(6); return group; } -StateMap_StateGroup CreateScreenStateOffGroup() { +StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId) { StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_OFF")); + group.set_group_id(screenOffId); group.add_value(0); group.add_value(1); group.add_value(3); @@ -365,36 +354,10 @@ StateMap_StateGroup CreateScreenStateOffGroup() { return group; } -StateMap CreateScreenStateOnOffMap() { - StateMap map; - *map.add_group() = CreateScreenStateOnGroup(); - *map.add_group() = CreateScreenStateOffGroup(); - return map; -} - -StateMap_StateGroup CreateScreenStateInDozeGroup() { - StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_DOZE")); - group.add_value(3); - group.add_value(4); - return group; -} - -StateMap_StateGroup CreateScreenStateNotDozeGroup() { - StateMap_StateGroup group; - group.set_group_id(StringToId("SCREEN_NOT_DOZE")); - group.add_value(0); - group.add_value(1); - group.add_value(2); - group.add_value(5); - group.add_value(6); - return group; -} - -StateMap CreateScreenStateInDozeMap() { +StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId) { StateMap map; - *map.add_group() = CreateScreenStateInDozeGroup(); - *map.add_group() = CreateScreenStateNotDozeGroup(); + *map.add_group() = CreateScreenStateOnGroup(screenOnId); + *map.add_group() = CreateScreenStateOffGroup(screenOffId); return map; } @@ -1038,6 +1001,27 @@ bool EqualsTo(const DimensionsValue& s1, const DimensionsValue& s2) { } } +bool LessThan(const google::protobuf::RepeatedPtrField<StateValue>& s1, + const google::protobuf::RepeatedPtrField<StateValue>& s2) { + if (s1.size() != s2.size()) { + return s1.size() < s2.size(); + } + for (int i = 0; i < s1.size(); i++) { + const StateValue& state1 = s1[i]; + const StateValue& state2 = s2[i]; + if (state1.atom_id() != state2.atom_id()) { + return state1.atom_id() < state2.atom_id(); + } + if (state1.value() != state2.value()) { + return state1.value() < state2.value(); + } + if (state1.group_id() != state2.group_id()) { + return state1.group_id() < state2.group_id(); + } + } + return false; +} + bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2) { if (s1.field() != s2.field()) { return s1.field() < s2.field(); @@ -1086,7 +1070,7 @@ bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2) { return false; } - return LessThan(s1.dimInCondition, s2.dimInCondition); + return LessThan(s1.stateValues, s2.stateValues); } void backfillStringInDimension(const std::map<uint64_t, string>& str_map, diff --git a/cmds/statsd/tests/statsd_test_util.h b/cmds/statsd/tests/statsd_test_util.h index d6ea77eb2c7d..37b98891797a 100644 --- a/cmds/statsd/tests/statsd_test_util.h +++ b/cmds/statsd/tests/statsd_test_util.h @@ -138,27 +138,16 @@ State CreateUidProcessState(); // Create State proto for overlay state atom. State CreateOverlayState(); -State CreateScreenStateWithOnOffMap(); - -State CreateScreenStateWithInDozeMap(); +State CreateScreenStateWithOnOffMap(int64_t screenOnId, int64_t screenOffId); // Create StateGroup proto for ScreenState ON group -StateMap_StateGroup CreateScreenStateOnGroup(); +StateMap_StateGroup CreateScreenStateOnGroup(int64_t screenOnId); // Create StateGroup proto for ScreenState OFF group -StateMap_StateGroup CreateScreenStateOffGroup(); +StateMap_StateGroup CreateScreenStateOffGroup(int64_t screenOffId); // Create StateMap proto for ScreenState ON/OFF map -StateMap CreateScreenStateOnOffMap(); - -// Create StateGroup proto for ScreenState IN DOZE group -StateMap_StateGroup CreateScreenStateInDozeGroup(); - -// Create StateGroup proto for ScreenState NOT IN DOZE group -StateMap_StateGroup CreateScreenStateNotDozeGroup(); - -// Create StateMap proto for ScreenState IN DOZE map -StateMap CreateScreenStateInDozeMap(); +StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId); // Add a predicate to the predicate combination. void addPredicateToPredicateCombination(const Predicate& predicate, Predicate* combination); @@ -319,12 +308,14 @@ void ValidateAttributionUidAndTagDimension( const DimensionsValue& value, int node_idx, int atomId, int uid, const std::string& tag); struct DimensionsPair { - DimensionsPair(DimensionsValue m1, DimensionsValue m2) : dimInWhat(m1), dimInCondition(m2){}; + DimensionsPair(DimensionsValue m1, google::protobuf::RepeatedPtrField<StateValue> m2) + : dimInWhat(m1), stateValues(m2){}; DimensionsValue dimInWhat; - DimensionsValue dimInCondition; + google::protobuf::RepeatedPtrField<StateValue> stateValues; }; +bool LessThan(const StateValue& s1, const StateValue& s2); bool LessThan(const DimensionsValue& s1, const DimensionsValue& s2); bool LessThan(const DimensionsPair& s1, const DimensionsPair& s2); @@ -393,7 +384,7 @@ void sortMetricDataByDimensionsValue(const T& metricData, T* sortedMetricData) { for (int i = 0; i < metricData.data_size(); ++i) { dimensionIndexMap.insert( std::make_pair(DimensionsPair(metricData.data(i).dimensions_in_what(), - metricData.data(i).dimensions_in_condition()), + metricData.data(i).slice_by_state()), i)); } for (const auto& itr : dimensionIndexMap) { diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java index d00366bd38f4..47ccc2f0badb 100644 --- a/core/java/android/app/ResourcesManager.java +++ b/core/java/android/app/ResourcesManager.java @@ -344,7 +344,7 @@ public class ResourcesManager { ApkAssets apkAssets = null; if (mLoadedApkAssets != null) { apkAssets = mLoadedApkAssets.get(newKey); - if (apkAssets != null) { + if (apkAssets != null && apkAssets.isUpToDate()) { return apkAssets; } } @@ -353,7 +353,7 @@ public class ResourcesManager { final WeakReference<ApkAssets> apkAssetsRef = mCachedApkAssets.get(newKey); if (apkAssetsRef != null) { apkAssets = apkAssetsRef.get(); - if (apkAssets != null) { + if (apkAssets != null && apkAssets.isUpToDate()) { if (mLoadedApkAssets != null) { mLoadedApkAssets.put(newKey, apkAssets); } @@ -1121,7 +1121,9 @@ public class ResourcesManager { daj = new DisplayAdjustments(daj); daj.setCompatibilityInfo(compat); } - daj.setConfiguration(config); + if (displayId == Display.DEFAULT_DISPLAY) { + daj.setConfiguration(config); + } DisplayMetrics dm = getDisplayMetrics(displayId, daj); if (displayId != Display.DEFAULT_DISPLAY) { applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig); diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java index c94d428f4475..6bd8b1d9d7c0 100644 --- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java +++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java @@ -21,7 +21,6 @@ import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE; import static android.content.pm.PackageManager.FEATURE_WATCH; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_BAD_MANIFEST; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES; -import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_NOT_APK; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_ONLY_COREAPP_ALLOWED; import static android.content.pm.PackageManager.INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION; import static android.os.Build.VERSION_CODES.DONUT; @@ -253,10 +252,8 @@ public class ParsingPackageUtils { final File baseApk = new File(lite.baseCodePath); ParseResult<ParsingPackage> result = parseBaseApk(input, baseApk, lite.codePath, assets, flags); - // TODO(b/135203078): Pass original error up? if (result.isError()) { - return input.error(INSTALL_PARSE_FAILED_NOT_APK, - "Failed to parse base APK: " + baseApk); + return input.error(result); } ParsingPackage pkg = result.getResult(); diff --git a/core/java/android/hardware/camera2/params/Capability.java b/core/java/android/hardware/camera2/params/Capability.java index 6f59c5fdcb53..ebb534a48955 100644 --- a/core/java/android/hardware/camera2/params/Capability.java +++ b/core/java/android/hardware/camera2/params/Capability.java @@ -16,8 +16,8 @@ package android.hardware.camera2.params; -import static com.android.internal.util.Preconditions.checkArgumentInRange; import static com.android.internal.util.Preconditions.checkArgumentNonnegative; +import static com.android.internal.util.Preconditions.checkArgumentPositive; import android.annotation.NonNull; import android.hardware.camera2.CameraCharacteristics; @@ -64,9 +64,15 @@ public final class Capability { "maxStreamingWidth must be nonnegative"); mMaxStreamingHeight = checkArgumentNonnegative(maxStreamingHeight, "maxStreamingHeight must be nonnegative"); - mMinZoomRatio = checkArgumentInRange(minZoomRatio, 0.0f, 1.0f, - "minZoomRatio must be between 0.0f and 1.0f"); - mMaxZoomRatio = maxZoomRatio; + + if (minZoomRatio > maxZoomRatio) { + throw new IllegalArgumentException("minZoomRatio " + minZoomRatio + + " is greater than maxZoomRatio " + maxZoomRatio); + } + mMinZoomRatio = checkArgumentPositive(minZoomRatio, + "minZoomRatio must be positive"); + mMaxZoomRatio = checkArgumentPositive(maxZoomRatio, + "maxZoomRatio must be positive"); } /** diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java index e9bcefef50c7..31d7d0820996 100644 --- a/core/java/android/net/NetworkAgent.java +++ b/core/java/android/net/NetworkAgent.java @@ -812,7 +812,7 @@ public abstract class NetworkAgent { * this is the destination the probes are being redirected to, otherwise {@code null}. */ public void onValidationStatus(@ValidationStatus int status, @Nullable Uri redirectUri) { - networkStatus(status, redirectUri.toString()); + networkStatus(status, null == redirectUri ? "" : redirectUri.toString()); } /** @hide TODO delete once subclasses have moved to onValidationStatus */ protected void networkStatus(int status, String redirectUrl) { diff --git a/core/java/android/net/VpnManager.java b/core/java/android/net/VpnManager.java index 2041cfb22ea8..c87b8279c4d6 100644 --- a/core/java/android/net/VpnManager.java +++ b/core/java/android/net/VpnManager.java @@ -75,7 +75,7 @@ public class VpnManager { } /** - * Create an instance of the VpnManger with the given context. + * Create an instance of the VpnManager with the given context. * * <p>Internal only. Applications are expected to obtain an instance of the VpnManager via the * {@link Context.getSystemService()} method call. diff --git a/core/java/android/os/incremental/IIncrementalService.aidl b/core/java/android/os/incremental/IIncrementalService.aidl index 2dbaea860e2a..25cb0400a38d 100644 --- a/core/java/android/os/incremental/IIncrementalService.aidl +++ b/core/java/android/os/incremental/IIncrementalService.aidl @@ -109,4 +109,9 @@ interface IIncrementalService { * Setting up native library directories and extract native libs onto a storage. */ boolean configureNativeBinaries(int storageId, in @utf8InCpp String apkFullPath, in @utf8InCpp String libDirRelativePath, in @utf8InCpp String abi); + + /** + * Waits until all native library extraction is done for the storage + */ + boolean waitForNativeBinariesExtraction(int storageId); } diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java index 7092751c0d7e..70ebbaa326b8 100644 --- a/core/java/android/os/incremental/IncrementalStorage.java +++ b/core/java/android/os/incremental/IncrementalStorage.java @@ -480,4 +480,18 @@ public final class IncrementalStorage { return false; } } + + /** + * Waits for all native binary extraction operations to complete on the storage. + * + * @return Success of not. + */ + public boolean waitForNativeBinariesExtraction() { + try { + return mService.waitForNativeBinariesExtraction(mId); + } catch (RemoteException e) { + e.rethrowFromSystemServer(); + return false; + } + } } diff --git a/core/java/android/service/dataloader/DataLoaderService.java b/core/java/android/service/dataloader/DataLoaderService.java index c047dc0d07c7..60373ace2d8a 100644 --- a/core/java/android/service/dataloader/DataLoaderService.java +++ b/core/java/android/service/dataloader/DataLoaderService.java @@ -34,6 +34,8 @@ import android.os.ParcelFileDescriptor; import android.util.ExceptionUtils; import android.util.Slog; +import libcore.io.IoUtils; + import java.io.IOException; import java.util.Collection; @@ -115,22 +117,10 @@ public abstract class DataLoaderService extends Service { destroy(id); throw new RuntimeException(ex); } finally { - // Closing FDs. if (control.incremental != null) { - if (control.incremental.cmd != null) { - try { - control.incremental.cmd.close(); - } catch (IOException e) { - Slog.e(TAG, "Failed to close IncFs CMD file descriptor " + e); - } - } - if (control.incremental.log != null) { - try { - control.incremental.log.close(); - } catch (IOException e) { - Slog.e(TAG, "Failed to close IncFs LOG file descriptor " + e); - } - } + IoUtils.closeQuietly(control.incremental.cmd); + IoUtils.closeQuietly(control.incremental.pendingReads); + IoUtils.closeQuietly(control.incremental.log); } } } diff --git a/core/java/android/view/IPinnedStackListener.aidl b/core/java/android/view/IPinnedStackListener.aidl index 071c2593f522..b6ce9f52e0c3 100644 --- a/core/java/android/view/IPinnedStackListener.aidl +++ b/core/java/android/view/IPinnedStackListener.aidl @@ -37,13 +37,9 @@ oneway interface IPinnedStackListener { /** * Called when the window manager has detected a change that would cause the movement bounds - * to be changed (ie. after configuration change, aspect ratio change, etc). It then provides - * the components that allow the listener to calculate the movement bounds itself. - * The {@param animatingBounds} are provided to indicate the current target bounds of the - * pinned stack (the final bounds if animating, the current bounds if not), - * which may be helpful in calculating dependent animation bounds. + * to be changed (ie. after configuration change, aspect ratio change, etc). */ - void onMovementBoundsChanged(in Rect animatingBounds, boolean fromImeAdjustment); + void onMovementBoundsChanged(boolean fromImeAdjustment); /** * Called when window manager decides to adjust the pinned stack bounds because of the IME, or diff --git a/core/java/android/view/IWindowSession.aidl b/core/java/android/view/IWindowSession.aidl index 81bfcb07ab6d..a0527b7434fc 100644 --- a/core/java/android/view/IWindowSession.aidl +++ b/core/java/android/view/IWindowSession.aidl @@ -48,6 +48,11 @@ interface IWindowSession { out Rect outContentInsets, out Rect outStableInsets, out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, out InsetsState insetsState, out InsetsSourceControl[] activeControls); + int addToDisplayAsUser(IWindow window, int seq, in WindowManager.LayoutParams attrs, + in int viewVisibility, in int layerStackId, in int userId, + out Rect outFrame, out Rect outContentInsets, out Rect outStableInsets, + out DisplayCutout.ParcelableWrapper displayCutout, out InputChannel outInputChannel, + out InsetsState insetsState, out InsetsSourceControl[] activeControls); int addToDisplayWithoutInputChannel(IWindow window, int seq, in WindowManager.LayoutParams attrs, in int viewVisibility, in int layerStackId, out Rect outContentInsets, out Rect outStableInsets, out InsetsState insetsState); diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java index dab11088b130..ed1edc3bd526 100644 --- a/core/java/android/view/ViewRootImpl.java +++ b/core/java/android/view/ViewRootImpl.java @@ -111,6 +111,7 @@ import android.os.RemoteException; import android.os.SystemClock; import android.os.SystemProperties; import android.os.Trace; +import android.os.UserHandle; import android.sysprop.DisplayProperties; import android.util.AndroidRuntimeException; import android.util.DisplayMetrics; @@ -893,6 +894,14 @@ public final class ViewRootImpl implements ViewParent, * We have one child */ public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView) { + setView(view, attrs, panelParentView, UserHandle.myUserId()); + } + + /** + * We have one child + */ + public void setView(View view, WindowManager.LayoutParams attrs, View panelParentView, + int userId) { synchronized (this) { if (mView == null) { mView = view; @@ -1001,8 +1010,8 @@ public final class ViewRootImpl implements ViewParent, mAttachInfo.mRecomputeGlobalAttributes = true; collectViewAttributes(); adjustLayoutParamsForCompatibility(mWindowAttributes); - res = mWindowSession.addToDisplay(mWindow, mSeq, mWindowAttributes, - getHostVisibility(), mDisplay.getDisplayId(), mTmpFrame, + res = mWindowSession.addToDisplayAsUser(mWindow, mSeq, mWindowAttributes, + getHostVisibility(), mDisplay.getDisplayId(), userId, mTmpFrame, mAttachInfo.mContentInsets, mAttachInfo.mStableInsets, mAttachInfo.mDisplayCutout, inputChannel, mTempInsets, mTempControls); @@ -1075,6 +1084,9 @@ public final class ViewRootImpl implements ViewParent, throw new WindowManager.InvalidDisplayException("Unable to add window " + mWindow + " -- the specified window type " + mWindowAttributes.type + " is not valid"); + case WindowManagerGlobal.ADD_INVALID_USER: + throw new WindowManager.BadTokenException("Unable to add Window " + + mWindow + " -- requested userId is not valid"); } throw new RuntimeException( "Unable to add window -- unknown error code " + res); diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java index ab968d798745..fba6a55ef6db 100644 --- a/core/java/android/view/WindowManagerGlobal.java +++ b/core/java/android/view/WindowManagerGlobal.java @@ -144,6 +144,7 @@ public final class WindowManagerGlobal { public static final int ADD_PERMISSION_DENIED = -8; public static final int ADD_INVALID_DISPLAY = -9; public static final int ADD_INVALID_TYPE = -10; + public static final int ADD_INVALID_USER = -11; @UnsupportedAppUsage private static WindowManagerGlobal sDefaultWindowManager; @@ -325,7 +326,7 @@ public final class WindowManagerGlobal { } public void addView(View view, ViewGroup.LayoutParams params, - Display display, Window parentWindow) { + Display display, Window parentWindow, int userId) { if (view == null) { throw new IllegalArgumentException("view must not be null"); } @@ -402,7 +403,7 @@ public final class WindowManagerGlobal { // do this last because it fires off messages to start doing things try { - root.setView(view, wparams, panelParentView); + root.setView(view, wparams, panelParentView, userId); } catch (RuntimeException e) { // BadTokenException or InvalidDisplayException, clean up. if (index >= 0) { diff --git a/core/java/android/view/WindowManagerImpl.java b/core/java/android/view/WindowManagerImpl.java index 316a5f2c88d2..2975d5ee8e1c 100644 --- a/core/java/android/view/WindowManagerImpl.java +++ b/core/java/android/view/WindowManagerImpl.java @@ -104,7 +104,8 @@ public final class WindowManagerImpl implements WindowManager { @Override public void addView(@NonNull View view, @NonNull ViewGroup.LayoutParams params) { applyDefaultToken(params); - mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow); + mGlobal.addView(view, params, mContext.getDisplayNoVerify(), mParentWindow, + mContext.getUserId()); } @Override diff --git a/core/java/android/view/WindowlessWindowManager.java b/core/java/android/view/WindowlessWindowManager.java index 39ed4018c65c..ec5130143086 100644 --- a/core/java/android/view/WindowlessWindowManager.java +++ b/core/java/android/view/WindowlessWindowManager.java @@ -130,6 +130,20 @@ public class WindowlessWindowManager implements IWindowSession { return WindowManagerGlobal.ADD_OKAY | WindowManagerGlobal.ADD_FLAG_APP_VISIBLE; } + /** + * IWindowSession implementation. Currently this class doesn't need to support for multi-user. + */ + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return addToDisplay(window, seq, attrs, viewVisibility, displayId, + outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls); + } + @Override public int addToDisplayWithoutInputChannel(android.view.IWindow window, int seq, android.view.WindowManager.LayoutParams attrs, int viewVisibility, int layerStackId, diff --git a/core/java/android/view/inputmethod/InputMethodManager.java b/core/java/android/view/inputmethod/InputMethodManager.java index 482d5b25e9da..71dd6653f6a6 100644 --- a/core/java/android/view/inputmethod/InputMethodManager.java +++ b/core/java/android/view/inputmethod/InputMethodManager.java @@ -1968,6 +1968,38 @@ public final class InputMethodManager { return true; } + /** + * An empty method only to avoid crashes of apps that call this method via reflection and do not + * handle {@link NoSuchMethodException} in a graceful manner. + * + * @deprecated This is an empty method. No framework method must call this method. + * @hide + */ + @Deprecated + @UnsupportedAppUsage(trackingBug = 37122102, maxTargetSdk = Build.VERSION_CODES.Q, + publicAlternatives = "{@code androidx.activity.ComponentActivity}") + public void windowDismissed(IBinder appWindowToken) { + // Intentionally empty. + // + // It seems that some applications call this method via reflection to null clear the + // following fields that used to exist in InputMethodManager: + // * InputMethodManager#mCurRootView + // * InputMethodManager#mServedView + // * InputMethodManager#mNextServedView + // so that these objects can be garbage-collected when an Activity gets dismissed. + // + // It is indeed true that older versions of InputMethodManager had issues that prevented + // these fields from being null-cleared when it should have been, but the understanding of + // the engineering team is that all known issues have already been fixed as of Android 10. + // + // For older devices, developers can work around the object leaks by using + // androidx.activity.ComponentActivity. + // See https://issuetracker.google.com/u/1/issues/37122102 for details. + // + // If you believe InputMethodManager is leaking objects in API 24 or any later version, + // please file a bug at https://issuetracker.google.com/issues/new?component=192705. + } + private int getStartInputFlags(View focusedView, int startInputFlags) { startInputFlags |= StartInputFlags.VIEW_HAS_FOCUS; if (focusedView.onCheckIsTextEditor()) { diff --git a/core/java/com/android/internal/content/NativeLibraryHelper.java b/core/java/com/android/internal/content/NativeLibraryHelper.java index 04bf91567986..02cf25a7c3d2 100644 --- a/core/java/com/android/internal/content/NativeLibraryHelper.java +++ b/core/java/com/android/internal/content/NativeLibraryHelper.java @@ -26,7 +26,6 @@ import static android.system.OsConstants.S_IXGRP; import static android.system.OsConstants.S_IXOTH; import android.content.Context; -import android.content.pm.ApplicationInfo; import android.content.pm.PackageManager; import android.content.pm.PackageParser; import android.content.pm.PackageParser.PackageLite; @@ -40,6 +39,7 @@ import android.os.incremental.IncrementalManager; import android.os.incremental.IncrementalStorage; import android.system.ErrnoException; import android.system.Os; +import android.util.ArraySet; import android.util.Slog; import dalvik.system.CloseGuard; @@ -545,4 +545,18 @@ public class NativeLibraryHelper { } return false; } + + /** + * Wait for all native library extraction to complete for the passed storages. + * + * @param incrementalStorages A list of the storages to wait for. + */ + public static void waitForNativeBinariesExtraction( + ArraySet<IncrementalStorage> incrementalStorages) { + for (int i = 0; i < incrementalStorages.size(); ++i) { + IncrementalStorage storage = incrementalStorages.valueAtUnchecked(i); + storage.waitForNativeBinariesExtraction(); + } + } + } diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml index 1c978bff0fd3..32a79f3ab8ae 100644 --- a/core/res/AndroidManifest.xml +++ b/core/res/AndroidManifest.xml @@ -1099,9 +1099,9 @@ android:description="@string/permgroupdesc_phone" android:priority="500" /> - <!-- Allows read only access to phone state, including the phone number of the device, - current cellular network information, the status of any ongoing calls, and a list of any - {@link android.telecom.PhoneAccount}s registered on the device. + <!-- Allows read only access to phone state, including the current cellular network information, + the status of any ongoing calls, and a list of any {@link android.telecom.PhoneAccount}s + registered on the device. <p class="note"><strong>Note:</strong> If <em>both</em> your <a href="{@docRoot}guide/topics/manifest/uses-sdk-element.html#min">{@code minSdkVersion}</a> and <a diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml index 37fd9652e894..cafa7e8e3af9 100644 --- a/core/res/res/values-am/strings.xml +++ b/core/res/res/values-am/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB አድስ ተያይዟል"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"የዩኤስቢ ማረሚያን ለማጥፋት መታ ያድርጉ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ማረሚያ ላለማንቃት ምረጥ።"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ገመድ-አልባ ማረም ተገናኝቷል"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ገመድ-አልባ ማረምን ለማጥፋት ይምረጡ"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ገመድ-አልባ ማረምን ለማሰናከል ይምረጡ።"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ገመድ-አልባ debugging ተገናኝቷል"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ገመድ-አልባ debuggingን ለማጥፋት ይምረጡ"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ገመድ-አልባ debuggingን ለማሰናከል ይምረጡ።"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"የሙከራ ጥቅል ሁነታ ነቅቷል"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"የመሞከሪያ ጥቅል ሁነታን ለማሰናከል የፋብሪካ ዳግም ቅንብርን ይሞክሩ።"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ተከታታይ ኮንሶል ነቅቷል"</string> diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml index 4715823b6482..1ed36a80ca52 100644 --- a/core/res/res/values-ar/strings.xml +++ b/core/res/res/values-ar/strings.xml @@ -554,7 +554,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"لم يتم التعرف عليها."</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"تم إلغاء المصادقة."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"لم يتم ضبط رقم تعريف شخصي أو نقش أو كلمة مرور."</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف بصمة الإصبع بشكل جزئي؛ يرجى إعادة المحاولة."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"تم اكتشاف جزء من بصمة الإصبع فقط؛ يرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"تعذرت معالجة بصمة الإصبع. يُرجى إعادة المحاولة."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"زر استشعار بصمات الأصابع متّسخ. يُرجى تنظيفه وإعادة المحاولة."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"لقد حرّكت إصبعك بسرعة، يُرجى إعادة المحاولة."</string> @@ -1389,9 +1389,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"تم توصيل أداة تصحيح أخطاء الجهاز عبر USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"انقر لإيقاف تصحيح أخطاء الجهاز عبر USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"اختيار إيقاف تصحيح أخطاء USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"انقر لإيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\"."</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"اختيار إيقاف ميزة \"تصحيح الأخطاء عبر شبكة Wi-Fi\""</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"تم تفعيل ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"انقر لإيقاف ميزة \"تصحيح الأخطاء اللاسلكي\"."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"اختيار إيقاف ميزة \"تصحيح الأخطاء اللاسلكي\""</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"تم تفعيل وضع \"مفعّل الاختبار\""</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"يمكنك إجراء إعادة ضبط على الإعدادات الأصلية لإيقاف وضع \"مفعِّل اختبار\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"وحدة التحكّم التسلسلية مفعّلة"</string> @@ -2180,8 +2180,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"محادثة"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"محادثة جماعية"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"عرض المحتوى الشخصي"</string> diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml index c0e070bf27bf..dae98671aa84 100644 --- a/core/res/res/values-as/strings.xml +++ b/core/res/res/values-as/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"ইউএছবি ডিবাগিং সংযোগ কৰা হ’ল"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"ইউএছবি ডিবাগিং বন্ধ কৰিবলৈ টিপক"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"ইউএছবি ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ৱায়াৰলেছ ডিবাগিং সংযোগ কৰা হৈছে"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ৱায়াৰলেছ ডিবাগিং অফ কৰিবলৈ টিপক"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ৱায়াৰলেছ ডিবাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ৱায়াৰলেচ ডি\'বাগিং সংযোগ কৰা হৈছে"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ৱায়াৰলেচ ডি\'বাগিং অফ কৰিবলৈ টিপক"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ৱায়াৰলেচ ডি\'বাগিং অক্ষম কৰিবলৈ বাছনি কৰক।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"টেষ্ট হাৰনেছ ম’ড সক্ষম কৰা আছে"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"টেষ্ট হাৰনেছ ম’ড অক্ষম কৰিবলৈ ফেক্টৰী ৰিছেট কৰক।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"ক্ৰমিক কনছ’ল সক্ষম কৰা আছে"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"বাৰ্তালাপ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গোটত কৰা বাৰ্তালাপ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ব্যক্তিগত ভিউ"</string> diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml index ec6960660b54..462ca3ad7130 100644 --- a/core/res/res/values-az/strings.xml +++ b/core/res/res/values-az/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB sazlama qoşuludur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB sazlamanı deaktiv etmək üçün klikləyin"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USb debaqı deaktivasiya etməyi seçin."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz sazlama qoşulub"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz sazlamanı deaktiv etmək üçün toxunun"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz sazlamanı deaktiv etmək üçün seçin."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"WiFi sazlaması qoşulub"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"WiFi sazlamasını deaktiv etmək üçün toxunun"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"WiFi sazlamasını deaktiv etmək üçün seçin."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test Rejimi aktivdir"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Test Rejimini deaktiv etmək üçün fabrika ayarlarına sıfırlayın."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Ardıcıl konsol aktiv edildi"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Söhbət"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Qrup Söhbəti"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Şəxsi məzmuna baxış"</string> diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml index 0636ea960572..84545894e794 100644 --- a/core/res/res/values-b+sr+Latn/strings.xml +++ b/core/res/res/values-b+sr+Latn/strings.xml @@ -701,7 +701,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Zahteva da sačuvani podaci aplikacije budu šifrovani."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Onemogućavanje kamera"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Sprečite korišćenje svih kamera uređaja."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemogućava funkcije zaključavanja ekrana"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemogućavanje funkcija zaklj. ekrana"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Sprečava korišćenje nekih funkcija zaključavanja ekrana."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Kuća"</item> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzacija"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupna konverzacija"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Lični prikaz"</string> diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml index 133df6c00109..9d3ca537ff04 100644 --- a/core/res/res/values-be/strings.xml +++ b/core/res/res/values-be/strings.xml @@ -1349,9 +1349,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Адладка па USB падключана"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Націсніце, каб выключыць адладку па USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Выберыце, каб адключыць адладку USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бесправадная адладка падключана"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Націсніце, каб выключыць бесправадную адладку"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Выберыце, каб адключыць бесправадную адладку."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Адладка па Wi-Fi уключана"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Націсніце, каб выключыць адладку па Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Выберыце, каб выключыць адладку па Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Тэставы рэжым уключаны"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Каб выключыць тэставы рэжым, скіньце налады да заводскіх значэнняў."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Паслядоўная кансоль уключана"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Размова"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групавая размова"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Прагляд асабістага змесціва"</string> diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml index 468b8256c689..ff0838dede37 100644 --- a/core/res/res/values-bg/strings.xml +++ b/core/res/res/values-bg/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групов разговор"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"Над <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Личен изглед"</string> diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml index a8cc98620260..4090e21544b2 100644 --- a/core/res/res/values-bn/strings.xml +++ b/core/res/res/values-bn/strings.xml @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"আঙ্গুলের ছাপ আংশিক শনাক্ত করা হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"আঙ্গুলের ছাপ প্রক্রিয়া করা যায়নি৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"আঙ্গুলের ছাপ নেওয়ার সেন্সরটি অপরিস্কার৷ অনুগ্রহ করে পরিষ্কার করে আবার চেষ্টা করুন৷"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"আঙ্গুল অতি দ্রুত সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"আঙ্গুল অতি দ্রুত সরানো হয়েছে৷ আবার চেষ্টা করুন৷"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"আঙ্গুল খুব ধীরে সরানো হয়েছে৷ অনুগ্রহ করে আবার চেষ্টা করুন৷"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"কথোপকথন"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"গ্রুপ কথোপকথন"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ব্যক্তিগত ভিউ"</string> diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml index a6aa753cdee0..bd05452c771b 100644 --- a/core/res/res/values-bs/strings.xml +++ b/core/res/res/values-bs/strings.xml @@ -513,7 +513,7 @@ <string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Omogućava aplikaciji uspostavljanje i prekidanje veze tableta sa WiMAX mrežama."</string> <string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Omogućava aplikaciji da se poveže s vašim Android TV uređajem i prekine povezanost Android TV uređaja s WiMAX mrežama."</string> <string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Omogućava aplikaciji uspostavljanje i prekidanje veze telefona sa WiMAX mrežama."</string> - <string name="permlab_bluetooth" msgid="586333280736937209">"uparivanje sa Bluetooth uređajima"</string> + <string name="permlab_bluetooth" msgid="586333280736937209">"uparivanje s Bluetooth uređajima"</string> <string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na tabletu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string> <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Omogućava aplikaciji da prikaže konfiguraciju Bluetootha na Android TV uređaju te uspostavi i prihvati vezu s uparenim uređajima."</string> <string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Omogućava aplikaciji prikaz konfiguracije za Bluetooth na telefonu, kao i uspostavljanje i prihvatanje veza sa uparenim uređajima."</string> @@ -545,7 +545,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Nije prepoznato"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Autentifikacija je otkazana"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Nije postavljen PIN, uzorak niti lozinka"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomičan otisak prsta. Pokušajte ponovo."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Otkriven je djelomični otisak prsta. Pokušajte ponovo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Obrada otiska prsta nije uspjela. Pokušajte ponovo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Senzor za otisak prsta je prljav. Očistite ga i pokušajte ponovo."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Prst je uklonjen prebrzo. Pokušajte ponovo."</string> @@ -702,7 +702,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Isključuje kamere"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Sprečava korištenje svih kamera uređaja."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Onemog. neke funk. zak. ekrana"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Spriječava korištenje nekih funkcija za zaključavanje ekrana."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Sprečava korištenje nekih funkcija za zaključavanje ekrana."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Kuća"</item> <item msgid="7740243458912727194">"Mobilni"</item> @@ -1205,7 +1205,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Uvijek prikaži"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"Aplikacija <xliff:g id="APP_NAME">%1$s</xliff:g> je napravljena za verziju operativnog sistema Android koja nije kompatibilna i može se ponašati neočekivano. Ažurirana verzija aplikacije može biti dostupna."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Uvijek prikaži"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Provjeri ima li ažuriranja"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Provjeri je li dostupno ažuriranje"</string> <string name="smv_application" msgid="3775183542777792638">"Aplikacija <xliff:g id="APPLICATION">%1$s</xliff:g> (proces <xliff:g id="PROCESS">%2$s</xliff:g>) prekršila je vlastita StrictMode pravila."</string> <string name="smv_process" msgid="1398801497130695446">"Proces <xliff:g id="PROCESS">%1$s</xliff:g> prekršio je vlastita StrictMode pravila."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Ažuriranje telefona…"</string> @@ -1531,7 +1531,7 @@ <string name="storage_usb_drive_label" msgid="6631740655876540521">"<xliff:g id="MANUFACTURER">%s</xliff:g> USB disk"</string> <string name="storage_usb" msgid="2391213347883616886">"USB pohrana"</string> <string name="extract_edit_menu_button" msgid="63954536535863040">"Uredi"</string> - <string name="data_usage_warning_title" msgid="9034893717078325845">"Upozorenje o potrošnji podataka"</string> + <string name="data_usage_warning_title" msgid="9034893717078325845">"Upozorenje o prijenosu podataka"</string> <string name="data_usage_warning_body" msgid="1669325367188029454">"Potrošili ste <xliff:g id="APP">%s</xliff:g> podataka"</string> <string name="data_usage_mobile_limit_title" msgid="3911447354393775241">"Dostignuto ograničenje za prijenos podataka"</string> <string name="data_usage_wifi_limit_title" msgid="2069698056520812232">"Dostignut limit WiFi podataka"</string> @@ -2080,8 +2080,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Prikaz ličnog sadržaja"</string> diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml index b3cb436fff63..a0e404a9e28a 100644 --- a/core/res/res/values-ca/strings.xml +++ b/core/res/res/values-ca/strings.xml @@ -1349,8 +1349,8 @@ <string name="ext_media_unmountable_notification_message" product="tv" msgid="3003611129979934633">"La unitat següent està malmesa: <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per solucionar-ho."</string> <string name="ext_media_unmountable_notification_message" product="automotive" msgid="5622514265490819212"></string> <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"<xliff:g id="NAME">%s</xliff:g> no és compatible"</string> - <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"El dispositiu no admet la unitat <xliff:g id="NAME">%s</xliff:g>. Toca per configurar-la amb un format compatible."</string> - <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"Aquest dispositiu no admet la unitat següent: <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per configurar-la en un format compatible."</string> + <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"El dispositiu no admet <xliff:g id="NAME">%s</xliff:g>. Toca per configurar-la en un format compatible."</string> + <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"Aquest dispositiu no admet <xliff:g id="NAME">%s</xliff:g>. Selecciona-la per configurar-la en un format compatible."</string> <string name="ext_media_unsupported_notification_message" product="automotive" msgid="7657357085538772913">"El dispositiu no admet <xliff:g id="NAME">%s</xliff:g>."</string> <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"S\'ha extret <xliff:g id="NAME">%s</xliff:g> de manera inesperada"</string> <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"Expulsa el suport extern abans d\'extreure\'l per evitar perdre\'n el contingut"</string> @@ -1592,7 +1592,7 @@ <string name="kg_invalid_sim_pin_hint" msgid="4821601451222564077">"Escriu un PIN que tingui de 4 a 8 números."</string> <string name="kg_invalid_sim_puk_hint" msgid="2539364558870734339">"El codi PUK ha de tenir 8 números."</string> <string name="kg_invalid_puk" msgid="4809502818518963344">"Torna a introduir el codi PUK correcte. Els intents repetits faran que es desactivi la SIM permanentment."</string> - <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Els codis PIN no coincideixen"</string> + <string name="kg_invalid_confirm_pin_hint" product="default" msgid="4705368340409816254">"Els PIN no coincideixen"</string> <string name="kg_login_too_many_attempts" msgid="699292728290654121">"Massa intents incorrectes"</string> <string name="kg_login_instructions" msgid="3619844310339066827">"Per desbloquejar el telèfon, inicia la sessió amb el compte de Google."</string> <string name="kg_login_username_hint" msgid="1765453775467133251">"Nom d\'usuari (correu electrònic)"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grup"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualització personal"</string> diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml index 36adc52ec8f7..f56b8b5d5bd7 100644 --- a/core/res/res/values-cs/strings.xml +++ b/core/res/res/values-cs/strings.xml @@ -1835,8 +1835,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“\n\n"<annotation id="url">"Další informace"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Hej Google“"</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“\n\n"<annotation id="url">"Další informace"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Spořič baterie za účelem úspory energie:\n·zapne tmavý motiv,\n·vypne nebo omezí aktivitu na pozadí, některé vizuální efekty a další funkce jako „Ok Google“"</string> <string name="data_saver_description" msgid="4995164271550590517">"Spořič dat z důvodu snížení využití dat některým aplikacím brání v odesílání nebo příjmu dat na pozadí. Aplikace, kterou právě používáte, data přenášet může, ale může tak činit méně často. V důsledku toho se například obrázky nemusejí zobrazit, dokud na ně neklepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnout Spořič dat?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnout"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzace"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzace"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobní zobrazení"</string> diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml index 6d8a2b4d21ff..6e9098b4c3e4 100644 --- a/core/res/res/values-da/strings.xml +++ b/core/res/res/values-da/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visningen Personligt"</string> diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml index 3de322e16ff1..bfb7b4d50512 100644 --- a/core/res/res/values-de/strings.xml +++ b/core/res/res/values-de/strings.xml @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Nicht erkannt"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Authentifizierung abgebrochen"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Keine PIN, kein Muster und kein Passwort festgelegt"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck teilweise erkannt. Bitte versuche es noch einmal."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Fingerabdruck nur teilweise erkannt. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Fingerabdruck konnte nicht verarbeitet werden. Bitte versuche es noch einmal."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Fingerabdrucksensor ist verschmutzt. Reinige ihn und versuche es noch einmal."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Du hast deinen Finger zu schnell bewegt. Bitte versuche es noch einmal."</string> @@ -679,7 +679,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Es wird überwacht, wie oft beim Versuch, den Bildschirm zu entsperren, ein falsches Passwort eingegeben wird. Wenn es zu viele Fehlversuche gibt, wird das Android TV-Gerät gesperrt oder alle Daten dieses Nutzers werden gelöscht."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Anzahl der falsch eingegebenen Passwörter beim Entsperren des Displays überwachen und Smartphone sperren oder alle Daten dieses Nutzers löschen, wenn zu häufig ein falsches Passwort eingegeben wird"</string> <string name="policylab_resetPassword" msgid="214556238645096520">"Displaysperre ändern"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"Displaysperre ändern"</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"Ändern der Displaysperre"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Bildschirm sperren"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Festlegen, wie und wann der Bildschirm gesperrt wird"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Alle Daten löschen"</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-Debugging aktiviert"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Zum Deaktivieren von USB-Debugging tippen"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB-Debugging deaktivieren: auswählen"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Kabelloses Debugging verbunden"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tippen, um kabelloses Debugging zu deaktivieren"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Auswählen, um kabelloses Debugging zu deaktivieren."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"\"Debugging über WLAN\" verbunden"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Tippen, um \"Debugging über WLAN\" zu deaktivieren"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Auswählen, um \"Debugging über WLAN\" zu deaktivieren."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Test-Harnischmodus aktiviert"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Setz das Gerät auf die Werkseinstellungen zurück, um den Test-Harnischmodus zu deaktivieren."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Serielle Konsole aktiviert"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Unterhaltung"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppenunterhaltung"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Private Ansicht"</string> diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml index 57b02f44954a..5fdbe9ed2a61 100644 --- a/core/res/res/values-el/strings.xml +++ b/core/res/res/values-el/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Συνδέθηκε ο εντοπισμός σφαλμάτων USB"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Απενεργοποιήστε τον εντοπισμό/διόρθ. σφαλμάτων USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Επιλογή για απενεργοποίηση του εντοπισμού σφαλμάτων USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο εντοπισμός σφαλμάτων μέσω ασύρματης σύνδεσης"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον εντοπισμό σφαλμάτων μέσω ασύρματης σύνδεσης."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Συνδέθηκε ο ασύρματος εντοπισμός σφαλμάτων"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Πατήστε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Επιλέξτε, για να απενεργοποιήσετε τον ασύρματο εντοπισμό σφαλμάτων."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Η λειτουργία περιβάλλοντος δοκιμών ενεργοποιήθηκε"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Εκτελέστε επαναφορά εργοστασιακών ρυθμίσεων για να απενεργοποιήσετε τη λειτουργία περιβάλλοντος δοκιμών."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Η σειριακή κονσόλα ενεργοποιήθηκε"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Συνομιλία"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ομαδική συνομιλία"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Προσωπική προβολή"</string> diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml index 366d19db16b8..cf58937aa9ca 100644 --- a/core/res/res/values-es-rUS/strings.xml +++ b/core/res/res/values-es-rUS/strings.xml @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"No se reconoció"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Se canceló la autenticación"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"No se estableció ningún PIN, patrón ni contraseña"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"La huella digital se detectó parcialmente. Vuelve a intentarlo."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Se detectó parcialmente la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"No se pudo procesar la huella digital. Vuelve a intentarlo."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"El sensor de huellas digitales está sucio. Limpia el sensor y vuelve a intentarlo."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Moviste el dedo muy rápido. Vuelve a intentarlo."</string> diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml index 197a47cd20ac..b57b6929cdc9 100644 --- a/core/res/res/values-es/strings.xml +++ b/core/res/res/values-es/strings.xml @@ -310,7 +310,7 @@ <string name="permgrouplab_camera" msgid="9090413408963547706">"Cámara"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"hacer fotos y grabar vídeos"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Registros de llamadas"</string> - <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leer y editar el registro de llamadas del teléfono"</string> + <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leer y escribir en el registro de llamadas del teléfono"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Teléfono"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"hacer y administrar llamadas telefónicas"</string> <string name="permgrouplab_sensors" msgid="9134046949784064495">"Sensores corporales"</string> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Exige que se cifren los datos de la aplicación almacenados."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Inhabilitar cámaras"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Evita el uso de las cámaras del dispositivo"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Inhabilitar algunas funciones del bloqueo de pantalla"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Desactivar algunas funciones del bloqueo de pantalla"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Evitar el uso de algunas funciones del bloqueo de pantalla"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Casa"</item> @@ -1262,7 +1262,7 @@ <string name="decline" msgid="6490507610282145874">"Rechazar"</string> <string name="select_character" msgid="3352797107930786979">"Insertar carácter"</string> <string name="sms_control_title" msgid="4748684259903148341">"Enviando mensajes SMS..."</string> - <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando un gran número de mensajes SMS. ¿Quieres permitir que está aplicación siga enviando mensajes?"</string> + <string name="sms_control_message" msgid="6574313876316388239">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> está enviando un gran número de mensajes SMS. ¿Permitir que está aplicación siga enviando mensajes?"</string> <string name="sms_control_yes" msgid="4858845109269524622">"Permitir"</string> <string name="sms_control_no" msgid="4845717880040355570">"Denegar"</string> <string name="sms_short_code_confirm_message" msgid="1385416688897538724">"<b><xliff:g id="APP_NAME">%1$s</xliff:g></b> quiere enviar un mensaje a <b><xliff:g id="DEST_ADDRESS">%2$s</xliff:g></b>."</string> @@ -1307,7 +1307,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Se ha detectado un accesorio de audio analógico"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"El dispositivo adjunto no es compatible con este teléfono. Toca para obtener más información."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"Depuración USB habilitada"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"Tocar para desactivar depuración USB"</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Toca aquí para desactivar la depuración USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Seleccionar para inhabilitar la depuración USB"</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuración inalámbrica conectada"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toca para desactivar la depuración inalámbrica"</string> @@ -1327,7 +1327,7 @@ <string name="share_remote_bugreport_action" msgid="7630880678785123682">"COMPARTIR"</string> <string name="decline_remote_bugreport_action" msgid="4040894777519784346">"RECHAZAR"</string> <string name="select_input_method" msgid="3971267998568587025">"Selecciona un método de entrada"</string> - <string name="show_ime" msgid="6406112007347443383">"Mantener en la pantalla mientras el teclado físico está activo"</string> + <string name="show_ime" msgid="6406112007347443383">"Lo mantiene en pantalla mientras el teclado físico está activo"</string> <string name="hardware" msgid="1800597768237606953">"Mostrar teclado virtual"</string> <string name="select_keyboard_layout_notification_title" msgid="4427643867639774118">"Configura el teclado físico"</string> <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"Toca para seleccionar el idioma y el diseño"</string> @@ -1628,7 +1628,7 @@ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes > Accesibilidad."</string> <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string> <string name="accessibility_shortcut_off" msgid="3651336255403648739">"No activar"</string> - <string name="accessibility_enable_service_title" msgid="3931558336268541484">"¿Quieres permitir que <xliff:g id="SERVICE">%1$s</xliff:g> pueda controlar totalmente tu dispositivo?"</string> + <string name="accessibility_enable_service_title" msgid="3931558336268541484">"¿Permitir que <xliff:g id="SERVICE">%1$s</xliff:g> pueda controlar totalmente tu dispositivo?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"Si activas <xliff:g id="SERVICE">%1$s</xliff:g>, el dispositivo no utilizará el bloqueo de pantalla para mejorar el cifrado de datos."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"El control total es adecuado para las aplicaciones de accesibilidad, pero no para la mayoría de las aplicaciones."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver y controlar la pantalla"</string> @@ -1789,9 +1789,9 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Para que la batería dure más, Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Para que la batería dure más, Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string> - <string name="data_saver_description" msgid="4995164271550590517">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que, por ejemplo, algunas imágenes no se mostrarán hasta que las toques."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Para que la batería dure más, el modo Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\"\n\n"<annotation id="url">"Más información"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Para que la batería dure más, el modo Ahorro de batería:\n· Activa el tema oscuro\n· Desactiva o restringe actividad en segundo plano, algunos efectos visuales y otras funciones como \"Ok Google\""</string> + <string name="data_saver_description" msgid="4995164271550590517">"El ahorro de datos evita que algunas aplicaciones envíen o reciban datos en segundo plano, lo que permite reducir el uso de datos. Una aplicación activa podrá acceder a los datos, aunque con menos frecuencia. Esto significa que es posible que, por ejemplo, algunas imágenes no se muestren hasta que las toques."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"¿Activar ahorro de datos?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activar"</string> <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversación"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversación de grupo"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Ver contenido personal"</string> diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml index 2e9ea38e7aa2..070fd79f65a3 100644 --- a/core/res/res/values-et/strings.xml +++ b/core/res/res/values-et/strings.xml @@ -563,7 +563,7 @@ <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ühtegi sõrmejälge pole registreeritud."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Selles seadmes pole sõrmejäljeandurit."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Andur on ajutiselt keelatud."</string> - <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrm <xliff:g id="FINGERID">%d</xliff:g>"</string> + <string name="fingerprint_name_template" msgid="8941662088160289778">"Sõrmejälg <xliff:g id="FINGERID">%d</xliff:g>"</string> <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string> @@ -679,7 +679,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Jälgitakse ekraanikuva avamisel sisestatud valede paroolide arvu ja lukustatakse Android TV seade või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Jälgitakse ekraani avamisel sisestatud valede paroolide arvu ja lukustatakse telefon või kustutatakse kõik selle kasutaja andmed, kui vale parool sisestatakse liiga palju kordi."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"Ekraaniluku muutmine"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"Muudetakse ekraanilukku."</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"Muutke ekraanilukku."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Ekraani lukustamine"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Määrake, kuidas ja millal ekraan lukustub."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Kõikide andmete kustutamine"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja akusäästja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid.\n\n"<annotation id="url">"Lisateave"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Aku tööea pikendamiseks teeb akusäästja järgmist.\n·Lülitab sisse tumeda teema.\n·Lülitab välja taustategevused, mõned visuaalsed efektid ja muud funktsioonid (nt „Hei Google”) või piirab neid."</string> <string name="data_saver_description" msgid="4995164271550590517">"Andmekasutuse vähendamiseks keelab andmemahu säästja mõne rakenduse puhul andmete taustal saatmise ja vastuvõtmise. Rakendus, mida praegu kasutate, pääseb andmesidele juurde, kuid võib seda teha väiksema sagedusega. Seetõttu võidakse näiteks pildid kuvada alles siis, kui neid puudutate."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Lül. andmemahu säästja sisse?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Lülita sisse"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Vestlus"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupivestlus"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Isiklik vaade"</string> diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml index 9af4b68a071a..c5922e1d5972 100644 --- a/core/res/res/values-eu/strings.xml +++ b/core/res/res/values-eu/strings.xml @@ -571,7 +571,7 @@ <string name="permdesc_manageFace" msgid="6204569688492710471">"Aurpegi-txantiloiak gehitu eta ezabatzeko metodoei dei egitea baimentzen dio aplikazioari."</string> <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"erabili aurpegiaren bidez desblokeatzeko hardwarea"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Autentifikazioa egiteko aurpegiaren bidez desblokeatzeko hardwarea erabiltzeko baimena ematen dio aplikazioari"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Aurpegiaren bidez desblokeatzeko aukera"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Aurpegiaren bidez desblokeatzeko eginbidea"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Erregistratu aurpegia berriro"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Ezagutzea hobetzeko, erregistratu aurpegia berriro"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"Ezin izan dira bildu argazkiaren datu zehatzak. Saiatu berriro."</string> @@ -602,9 +602,9 @@ <string name="face_error_canceled" msgid="2164434737103802131">"Utzi da aurpegiaren bidezko eragiketa."</string> <string name="face_error_user_canceled" msgid="8553045452825849843">"Erabiltzaileak bertan behera utzi du aurpegiaren bidez desblokeatzea."</string> <string name="face_error_lockout" msgid="7864408714994529437">"Saiakera gehiegi egin dituzu. Saiatu berriro geroago."</string> - <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Saiakera gehiegi egin dira. Aurpegiaren bidez desblokeatzeko aukera desgaitu egin da."</string> + <string name="face_error_lockout_permanent" msgid="8277853602168960343">"Saiakera gehiegi egin dira. Aurpegiaren bidez desblokeatzeko eginbidea desgaitu egin da."</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"Ezin da egiaztatu aurpegia. Saiatu berriro."</string> - <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko aukera."</string> + <string name="face_error_not_enrolled" msgid="7369928733504691611">"Ez duzu konfiguratu aurpegiaren bidez desblokeatzeko eginbidea."</string> <string name="face_error_hw_not_present" msgid="1070600921591729944">"Gailu honek ez du onartzen aurpegiaren bidez desblokeatzea."</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"Sentsorea aldi baterako desgaitu da."</string> <string name="face_name_template" msgid="3877037340223318119">"<xliff:g id="FACEID">%d</xliff:g> aurpegia"</string> @@ -905,7 +905,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"Zabaldu desblokeatzeko eremua."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"Hatza lerratuta desblokeatzea."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"Ereduaren bidez desblokeatzea."</string> - <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Aurpegiaren bidez desblokeatzeko aukera."</string> + <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"Aurpegiaren bidez desblokeatzeko eginbidea."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"PIN kodearen bidez desblokeatzea."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"SIM txartela desblokeatzeko PIN kodea."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"SIM txartela desblokeatzeko PUK kodea."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Elkarrizketa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Taldeko elkarrizketa"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Ikuspegi pertsonala"</string> diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml index b62d8b02cbe3..315f7ea459b2 100644 --- a/core/res/res/values-fi/strings.xml +++ b/core/res/res/values-fi/strings.xml @@ -1307,7 +1307,7 @@ <string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Analoginen äänilaite havaittu"</string> <string name="usb_unsupported_audio_accessory_message" msgid="1300168007129796621">"Liitetty laite ei ole yhteensopiva puhelimen kanssa. Napauta, niin näet lisätietoja."</string> <string name="adb_active_notification_title" msgid="408390247354560331">"USB-vianetsintä yhdistetty"</string> - <string name="adb_active_notification_message" msgid="5617264033476778211">"Poista USB-virheenkorjaus käytöstä napauttamalla."</string> + <string name="adb_active_notification_message" msgid="5617264033476778211">"Poista USB-virheenkorjaus käytöstä napauttamalla"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Poista USB-vianetsintä käytöstä valitsemalla tämä."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Langaton virheenkorjaus yhdistetty"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Poista langaton virheenkorjaus käytöstä napauttamalla"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Keskustelu"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Ryhmäkeskustelu"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Henkilökohtainen näkymä"</string> diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml index 84c1c18151b6..6198d0ecb30c 100644 --- a/core/res/res/values-fr-rCA/strings.xml +++ b/core/res/res/values-fr-rCA/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Affichage personnel"</string> diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml index 1de01a3d738d..3708d3a9ca6e 100644 --- a/core/res/res/values-fr/strings.xml +++ b/core/res/res/values-fr/strings.xml @@ -310,7 +310,7 @@ <string name="permgrouplab_camera" msgid="9090413408963547706">"Appareil photo"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"prendre des photos et enregistrer des vidéos"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Journaux d\'appels"</string> - <string name="permgroupdesc_calllog" msgid="2026996642917801803">"Lire et écrire les journaux d\'appels du téléphone"</string> + <string name="permgroupdesc_calllog" msgid="2026996642917801803">"Consulter et modifier les journaux d\'appels du téléphone"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Téléphone"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"effectuer et gérer des appels téléphoniques"</string> <string name="permgrouplab_sensors" msgid="9134046949784064495">"Capteurs corporels"</string> @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"Modifier le verrouillage de l\'écran"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Modifier le verrouillage de l\'écran"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Verrouiller l\'écran"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"Gérer le mode et les conditions de verrouillage de l\'écran"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"Gérer la méthode et les conditions de verrouillage de l\'écran"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Effacer toutes les données"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Effacer les données de la tablette sans avertissement, en rétablissant la configuration d\'usine"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Efface les données de votre appareil Android TV sans avertissement en rétablissant la configuration d\'usine."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Désactiver les appareils photo"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Empêcher l\'utilisation de tous les appareils photos"</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Désactiver les options de verrouillage de l\'écran"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Empêcher l\'utilisation de certaines fonctionnalités du verrouillage de l\'écran"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Domicile"</item> <item msgid="7740243458912727194">"Mobile"</item> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Débogage USB activé"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Appuyez pour désactiver le débogage USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Sélectionnez cette option pour désactiver le débogage USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage via Wi-Fi activé"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage via Wi-Fi"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage via Wi-Fi."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Débogage sans fil connecté"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Appuyez pour désactiver le débogage sans fil"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Sélectionnez cette option pour désactiver le débogage sans fil."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Mode Atelier de test activé"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Rétablissez la configuration d\'usine pour désactiver le mode Atelier de test."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Console série activée"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n·active le thème sombre ;\n·désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\".\n\n"<annotation id="url">"En savoir plus"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n·active le thème sombre ;\n·désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\"."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n· active le thème sombre ;\n· désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\".\n\n"<annotation id="url">"En savoir plus"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Pour prolonger l\'autonomie de la batterie, l\'économiseur de batterie :\n· active le thème sombre ;\n· désactive ou restreint les activités en arrière-plan, certains effet visuels et d\'autres fonctionnalités, comme \"Ok Google\"."</string> <string name="data_saver_description" msgid="4995164271550590517">"Pour réduire la consommation de données, l\'économiseur de données empêche certaines applications d\'envoyer ou de recevoir des données en arrière-plan. Ainsi, les applications que vous utilisez peuvent toujours accéder aux données, mais pas en permanence. Par exemple, il se peut que les images ne s\'affichent pas tant que vous n\'appuyez pas dessus."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Activer l\'économiseur de données ?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Activer"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g> :"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversation de groupe"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g> ou +"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Vue personnelle"</string> diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml index 1f6e4d74f696..7f621ca43545 100644 --- a/core/res/res/values-gl/strings.xml +++ b/core/res/res/values-gl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa de grupo"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"><xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Vista persoal"</string> diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml index 29a984773c31..fa88ebc38c5c 100644 --- a/core/res/res/values-gu/strings.xml +++ b/core/res/res/values-gu/strings.xml @@ -307,7 +307,7 @@ <string name="permgroupdesc_microphone" msgid="1047786732792487722">"ઑડિઓ રેકોર્ડ કરવાની"</string> <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"શારીરિક પ્રવૃત્તિ"</string> <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"તમારી શારીરિક પ્રવૃત્તિને ઍક્સેસ કરવી"</string> - <string name="permgrouplab_camera" msgid="9090413408963547706">"કૅમેરો"</string> + <string name="permgrouplab_camera" msgid="9090413408963547706">"કૅમેરા"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"ચિત્રો લેવાની અને વીડિઓ રેકોર્ડ કરવાની"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"કૉલ લૉગ"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"ફોન કૉલ લૉગ વાંચો અને લખો"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"વાતચીત"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ગ્રૂપ વાતચીત"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"વ્યક્તિગત વ્યૂ"</string> diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml index cd6eec1ade9e..ca9ad6778590 100644 --- a/core/res/res/values-hi/strings.xml +++ b/core/res/res/values-hi/strings.xml @@ -559,7 +559,7 @@ <string name="fingerprint_error_user_canceled" msgid="7685676229281231614">"उपयोगकर्ता ने फिंगरप्रिंट की पुष्टि की कार्रवाई रद्द कर दी है."</string> <string name="fingerprint_error_lockout" msgid="7853461265604738671">"बहुत ज़्यादा प्रयास कर लिए गए हैं. बाद में फिर से प्रयास करें."</string> <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"बहुत ज़्यादा कोशिशें. फ़िंगरप्रिंट सेंसर अक्षम है."</string> - <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से प्रयास करें."</string> + <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"फिर से कोशिश करें."</string> <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"कोई फ़िंगरप्रिंट रजिस्टर नहीं किया गया है."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"इस डिवाइस में फ़िंगरप्रिंट सेंसर नहीं है."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"सेंसर कुछ समय के लिए बंद कर दिया गया है."</string> @@ -680,8 +680,8 @@ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रीनका लॉक खोलते समय गलत तरीके से लिखे गए पासवर्ड पर नज़र रखें, और अगर बार-बार गलत पासवर्ड लिखा जाता है तो फ़ोन को लॉक करें या इस उपयोगकर्ता का सभी डेटा मिटा दें."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रीन लॉक बदलना"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रीन लॉक बदलना."</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रीन लॉक करें"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"नियंत्रित करें कि स्क्रीन कैसे और कब लॉक हो."</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रीन लॉक करना"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"इससे नियंत्रित होगा कि स्क्रीन कैसे और कब लॉक हो."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"सारा डेटा मिटाना"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"फ़ैक्टरी डेटा रीसेट करके चेतावनी दिए बिना फ़ोन का डेटा मिटाना."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ़ैक्ट्री डेटा रीसेट करके अपने Android TV डिवाइस का डेटा बिना चेतावनी दिए मिटाएं."</string> @@ -698,8 +698,8 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"संग्रहित ऐप्स डेटा को एन्क्रिप्ट किया जाना आवश्यक है."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"कैमरों को अक्षम करें"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"सभी डिवाइस कैमरों का उपयोग रोकें."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रीन लॉक की कुछ सुविधाएं बंद करें"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"कुछ स्क्रीन लाॅक सुविधाओं का उपयोग रोकें."</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रीन लॉक की कुछ सुविधाएं बंद करना"</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"यह कुछ स्क्रीन लाॅक सुविधाओं का इस्तेमाल रोकती है."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"घर"</item> <item msgid="7740243458912727194">"मोबाइल"</item> @@ -832,8 +832,8 @@ <string name="lockscreen_emergency_call" msgid="7500692654885445299">"आपातकाल"</string> <string name="lockscreen_return_to_call" msgid="3156883574692006382">"कॉल पर वापस लौटें"</string> <string name="lockscreen_pattern_correct" msgid="8050630103651508582">"सही!"</string> - <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से प्रयास करें"</string> - <string name="lockscreen_password_wrong" msgid="8605355913868947490">"फिर से प्रयास करें"</string> + <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"फिर से कोशिश करें"</string> + <string name="lockscreen_password_wrong" msgid="8605355913868947490">"फिर से कोशिश करें"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"सभी सुविधाओं और डेटा के लिए अनलॉक करें"</string> <string name="faceunlock_multiple_failures" msgid="681991538434031708">"मालिक का चेहरा पहचानकर अनलॉक करने की तय सीमा खत्म हो गई"</string> <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"कोई सिम कार्ड नहीं है"</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"यूएसबी डीबग करने के लिए एडीबी कनेक्ट किया गया"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"यूएसबी को डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डीबग करना अक्षम करने के लिए चुनें."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस तरीके से डीबग करने की सुविधा फ़ोन से कनेक्ट है"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए टैप करें"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस तरीके से डीबग करने की सुविधा बंद करने के लिए चुनें."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वॉयरलेस डीबगिंग कनेक्ट है"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वॉयरलेस डीबगिंग की सुविधा बंद करने के लिए टैप करें"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वॉयरलेस डीबगिंग की सुविधा बंद करने के लिए चुनें."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"टेस्ट हार्नेस मोड चालू किया गया"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"टेस्ट हार्नेस मोड बंद करने के लिए फ़ैक्ट्री रीसेट करें."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"सीरियल कंसोल को चालू करें"</string> @@ -1660,7 +1660,7 @@ <string name="user_switched" msgid="7249833311585228097">"मौजूदा उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> पर स्विच किया जा रहा है…"</string> <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्थान किया जा रहा है…"</string> - <string name="owner_name" msgid="8713560351570795743">"स्वामी"</string> + <string name="owner_name" msgid="8713560351570795743">"मालिक"</string> <string name="error_message_title" msgid="4082495589294631966">"गड़बड़ी"</string> <string name="error_message_change_not_allowed" msgid="843159705042381454">"आपका व्यवस्थापक इस बदलाव की अनुमति नहीं देता"</string> <string name="app_not_found" msgid="3429506115332341800">"इस कार्यवाही को प्रबंधित करने के लिए कोई ऐप्स नहीं मिला"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"बातचीत"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ग्रुप में बातचीत"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"निजी व्यू"</string> diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml index 94ff54c3cd48..4dab59979ccd 100644 --- a/core/res/res/values-hr/strings.xml +++ b/core/res/res/values-hr/strings.xml @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Razgovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupni razgovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobni prikaz"</string> diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml index 30a75dc25ff4..a2eac83638ae 100644 --- a/core/res/res/values-hu/strings.xml +++ b/core/res/res/values-hu/strings.xml @@ -34,7 +34,7 @@ <string name="defaultMsisdnAlphaTag" msgid="2285034592902077488">"MSISDN1"</string> <string name="mmiError" msgid="2862759606579822246">"Kapcsolódási probléma vagy érvénytelen MMI-kód."</string> <string name="mmiFdnError" msgid="3975490266767565852">"A művelet fix hívószámokra van korlátozva."</string> - <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"A hívásátirányítási beállításokat barangolás közben telefonról nem lehet módosítani."</string> + <string name="mmiErrorWhileRoaming" msgid="1204173664713870114">"A hívásátirányítási beállításokat roaming közben telefonról nem lehet módosítani."</string> <string name="serviceEnabled" msgid="7549025003394765639">"A szolgáltatás engedélyezésre került."</string> <string name="serviceEnabledFor" msgid="1463104778656711613">"Engedélyezett szolgáltatás(ok):"</string> <string name="serviceDisabled" msgid="641878791205871379">"A szolgáltatás ki van kapcsolva."</string> @@ -113,12 +113,12 @@ <string name="roamingText2" msgid="2834048284153110598">"Barangolásjelző villog"</string> <string name="roamingText3" msgid="831690234035748988">"A környéken kívül"</string> <string name="roamingText4" msgid="2171252529065590728">"Épületen kívül"</string> - <string name="roamingText5" msgid="4294671587635796641">"Barangolás - preferált rendszer"</string> - <string name="roamingText6" msgid="5536156746637992029">"Barangolás -- elérhető rendszer"</string> - <string name="roamingText7" msgid="1783303085512907706">"Barangolás - szövetségi partner"</string> - <string name="roamingText8" msgid="7774800704373721973">"Barangolás -- Prémium partner"</string> - <string name="roamingText9" msgid="1933460020190244004">"Barangolás - teljes szolgáltatásműködés"</string> - <string name="roamingText10" msgid="7434767033595769499">"Barangolás - részleges szolgáltatásműködés"</string> + <string name="roamingText5" msgid="4294671587635796641">"Roaming - preferált rendszer"</string> + <string name="roamingText6" msgid="5536156746637992029">"Roaming - elérhető rendszer"</string> + <string name="roamingText7" msgid="1783303085512907706">"Roaming - szövetségi partner"</string> + <string name="roamingText8" msgid="7774800704373721973">"Roaming - Prémium partner"</string> + <string name="roamingText9" msgid="1933460020190244004">"Roaming - teljes szolgáltatásműködés"</string> + <string name="roamingText10" msgid="7434767033595769499">"Roaming - részleges szolgáltatásműködés"</string> <string name="roamingText11" msgid="5245687407203281407">"Barangolást jelző szalaghirdetés bekapcsolva"</string> <string name="roamingText12" msgid="673537506362152640">"Barangolást jelző szalaghirdetés kikapcsolva"</string> <string name="roamingTextSearching" msgid="5323235489657753486">"Szolgáltatás keresése"</string> @@ -1309,7 +1309,7 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB-hibakereső csatlakoztatva"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Koppintson az USB-hibakeresés kikapcsolásához"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Válassza ezt az USB hibakeresés kikapcsolásához."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Vezeték nélküli hibakereső csatlakoztatva"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Vezeték nélküli hibakeresés csatlakoztatva"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Koppintson a vezeték nélküli hibakeresés kikapcsolásához"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Válassza ezt a vezeték nélküli hibakeresés letiltásához."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Tesztelési alapkörnyezet mód engedélyezve"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Beszélgetés"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Csoportos beszélgetés"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Személyes nézet"</string> diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml index 21aa14802157..8ca31763d7c5 100644 --- a/core/res/res/values-hy/strings.xml +++ b/core/res/res/values-hy/strings.xml @@ -1546,7 +1546,7 @@ <string name="activity_resolver_use_once" msgid="948462794469672658">"Միայն այս անգամ"</string> <string name="activity_resolver_app_settings" msgid="6758823206817748026">"Կարգավորումներ"</string> <string name="activity_resolver_work_profiles_support" msgid="4071345609235361269">"%1$s-ը չի աջակցում աշխատանքային պրոֆիլներ"</string> - <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Գրասալիկ"</string> + <string name="default_audio_route_name" product="tablet" msgid="367936735632195517">"Պլանշետ"</string> <string name="default_audio_route_name" product="tv" msgid="4908971385068087367">"Հեռուստացույց"</string> <string name="default_audio_route_name" product="default" msgid="9213546147739983977">"Հեռախոս"</string> <string name="default_audio_route_name_dock_speakers" msgid="1551166029093995289">"Դոկ-կայանի բարձրախոսներ"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>՝"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Նամակագրություն"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Խմբային նամակագրություն"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Անձնական"</string> diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml index 6f2deee7e511..c45f349146d9 100644 --- a/core/res/res/values-is/strings.xml +++ b/core/res/res/values-is/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtal"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Hópsamtal"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persónulegt yfirlit"</string> diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml index 39e5a6e61d66..704b233a010c 100644 --- a/core/res/res/values-it/strings.xml +++ b/core/res/res/values-it/strings.xml @@ -295,7 +295,7 @@ <string name="managed_profile_label" msgid="7316778766973512382">"Passa a profilo di lavoro"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"Contatti"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"accedere ai contatti"</string> - <string name="permgrouplab_location" msgid="1858277002233964394">"Geolocalizz."</string> + <string name="permgrouplab_location" msgid="1858277002233964394">"Geolocalizzazione"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"accedere alla posizione di questo dispositivo"</string> <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendario"</string> <string name="permgroupdesc_calendar" msgid="6762751063361489379">"accedere al calendario"</string> @@ -309,7 +309,7 @@ <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"Consente di accedere all\'attività fisica"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Fotocamera"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"scattare foto e registrare video"</string> - <string name="permgrouplab_calllog" msgid="7926834372073550288">"Log chiamate"</string> + <string name="permgrouplab_calllog" msgid="7926834372073550288">"Registri chiamate"</string> <string name="permgroupdesc_calllog" msgid="2026996642917801803">"leggere e modificare il registro chiamate del telefono"</string> <string name="permgrouplab_phone" msgid="570318944091926620">"Telefono"</string> <string name="permgroupdesc_phone" msgid="270048070781478204">"eseguire e gestire le telefonate"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Per estendere la durata della batteria, Risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Per estendere la durata della batteria, il risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\"\n\n"<annotation id="url">"Ulteriori informazioni"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Per estendere la durata della batteria, il risparmio energetico:\n·Attiva il Tema scuro\n·Disattiva o limita le attività in background, alcuni effetti visivi e altre funzionalità come \"Ok Google\""</string> <string name="data_saver_description" msgid="4995164271550590517">"Per contribuire a ridurre l\'utilizzo dei dati, la funzione Risparmio dati impedisce ad alcune app di inviare o ricevere dati in background. Un\'app in uso può accedere ai dati, ma potrebbe farlo con meno frequenza. Esempio: le immagini non vengono visualizzate finché non le tocchi."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Attivare Risparmio dati?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Attiva"</string> diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml index 4b131247e7ee..5c0ab1448bbf 100644 --- a/core/res/res/values-iw/strings.xml +++ b/core/res/res/values-iw/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"שיחה"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"שיחה קבוצתית"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"תצוגה אישית"</string> diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml index f31f1c830688..1e5f5ec50eb9 100644 --- a/core/res/res/values-ja/strings.xml +++ b/core/res/res/values-ja/strings.xml @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"指紋を一部しか検出できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"指紋を処理できませんでした。もう一度お試しください。"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"指紋認証センサーに汚れがあります。汚れを落としてもう一度お試しください。"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"指の動きが速すぎました。もう一度お試しください。"</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"指を離すのが速すぎました。もう一度お試しください。"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"指の動きが遅すぎました。もう一度お試しください。"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"保存したアプリデータが暗号化されるようにします。"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"カメラを無効にする"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"すべてのデバイスカメラを使用できないようにします。"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"画面ロックの一部の機能を無効化"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"画面ロックの一部機能を無効化"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"画面ロックの一部の機能の使用を禁止します。"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"自宅"</item> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"会話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"グループの会話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人用ビュー"</string> diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml index b5892ebbe434..a417eab484a9 100644 --- a/core/res/res/values-kk/strings.xml +++ b/core/res/res/values-kk/strings.xml @@ -305,8 +305,8 @@ <string name="permgroupdesc_storage" msgid="6351503740613026600">"құрылғыдағы фотосуреттерге, мультимедиаға және файлдарға қол жеткізу"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"аудио жазу"</string> - <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Физикалық әрекет"</string> - <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"физикалық әрекет дерегін алу"</string> + <string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Іс-қимыл"</string> + <string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"іс-қимыл дерегін алу"</string> <string name="permgrouplab_camera" msgid="9090413408963547706">"Камера"</string> <string name="permgroupdesc_camera" msgid="7585150538459320326">"суретке түсіріп, бейне жазу"</string> <string name="permgrouplab_calllog" msgid="7926834372073550288">"Қоңырау журналдары"</string> @@ -542,7 +542,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Танылмады"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификациядан бас тартылды."</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Ешқандай PIN коды, өрнек немесе құпия сөз орнатылмаған."</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі ішінара анықталды. Әрекетті қайталаңыз."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Саусақ ізі толық анықталмады. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Саусақ ізін өңдеу мүмкін емес. Әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Саусақ ізі сенсоры лас. Тазалап, әрекетті қайталаңыз."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Саусағыңызды тым жылдам қозғалттыңыз. Әрекетті қайталап көріңіз."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Камераларды өшіру"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Құрылғыдағы барлық камералар қолданысын бөгеу."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Экран құлпы функцияларын өшіру"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Кейбір экранды құлыптау мүмкіндіктерін пайдалануға тыйым салынады."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Кейбір экранды құлыптау мүмкіндіктерін пайдалануға тыйым салу."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Үй"</item> <item msgid="7740243458912727194">"Ұялы тел."</item> @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Үнемі көрсету"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасы сіздің Android OЖ-бен үйлеспейді және дұрыс жұмыс істемеуі ықтимал. Қолданбаның жаңартылған нұсқасы қолжетімді болуы мүмкін."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Үнемі көрсету"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңартуды тексеру"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Жаңа нұсқасының бар-жоғын тексеру"</string> <string name="smv_application" msgid="3775183542777792638">"<xliff:g id="APPLICATION">%1$s</xliff:g> қолданбасы (<xliff:g id="PROCESS">%2$s</xliff:g> процесі) өзі қолданған StrictMode саясатын бұзды."</string> <string name="smv_process" msgid="1398801497130695446">"<xliff:g id="PROCESS">%1$s</xliff:g> үрдісі өздігінен күшіне енген ҚатаңРежим ережесін бұзды."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"Телефон жаңартылуда…"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"Қолданба қолжетімді емес"</string> <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> қазір қолжетімді емес."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Қолданба Android жүйесінің ескі нұсқасына арналған және дұрыс жұмыс істемеуі мүмкін. Жаңартылған нұсқаны тексеріңіз немесе әзірлеушіге хабарласыңыз."</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңартылған нұсқаны тексеру"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Жаңа нұсқасының бар-жоғын тексеру"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Сізде жаңа хабарлар бар"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"Көру үшін SMS қолданбасын ашыңыз"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Кейбір функциялар істемеуі мүмкін."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтық чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Жеке көру"</string> diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml index 7de5a8b40ffa..50cea4455695 100644 --- a/core/res/res/values-km/strings.xml +++ b/core/res/res/values-km/strings.xml @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"ប្តូរការចាក់សោអេក្រង់"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"ប្តូរការចាក់សោអេក្រង់។"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"ចាក់សោអេក្រង់"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"ពិនិត្យវិធី និងពេលវេលាចាក់សោអេក្រង់។"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"គ្រប់គ្រងវិធី និងពេលវេលាចាក់សោអេក្រង់។"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"លុបទិន្នន័យទាំងអស់"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"លុបទិន្នន័យកុំព្យូទ័របន្ទះដោយមិនព្រមានដោយអនុវត្តការកំណត់ទិន្នន័យដូចចេញពីរោងចក្រ។"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"លុបទិន្នន័យឧបករណ៍ Android TV របស់អ្នកដោយមិនមានការព្រមាន ដោយធ្វើការកំណត់ទិន្នន័យដូចចេញពីរោងចក្រ។"</string> @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>៖"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ការសន្ទនា"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ការសន្ទនាជាក្រុម"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ទិដ្ឋភាពផ្ទាល់ខ្លួន"</string> diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml index 8d4b30ac100d..bbe9201bacaf 100644 --- a/core/res/res/values-kn/strings.xml +++ b/core/res/res/values-kn/strings.xml @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", ಸುರಕ್ಷಿತ"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ಮರೆತಿರುವಿರಿ"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"ತಪ್ಪು ಪ್ಯಾಟರ್ನ್"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"ಪ್ಯಾಟರ್ನ್ ತಪ್ಪಾಗಿದೆ"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"ತಪ್ಪು ಪಾಸ್ವರ್ಡ್"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"ತಪ್ಪಾದ ಪಿನ್"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ಸಂವಾದ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ಗುಂಪು ಸಂವಾದ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ವೈಯಕ್ತಿಕ ವೀಕ್ಷಣೆ"</string> diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml index 73a769b65c19..a5c88328d39f 100644 --- a/core/res/res/values-ko/strings.xml +++ b/core/res/res/values-ko/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"대화"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"그룹 대화"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"개인 뷰"</string> diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml index 69d886f0dbd4..5ea4383c6a45 100644 --- a/core/res/res/values-ky/strings.xml +++ b/core/res/res/values-ky/strings.xml @@ -491,7 +491,7 @@ <string name="permlab_changeNetworkState" msgid="8945711637530425586">"тармак туташымдуулугун өзгөртүү"</string> <string name="permdesc_changeNetworkState" msgid="649341947816898736">"Колдонмого тармактык туташуунун абалын өзгөртүү мүмкүнчүлүгүн берет."</string> <string name="permlab_changeTetherState" msgid="9079611809931863861">"интернет бөлүшүү байланышын өзгөртүү"</string> - <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Колдонмого тетеринг тармактык туташуусунун абалын өзгөртүү мүмкүнчүлүгүн берет."</string> + <string name="permdesc_changeTetherState" msgid="3025129606422533085">"Колдонмо модем режимин күйгүзүп, өчүрө алат."</string> <string name="permlab_accessWifiState" msgid="5552488500317911052">"Wi-Fi туташууларын көрүү"</string> <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Колдонмого Wi-Fi жандырылгандыгы жана туташкан Wi-Fi түзмөктөрдүн аттары сыяктуу, Wi-Fi түйүндөрүнүн маалыматтарын көрүүгө уруксаты берет."</string> <string name="permlab_changeWifiState" msgid="7947824109713181554">"Wi-Fi менен туташуу жана ажыратуу"</string> @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Манжа изи жарым-жартылай аныкталды. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Манжа изи иштелбей койду. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Манжа изинин сенсору кирдеп калган. Тазалап, кайталап көрүңүз."</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Манжа өтө тез жылдырылды. Кайталап көрүңүз."</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Манжаңызды өтө тез жылдырдыңыз. Кайталап көрүңүз."</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"Манжа өтө жай жылды. Кайталап көрүңүз."</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -1311,7 +1311,7 @@ <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB аркылуу мүчүлүштүктөрдү оңдоону өчүрүүнү тандаңыз."</string> <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Мүчүлүштүктөрдү зымсыз оңдоо иштетилди"</string> <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүү үчүн таптап коюңуз"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Мүчүлүштүктөрдү зымсыз оңдоону өчүрүүнү тандаңыз."</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Мүчүлүштүктөрдү Wi-Fi аркылуу оңдоону өчүрүңүз."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Сыноо программасынын режими иштетилди"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Сыноо программасынын режимин өчүрүү үчүн, баштапкы жөндөөлөргө кайтарыңыз."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Сериялык консоль иштетилди"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Жазышуу"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Топтук маек"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Жеке көрүнүш"</string> diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml index 2e331a03bb97..b22fa0e7b6b4 100644 --- a/core/res/res/values-lo/strings.xml +++ b/core/res/res/values-lo/strings.xml @@ -293,7 +293,7 @@ <string name="android_system_label" msgid="5974767339591067210">"ລະບົບ Android"</string> <string name="user_owner_label" msgid="8628726904184471211">"ສະຫຼັບໄປໂປຣໄຟລ໌ສ່ວນຕົວ"</string> <string name="managed_profile_label" msgid="7316778766973512382">"ສະຫຼັບໄປໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກ"</string> - <string name="permgrouplab_contacts" msgid="4254143639307316920">"ລາຍຊື່"</string> + <string name="permgrouplab_contacts" msgid="4254143639307316920">"ລາຍຊື່ຜູ້ຕິດຕໍ່"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"ເຂົ້າຫາລາຍຊື່ຂອງທ່ານ"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"ສະຖານທີ່"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ເຂົ້າເຖິງຂໍ້ມູນສະຖານທີ່ຂອງອຸປະກອນນີ້"</string> @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"ປ່ຽນລັອກໜ້າຈໍ"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"ປ່ຽນລັອກໜ້າຈໍ."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"ລັອກໜ້າຈໍ"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"ຄວບຄຸມວ່າໜ້າຈໍຄວນຈະຖືກລັອກເມື່ອໃດ ແລະແນວໃດ"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"ຄວບຄຸມວ່າໜ້າຈໍຄວນຈະຖືກລັອກເມື່ອໃດ ແລະ ແນວໃດ."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"ລຶບຂໍ້ມູນທັງໝົດ"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ລຶບຂໍ້ມູນຂອງແທັບເລັດໂດຍບໍ່ມີການເຕືອນ ໂດຍການຣີເຊັດກັບຄືນໃຫ້ເປັນແບບທີ່ມາຈາກໂຮງງານ."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"ລຶບຂໍ້ມູນຂອງອຸປະກອນ Android TV ທ່ານໂດຍບໍ່ຕ້ອງແຈ້ງເຕືອນດ້ວຍການຣີເຊັດຂໍ້ມູນເປັນຄ່າເລີ່ມຕົ້ນຈາກໂຮງງານ."</string> diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml index 021717d5133c..1b2d0b59f080 100644 --- a/core/res/res/values-lt/strings.xml +++ b/core/res/res/values-lt/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pokalbis"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupės pokalbis"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Asmeninė peržiūra"</string> diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml index 6ea61a170fe0..9cb4bd6b89cd 100644 --- a/core/res/res/values-lv/strings.xml +++ b/core/res/res/values-lv/strings.xml @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Saruna"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grupas saruna"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personisks skats"</string> diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml index 9c434db0d025..3807da8bcd09 100644 --- a/core/res/res/values-mk/strings.xml +++ b/core/res/res/values-mk/strings.xml @@ -194,7 +194,7 @@ <string name="location_changed_notification_title" msgid="3620158742816699316">"Апликациите може да пристапуваат до вашата локација"</string> <string name="location_changed_notification_text" msgid="7158423339982706912">"Контактирајте со IT-администраторот за да дознаете повеќе"</string> <string name="country_detector" msgid="7023275114706088854">"Детектор на земја"</string> - <string name="location_service" msgid="2439187616018455546">"Услуги според локација"</string> + <string name="location_service" msgid="2439187616018455546">"Услуга за локација"</string> <string name="sensor_notification_service" msgid="7474531979178682676">"Услуга за известување од сензорот"</string> <string name="twilight_service" msgid="8964898045693187224">"Услуга за самрак"</string> <string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string> @@ -678,14 +678,14 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го таблетот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"Го следи бројот на погрешно внесени лозинки при отклучување на екранот и го заклучува уредот Android TV или ги брише сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"Набљудувај го бројот на погрешно внесени лозинки при отклучување на екранот и заклучи го телефонот или избриши ги сите податоци од овој корисник доколку се внесени премногу погрешни лозинки."</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"Промени го заклучувањето на екранот."</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"Промени го заклучувањето на екранот"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Промени го заклучувањето на екранот."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Заклучи го екранот"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"Контролирај како и кога се заклучува екранот."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Избриши ги сите податоци"</string> - <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Избриши ги податоците во таблетот без предупредување со вршење на фабричко ресетирање на податоци."</string> + <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Избриши ги податоците во таблетот без предупредување со ресетирање на фабрички податоци."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Ги брише податоците на вашиот уред Android TV без предупредување, така што ќе изврши ресетирање на фабричките податоци."</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Избриши ги податоците во телефонот без предупредување со вршење на фабричко ресетирање на податоци."</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Избриши ги податоците во телефонот без предупредување со ресетирање на фабрички податоци."</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"Избриши ги податоците на корисникот"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Избриши ги податоците на овој корисник на таблетот без предупредување."</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Ги брише податоците на овој корисник на уредов Android TV без предупредување."</string> @@ -699,7 +699,7 @@ <string name="policylab_disableCamera" msgid="5749486347810162018">"Оневозможи фотоапарати"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Спречи употреба на сите камери на уредот."</string> <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онев. функции од заклуч. екран"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречете користење на некои функции од заклучување на екранот."</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречи користење на некои функции од заклучување на екранот."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Дома"</item> <item msgid="7740243458912727194">"Мобилен"</item> @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Разговор"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групен разговор"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Службени"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Личен приказ"</string> diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml index ad0cde1d4f87..e54cf72a7ac3 100644 --- a/core/res/res/values-ml/strings.xml +++ b/core/res/res/values-ml/strings.xml @@ -680,7 +680,7 @@ <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"സ്ക്രീൻ അൺലോക്കുചെയ്യുമ്പോൾ തെറ്റായി ടൈപ്പുചെയ്ത പാസ്വേഡുകളുടെ എണ്ണം നിരീക്ഷിക്കുകയും നിരവധി തവണ പാസ്വേഡ് ടൈപ്പുചെയ്തെങ്കിൽ ഫോൺ ലോക്കുചെയ്യുകയോ ഈ എല്ലാ ഉപയോക്തൃവിവരവും മായ്ക്കുകയോ ചെയ്യുക."</string> <string name="policylab_resetPassword" msgid="214556238645096520">"സ്ക്രീൻ ലോക്ക് മാറ്റുക"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"സ്ക്രീൻ ലോക്ക് മാറ്റുക."</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"സ്ക്രീൻ ലോക്കുചെയ്യുക"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"സ്ക്രീൻ ലോക്ക് ചെയ്യുക"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"സ്ക്രീൻ ലോക്കുകൾ എങ്ങനെ വേണമെന്നും എപ്പോൾ വേണമെന്നും എന്നത് നിയന്ത്രിക്കുക"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"എല്ലാ ഡാറ്റയും മായ്ക്കുക"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"ഒരു ഫാക്ടറി ഡാറ്റ പുനഃസജ്ജീകരണം നടപ്പിലാക്കുന്നതിലൂടെ ടാബ്ലെറ്റിന്റെ ഡാറ്റ മുന്നറിയിപ്പില്ലാതെ മായ്ക്കുക."</string> @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തു"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ഡീബഗ്ഗുചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"വയർലെസ് ഡീബഗ്ഗ് ചെയ്യൽ പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"വയർലെസ് ഡീബഗ്ഗിംഗ് കണക്റ്റ് ചെയ്തിരിക്കുന്നു"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"വയർലെസ് ഡീബഗ്ഗിംഗ് ഓഫാക്കാൻ ടാപ്പ് ചെയ്യുക"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"വയർലെസ് ഡീബഗ്ഗിംഗ് പ്രവർത്തനരഹിതമാക്കാൻ തിരഞ്ഞെടുക്കുക."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"പരിശോധനാ സംവിധാനങ്ങൾ മോഡ് പ്രവർത്തനക്ഷമമാക്കി"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"പരിശോധനാ സംവിധാന മോഡ് പ്രവർത്തനരഹിതമാക്കാൻ ഫാക്ടറി പുനഃക്രമീകരണം നിർവഹിക്കുക."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"സീരിയൽ കൺസോൾ പ്രവർത്തനക്ഷമമാക്കി"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"സംഭാഷണം"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ഗ്രൂപ്പ് സംഭാഷണം"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"വ്യക്തിപര കാഴ്ച"</string> diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml index 462d3a5c52ea..4fcbe76d1125 100644 --- a/core/res/res/values-mn/strings.xml +++ b/core/res/res/values-mn/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB дебаг холбогдсон"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB дебаг хийхийг унтраахын тулд товшино уу"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB дебаг хийхийг идэвхгүй болгох бол сонгоно уу."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Утасгүй дебагийг холболоо"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Утасгүй дебагийг унтраахын тулд товшино уу"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Утасгүй дебагийг идэвхгүй болгохын тулд сонгоно уу."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wireless debugging-г холболоо"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wireless debugging-г унтраахын тулд товшино уу"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Wireless debugging-г идэвхгүй болгохын тулд сонгоно уу."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Туршилтын цогц горимыг идэвхжүүлсэн"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Туршилтын цогц горимыг идэвхгүй болгохын тулд үйлдвэрийн төлөвт шинэчилнэ үү."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Цуваа консолыг идэвхжүүлсэн"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Харилцан яриа"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Бүлгийн харилцан яриа"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Хувийн харагдах байдал"</string> diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml index 5dc743355260..feba806659e4 100644 --- a/core/res/res/values-mr/strings.xml +++ b/core/res/res/values-mr/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"संभाषण"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"गट संभाषण"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"वैयक्तिक दृश्य"</string> diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml index 752a9c72e6ee..1a69a731f4cc 100644 --- a/core/res/res/values-ms/strings.xml +++ b/core/res/res/values-ms/strings.xml @@ -681,11 +681,11 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"Tukar kunci skrin"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"Tukar kunci skrin."</string> <string name="policylab_forceLock" msgid="7360335502968476434">"Kunci skrin"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"Mengawal cara dan masa skrin dikunci."</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"Kawal cara dan masa skrin dikunci."</string> <string name="policylab_wipeData" msgid="1359485247727537311">"Padamkan semua data"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"Memadamkan data tablet tanpa amaran dengan melakukan tetapan semula data kilang."</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"Padamkan data peranti Android TV anda tanpa amaran dengan melaksanakan tetapan semula data kilang."</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Memadamkan data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"Padamkan data telefon tanpa amaran dengan melakukan tetapan semula data kilang."</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"Padam data pengguna"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"Padam data pengguna ini pada tablet ini tanpa amaran."</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"Padamkan data pengguna ini pada peranti Android TV tanpa amaran."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Perbualan"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Perbualan Kumpulan"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Paparan peribadi"</string> diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml index e94e5536bd0b..c93ca0f30ce9 100644 --- a/core/res/res/values-my/strings.xml +++ b/core/res/res/values-my/strings.xml @@ -678,9 +678,9 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက တက်ဘလက်အား သော့ချခြင်း သို့မဟုတ် တက်ဘလက်၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"မျက်နှာပြင်ကို လော့ခ်ဖွင့်သည့်အခါ စကားဝှက်မှားယွင်းစွာ ရိုက်သွင်းသည့်အကြိမ်ရေကို စောင့်ကြည့်ပြီး မှားယွင်းသည့်အကြိမ်ရေ အလွန်များလာပါက သင့် Android TV စက်ပစ္စည်းကို လော့ခ်ချခြင်း သို့မဟုတ် ဤအသုံးပြုသူဒေတာများအားလုံးကို ဖျက်ခြင်းတို့ ပြုလုပ်သွားပါမည်။"</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"ဖန်မျက်နှာပြင်အား သော့ဖွင့်စဉ် လျှို့ဝှက်ကုဒ်အမှားများ ရိုက်သွင်းမှုအား စောင့်ကြည့်ရန်နှင့်၊ လျှို့ဝှက်ကုဒ်အမှားများ များစွာ ရိုက်သွင်းပါက ဖုန်းအား သော့ချခြင်း သို့မဟုတ် ဖုန်း၏ အချက်အလက်များအား ဖျက်ပစ်ခြင်းများ ပြုလုပ်မည်။"</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"မျက်နှာပြင်လော့ခ်ပြောင်းခြင်း"</string> - <string name="policydesc_resetPassword" msgid="4626419138439341851">"မျက်နှာပြင်လော့ခ်ပြောင်းသည်။"</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"မျက်နှာပြင်အား လော့ခ်ချခြင်း"</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"ဖန်သားပြင်လော့ခ်ပြောင်းခြင်း"</string> + <string name="policydesc_resetPassword" msgid="4626419138439341851">"ဖန်သားပြင်လော့ခ်ပြောင်းသည်။"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"ဖန်သားပြင်အား လော့ခ်ချခြင်း"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"ဖန်သားပြင် လော့ခ်ချချိန်၊ လော့ချနည်းကို ထိမ်းချုပ်သည်။"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"ဒေတာအားလုံးအားဖျက်ခြင်း"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"စက်ရုံထုတ် အခြေအနေအား ပြန်ပြောင်းခြင်းဖြင့် တက်ဘလက်ရှိ အချက်အလက်များအား ကြိုတင်သတိပေးမှုမရှိပဲ ဖျက်စီးရန်"</string> @@ -1855,7 +1855,7 @@ <string name="expand_button_content_description_expanded" msgid="7484217944948667489">"ခေါက်သိမ်းရန်"</string> <string name="expand_action_accessibility" msgid="1947657036871746627">"ချဲ့ခြင်းခလုတ်"</string> <string name="usb_midi_peripheral_name" msgid="490523464968655741">"Android USB ဘေးဘက်အပေါက်"</string> - <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"အန်းဒရွိုက်"</string> + <string name="usb_midi_peripheral_manufacturer_name" msgid="7557148557088787741">"Android"</string> <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB ဘေးရှိပို့တ်"</string> <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"နောက်ထပ် ရွေးစရာများ"</string> <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"ကိရိယာဘားအပိုအား ပိတ်ရန်"</string> diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml index e41127b30609..78580644f2d5 100644 --- a/core/res/res/values-nb/strings.xml +++ b/core/res/res/values-nb/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Samtale"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppesamtale"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personlig visning"</string> diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml index 6693823eb4c1..2ad119f23fe1 100644 --- a/core/res/res/values-ne/strings.xml +++ b/core/res/res/values-ne/strings.xml @@ -678,14 +678,14 @@ <string name="policydesc_watchLogin_secondaryUser" product="tablet" msgid="2049038943004297474">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा ट्याब्लेट लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string> <string name="policydesc_watchLogin_secondaryUser" product="tv" msgid="8965224107449407052">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप गरेको सङ्ख्या निरीक्षण गर्नुहोस्, र धेरै पटक गलत पासवर्डहरू टाइप गरिएको खण्डमा आफ्नो Android TV यन्त्र लक गर्नुहोस् वा यो प्रयोगकर्ताको सम्पूर्ण डेटा मेटाउनुहोस्।"</string> <string name="policydesc_watchLogin_secondaryUser" product="default" msgid="9177645136475155924">"स्क्रिन अनलक गर्दा गलत पासवर्ड टाइप संख्या अनुगमन गर्नुहोस्, र यदि निकै धेरै गलत पासवर्डहरू टाइप गरिएमा फोन लक गर्नुहोस् वा प्रयोगकर्ताको डेटा मेटाउनुहोस्।"</string> - <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्नुहोस्"</string> + <string name="policylab_resetPassword" msgid="214556238645096520">"स्क्रिन लक परिवर्तन गर्ने"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"स्क्रिन लक परिवर्तन गर्नुहोस्।"</string> - <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्नुहोस्।"</string> + <string name="policylab_forceLock" msgid="7360335502968476434">"स्क्रिन लक गर्ने"</string> <string name="policydesc_forceLock" msgid="1008844760853899693">"कसरी र कहिले स्क्रिन लक गर्ने नियन्त्रण गर्नुहोस्।"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"सबै डेटा मेट्नुहोस्"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै ट्याबल्टको डेटा मेट्नुहोस्।"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"फ्याक्ट्री डेटा रिसेट गरेर चेतावनी नदिइकन आफ्नो Android TV यन्त्रको डेटा मेटाउनुहोस्।"</string> - <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नआउँदै फोनको डेटा मेट्नुहोस्।"</string> + <string name="policydesc_wipeData" product="default" msgid="8036084184768379022">"एउटा फ्याक्ट्रि डेटा पुनःसेट गरेर चेतावनी नदिइकन फोनको डेटा मेट्न।"</string> <string name="policylab_wipeData_secondaryUser" msgid="413813645323433166">"प्रयोगकर्ता डेटा मेट्नुहोस्"</string> <string name="policydesc_wipeData_secondaryUser" product="tablet" msgid="2336676480090926470">"चेतावनी बिना यो ट्याब्लेटमा यस प्रयोगकर्ताको डेटा मेट्नुहोस्।"</string> <string name="policydesc_wipeData_secondaryUser" product="tv" msgid="2293713284515865200">"यो Android TV यन्त्रमा भएको यस प्रयोगकर्ताको डेटा चेतावनी नदिइकन मेटाउनुहोस्।"</string> @@ -698,7 +698,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"भण्डार गरिएको डेटा इन्क्रिप्ट हुनु आवश्यक छ।"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"क्यामेरालाई असक्षम गराउनुहोस्"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"सबै उपकरण क्यामराहरूको प्रयोग रोक्नुहोस्"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"केही स्क्रिन लकका सुविधाहरू अक्षम गर्नुहोस्"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"स्क्रिन लकका केही सुविधा असक्षम पार्ने"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"केही स्क्रिन लक सुविधाहरूको प्रयोगमा रोक लगाउनुहोस्।"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"गृह"</item> @@ -930,7 +930,7 @@ <string name="js_dialog_before_unload_negative_button" msgid="3873765747622415310">"यही पृष्ठमा रहनुहोस्"</string> <string name="js_dialog_before_unload" msgid="7213364985774778744">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nके तपाईं यो पेजबाट नेभिगेट गर्न चाहनु हुन्छ भन्ने निश्चत छ?"</string> <string name="save_password_label" msgid="9161712335355510035">"निश्चित गर्नुहोस्"</string> - <string name="double_tap_toast" msgid="7065519579174882778">"जुक्ति: जुमलाई ठूलो र सानो पार्न दुई पटक हान्नुहोस्।"</string> + <string name="double_tap_toast" msgid="7065519579174882778">"जुक्ति: जुमलाई ठुलो र सानो पार्न दुई पटक हान्नुहोस्।"</string> <string name="autofill_this_form" msgid="3187132440451621492">"स्वतः भर्ने"</string> <string name="setup_autofill" msgid="5431369130866618567">"अटोफिल सेटअप गर्नुहोस्"</string> <string name="autofill_window_title" msgid="4379134104008111961">"<xliff:g id="SERVICENAME">%1$s</xliff:g> मार्फत स्वतः भरण गर्नुहोस्"</string> @@ -1315,9 +1315,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB डिबग गर्ने सुविधा सुचारू छ"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB डिबगिङलाई असक्षम पार्न ट्याप गर्नुहोस्।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डिबग प्रक्रिया जडान गरियो"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डिबग प्रक्रिया निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डिबग प्रक्रिया असक्षम पार्ने विकल्प चयन गर्नुहोस्।"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"वायरलेस डिबगिङ जोडियो"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"वायरलेस डिबगिङ निष्क्रिय पार्न ट्याप गर्नुहोस्"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"वायरलेस डिबगिङ असक्षम पार्न यो विकल्प चयन गर्नुहोस्।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"परीक्षण प्याकेज मोड सक्षम पारियो"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"परीक्षण प्याकेज मोड असक्षम पार्न फ्याक्ट्री रिसेट गर्नुहोस्।"</string> <string name="console_running_notification_title" msgid="6087888939261635904">"क्रमसम्बन्धी कन्सोल सक्षम पारियो"</string> @@ -1339,7 +1339,7 @@ <string name="select_keyboard_layout_notification_message" msgid="8835158247369158154">"भाषा र लेआउट चयन गर्न ट्याप गर्नुहोस्"</string> <string name="fast_scroll_alphabet" msgid="8854435958703888376">" ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> <string name="fast_scroll_numeric_alphabet" msgid="2529539945421557329">" 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"</string> - <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अन्य अनुप्रयोगहरूको माथिपट्टि देखाउनुहोस्"</string> + <string name="alert_windows_notification_channel_group_name" msgid="6063891141815714246">"अन्य अनुप्रयोगमा देखाउनुहोस्"</string> <string name="alert_windows_notification_channel_name" msgid="3437528564303192620">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string> <string name="alert_windows_notification_title" msgid="6331662751095228536">"<xliff:g id="NAME">%s</xliff:g> अन्य अनुप्रयोगहरूमा देखिँदैछ"</string> <string name="alert_windows_notification_message" msgid="6538171456970725333">"तपाईं <xliff:g id="NAME">%s</xliff:g> ले यो विशेषता प्रयोग नगरेको चाहनुहुन्न भने सेटिङहरू खोली यसलाई निष्क्रिय पार्न ट्याप गर्नुहोस्।"</string> @@ -1579,7 +1579,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", सुरक्षित"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ढाँचा बिर्सनु भयो"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"गलत ढाँचा"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"प्याटर्न मिलेन"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"गलत पासवर्ड"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"गलत PIN"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -1865,7 +1865,7 @@ <string name="usb_midi_peripheral_product_name" msgid="2836276258480904434">"USB पेरिफेरल पोर्ट"</string> <string name="floating_toolbar_open_overflow_description" msgid="2260297653578167367">"थप विकल्पहरू"</string> <string name="floating_toolbar_close_overflow_description" msgid="3949818077708138098">"ओभरफ्लो बन्द गर्नुहोस्"</string> - <string name="maximize_button_text" msgid="4258922519914732645">"ठूलो बनाउनुहोस्"</string> + <string name="maximize_button_text" msgid="4258922519914732645">"ठुलो बनाउनुहोस्"</string> <string name="close_button_text" msgid="10603510034455258">"बन्द गर्नुहोस्"</string> <string name="notification_messaging_title_template" msgid="772857526770251989">"<xliff:g id="CONVERSATION_TITLE">%1$s</xliff:g>: <xliff:g id="SENDER_NAME">%2$s</xliff:g>"</string> <plurals name="selected_count" formatted="false" msgid="3946212171128200491"> @@ -2050,8 +2050,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"वार्तालाप"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"सामूहिक वार्तालाप"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"व्यक्तिगत दृश्य"</string> @@ -2135,17 +2134,17 @@ <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM को कर्पोरेट लक खोलिदिन गरिएको अनुरोध असफल भयो"</string> <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM को सेवा प्रदायकसम्बन्धी लक खोलिदिन अनुरोध गर्न सकिएन।"</string> <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUK अनलक गर्न सकिएन।"</string> - <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUK अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUK प्रयोग गरेर अनलक गर्न सकिएन।"</string> <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"घरमा जोडिने SP सरहको PLMN अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID अनलक गर्न गरिएको अनुरोध असफल भयो।"</string> @@ -2162,17 +2161,17 @@ <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS" msgid="6020936629725666932">"RUIM को सेवा प्रदायकसम्बन्धी लक खोलियो।"</string> <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM को कर्पोरेट लक खोलियो।"</string> <string name="PERSOSUBSTATE_RUIM_RUIM_SUCCESS" msgid="2526483514124121988">"RUIM अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUK अनलक गरियो।"</string> - <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUK अनलक गरियो।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUK प्रयोग गरेर अनलक गर्न सकियो।"</string> <string name="PERSOSUBSTATE_SIM_SPN_SUCCESS" msgid="2053891977727320532">"SPN अनलक गरियो।"</string> <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS" msgid="8146602361895007345">"घरमा जोडिने SP सरहको PLMN अनलक गरियो।"</string> <string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID अनलक गरियो।"</string> diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml index 2fb675c4d5d0..90172037465d 100644 --- a/core/res/res/values-nl/strings.xml +++ b/core/res/res/values-nl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Gesprek"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Groepsgesprek"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Persoonlijke weergave"</string> diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml index b5757c6f674d..e28ed6f5c061 100644 --- a/core/res/res/values-or/strings.xml +++ b/core/res/res/values-or/strings.xml @@ -385,7 +385,7 @@ <string name="permdesc_foregroundService" msgid="8720071450020922795">"ଫୋର୍ଗ୍ରାଉଣ୍ଡ ସେବାଗୁଡ଼ିକୁ ବ୍ୟବହାର କରିବା ପାଇଁ ଆପ୍କୁ ଅନୁମତି ଦିଅନ୍ତୁ।"</string> <string name="permlab_getPackageSize" msgid="375391550792886641">"ଆପ୍ ଷ୍ଟୋରେଜ୍ ସ୍ଥାନର ମାପ କରନ୍ତୁ"</string> <string name="permdesc_getPackageSize" msgid="742743530909966782">"ଆପ୍ର କୋଡ୍, ଡାଟା ଓ କ୍ୟାଶ୍ ଆକାର ହାସଲ କରିବା ପାଇଁ ଏହାକୁ ଅନୁମତି ଦେଇଥାଏ।"</string> - <string name="permlab_writeSettings" msgid="8057285063719277394">"ସିଷ୍ଟମ୍ ସେଟିଙ୍ଗ ବଦଳାନ୍ତୁ"</string> + <string name="permlab_writeSettings" msgid="8057285063719277394">"ସିଷ୍ଟମ୍ ସେଟିଂସ ବଦଳାନ୍ତୁ"</string> <string name="permdesc_writeSettings" msgid="8293047411196067188">"ଆପ୍କୁ, ସିଷ୍ଟମର ସେଟିଙ୍ଗ ଡାଟା ବଦଳାଇବାକୁ ଦେଇଥାଏ। ହାନୀକାରକ ଆପ୍ ଦ୍ୱାରା ଆପଣଙ୍କ ସିଷ୍ଟମର କନଫିଗରେସନ୍ ଖରାପ ହୋଇପାରେ।"</string> <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"ଆରମ୍ଭ ହେଲେ ଚଲାନ୍ତୁ"</string> <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"ସିଷ୍ଟମ୍ ବୁଟ୍ ଶେଷ ହେବା କ୍ଷଣି ଆପ୍ଟିକୁ ସ୍ୱତଃ ଆରମ୍ଭ ହେବାକୁ ଦେଇଥାଏ। ଏହା କାରଣରୁ ଟାବଲେଟଟ୍ଟି ଚାଲୁ ହେବାରେ ଅଧିକ ସମୟ ଲାଗିପାରେ ଏବଂ ଆପ୍ଟି ଲଗାତାର ଚାଲିବା ଦ୍ୱାରା ସମଗ୍ର ଟାବଲେଟଟ୍ ମନ୍ଥର ହୋଇଯାଇପାରେ।"</string> @@ -1118,7 +1118,7 @@ <string name="no" msgid="5122037903299899715">"କ୍ୟାନ୍ସଲ୍ କରନ୍ତୁ"</string> <string name="dialog_alert_title" msgid="651856561974090712">"ଧ୍ୟାନଦିଅନ୍ତୁ"</string> <string name="loading" msgid="3138021523725055037">"ଲୋଡ୍ କରାଯାଉଛି…"</string> - <string name="capital_on" msgid="2770685323900821829">"ଅନ୍"</string> + <string name="capital_on" msgid="2770685323900821829">"ଚାଲୁ"</string> <string name="capital_off" msgid="7443704171014626777">"ଅଫ୍"</string> <string name="checked" msgid="9179896827054513119">"ଯାଞ୍ଚ ହୋଇଛି"</string> <string name="not_checked" msgid="7972320087569023342">"ଯାଞ୍ଚ ହୋଇନାହିଁ"</string> @@ -1170,7 +1170,7 @@ <string name="anr_application_process" msgid="4978772139461676184">"<xliff:g id="APPLICATION">%1$s</xliff:g> କାମ କରୁନାହିଁ"</string> <string name="anr_process" msgid="1664277165911816067">"<xliff:g id="PROCESS">%1$s</xliff:g> ପ୍ରୋସେସ୍ କାମ କରୁନାହିଁ"</string> <string name="force_close" msgid="9035203496368973803">"ଠିକ୍ ଅଛି"</string> - <string name="report" msgid="2149194372340349521">"ରିପୋର୍ଟ"</string> + <string name="report" msgid="2149194372340349521">"ରିପୋର୍ଟ କରନ୍ତୁ"</string> <string name="wait" msgid="7765985809494033348">"ଅପେକ୍ଷା କରନ୍ତୁ"</string> <string name="webpage_unresponsive" msgid="7850879412195273433">"ଏହି ପୃଷ୍ଠାଟି ଚାଲୁନାହିଁ।\n\nଆପଣ ଏହାକୁ ବନ୍ଦ କରିବେ କି?"</string> <string name="launch_warning_title" msgid="6725456009564953595">"ଆପ୍କୁ ରିଡାଇରେକ୍ଟ କରାଗଲା"</string> @@ -1253,7 +1253,7 @@ <string-array name="network_switch_type_name"> <item msgid="2255670471736226365">"ମୋବାଇଲ୍ ଡାଟା"</item> <item msgid="5520925862115353992">"ୱାଇ-ଫାଇ"</item> - <item msgid="1055487873974272842">"ବ୍ଲୁଟୂଥ୍"</item> + <item msgid="1055487873974272842">"ବ୍ଲୁଟୁଥ"</item> <item msgid="1616528372438698248">"ଇଥରନେଟ୍"</item> <item msgid="9177085807664964627">"VPN"</item> </string-array> @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB ଡିବଗିଙ୍ଗ ସଂଯୁକ୍ତ ହୋଇଛି"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USBର ଡିବଗିଙ୍ଗ ସୁବିଧାକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB ଡିବଗିଙ୍ଗକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱେୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସର ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"ୱାୟାରଲେସ୍ ଡିବଗିଂ ସଂଯୋଗ କରାଯାଇଛି"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ବନ୍ଦ କରିବା ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"ୱାୟାରଲେସ୍ ଡିବଗିଂକୁ ଅକ୍ଷମ କରିବା ପାଇଁ ଚୟନ କରନ୍ତୁ।"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ସକ୍ଷମ ଅଛି"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"ଟେଷ୍ଟ ହାର୍ନେସ୍ ମୋଡ୍ ଅକ୍ଷମ କରିବାକୁ ଏକ ଫ୍ୟାକ୍ଟରୀ ରିସେଟ୍ କରନ୍ତୁ।"</string> @@ -1770,7 +1770,7 @@ <string name="restr_pin_try_later" msgid="5897719962541636727">"ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ"</string> <string name="immersive_cling_title" msgid="2307034298721541791">"ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନରେ ଦେଖାଯାଉଛି"</string> <string name="immersive_cling_description" msgid="7092737175345204832">"ବାହାରିବା ପାଇଁ, ଉପରୁ ତଳକୁ ସ୍ୱାଇପ୍ କରନ୍ତୁ।"</string> - <string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଲି"</string> + <string name="immersive_cling_positive" msgid="7047498036346489883">"ବୁଝିଗଲି"</string> <string name="done_label" msgid="7283767013231718521">"ହୋଇଗଲା"</string> <string name="hour_picker_description" msgid="5153757582093524635">"ଘଣ୍ଟା ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string> <string name="minute_picker_description" msgid="9029797023621927294">"ମିନିଟ୍ସ ସର୍କୁଲାର୍ ସ୍ଲାଇଡର୍"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ବାର୍ତ୍ତାଳାପ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ଗୋଷ୍ଠୀ ବାର୍ତ୍ତାଳାପ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ବ୍ୟକ୍ତିଗତ ଭ୍ୟୁ"</string> diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml index 760b08b4a393..9a3ae250b157 100644 --- a/core/res/res/values-pa/strings.xml +++ b/core/res/res/values-pa/strings.xml @@ -290,7 +290,7 @@ <string name="foreground_service_tap_for_details" msgid="9078123626015586751">"ਬੈਟਰੀ ਅਤੇ ਡਾਟਾ ਵਰਤੋਂ ਸਬੰਧੀ ਵੇਰਵਿਆਂ ਲਈ ਟੈਪ ਕਰੋ"</string> <string name="foreground_service_multiple_separator" msgid="5002287361849863168">"<xliff:g id="LEFT_SIDE">%1$s</xliff:g>, <xliff:g id="RIGHT_SIDE">%2$s</xliff:g>"</string> <string name="safeMode" msgid="8974401416068943888">"ਸੁਰੱਖਿਅਤ ਮੋਡ"</string> - <string name="android_system_label" msgid="5974767339591067210">"Android System"</string> + <string name="android_system_label" msgid="5974767339591067210">"Android ਸਿਸਟਮ"</string> <string name="user_owner_label" msgid="8628726904184471211">"ਨਿੱਜੀ ਪ੍ਰੋਫਾਈਲ ਵਰਤੋ"</string> <string name="managed_profile_label" msgid="7316778766973512382">"ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਰਤੋ"</string> <string name="permgrouplab_contacts" msgid="4254143639307316920">"ਸੰਪਰਕ"</string> @@ -545,7 +545,7 @@ <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"ਅਧੂਰਾ ਫਿੰਗਰਪ੍ਰਿਟ ਮਿਲਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਦੀ ਪ੍ਰਕਿਰਿਆ ਨਹੀਂ ਕਰ ਸਕਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਗੰਦਾ ਹੈ। ਕਿਰਪਾ ਕਰਕੇ ਇਸਨੂੰ ਸਾਫ਼ ਕਰੋ ਅਤੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> - <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"ਉਂਗਲ ਨੂੰ ਬਹੁਤ ਤੇਜ਼ ਲੈ ਜਾਇਆ ਗਿਆ. ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ."</string> + <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"ਉਂਗਲ ਨੂੰ ਬਹੁਤ ਤੇਜ਼ ਲੈ ਜਾਇਆ ਗਿਆ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string name="fingerprint_acquired_too_slow" msgid="6683510291554497580">"ਉਂਗਲ ਕਾਫ਼ੀ ਹੌਲੀ ਮੂਵ ਹੋਈ। ਕਿਰਪਾ ਕਰਕੇ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string> <string-array name="fingerprint_acquired_vendor"> </string-array> @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"ਹਮੇਸ਼ਾ ਦਿਖਾਓ"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ Android OS ਦਾ ਇੱਕ ਗੈਰ-ਅਨੁਕੂਲ ਵਰਜਨ ਬਣਾਇਆ ਗਿਆ ਸੀ ਅਤੇ ਅਣਕਿਆਸੇ ਤੌਰ \'ਤੇ ਵਿਹਾਰ ਕਰ ਸਕਦੀ ਹੈ। ਐਪ ਦਾ ਇੱਕ ਅੱਪਡੇਟ ਕੀਤਾ ਹੋਇਆ ਵਰਜਨ ਉਪਲਬਧ ਹੋ ਸਕਦਾ ਹੈ।"</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"ਹਮੇਸਾਂ ਦਿਖਾਓ"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ"</string> <string name="smv_application" msgid="3775183542777792638">"ਐਪ <xliff:g id="APPLICATION">%1$s</xliff:g> (ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%2$s</xliff:g>) ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string> <string name="smv_process" msgid="1398801497130695446">"ਪ੍ਰਕਿਰਿਆ <xliff:g id="PROCESS">%1$s</xliff:g> ਨੇ ਆਪਣੀ ਖੁਦ-ਲਾਗੂ ਕੀਤੀ ਸਟ੍ਰਿਕਟਮੋਡ ਨੀਤੀ ਦੀ ਉਲੰਘਣਾ ਕੀਤੀ ਹੈ।"</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"ਫ਼ੋਨ ਅੱਪਡੇਟ ਹੋ ਰਿਹਾ ਹੈ…"</string> @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", ਸੁਰੱਖਿਅਤ"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"ਪੈਟਰਨ ਭੁੱਲ ਗਏ"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"ਗ਼ਲਤ ਪੈਟਰਨ"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"ਗਲਤ ਪੈਟਰਨ"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"ਗਲਤ ਪਾਸਵਰਡ"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"ਗਲਤ ਪਿੰਨ"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -1789,7 +1789,7 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Ok Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ\n\n"<annotation id="url">"ਹੋਰ ਜਾਣੋ"</annotation></string> <string name="battery_saver_description" msgid="7618492104632328184">"ਬੈਟਰੀ ਲਾਈਫ਼ ਵਧਾਉਣ ਲਈ, ਬੈਟਰੀ ਸੇਵਰ:\n ਗੂੜ੍ਹਾ ਥੀਮ ਚਾਲੂ ਕਰਦਾ ਹੈ\n ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ ਪ੍ਰਭਾਵਾਂ, ਅਤੇ \"Hey Google\" ਵਰਗੀਆਂ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬੰਦ ਕਰਦਾ ਹੈ ਜਾਂ ਉਹਨਾਂ \'ਤੇ ਪਾਬੰਦੀ ਲਗਾਉਂਦਾ ਹੈ"</string> <string name="data_saver_description" msgid="4995164271550590517">"ਡਾਟਾ ਵਰਤੋਂ ਘਟਾਉਣ ਵਿੱਚ ਮਦਦ ਲਈ, ਡਾਟਾ ਸੇਵਰ ਕੁਝ ਐਪਾਂ ਨੂੰ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਡਾਟਾ ਭੇਜਣ ਜਾਂ ਪ੍ਰਾਪਤ ਕਰਨ ਤੋਂ ਰੋਕਦਾ ਹੈ। ਤੁਹਾਡੇ ਵੱਲੋਂ ਵਰਤਮਾਨ ਤੌਰ \'ਤੇ ਵਰਤੀ ਜਾ ਰਹੀ ਐਪ ਡਾਟਾ \'ਤੇ ਪਹੁੰਚ ਕਰ ਸਕਦੀ ਹੈ, ਪਰ ਉਹ ਇੰਝ ਕਦੇ-ਕਦਾਈਂ ਕਰ ਸਕਦੀ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਸ ਦਾ ਮਤਲਬ ਇਹ ਹੋ ਸਕਦਾ ਹੈ ਕਿ ਚਿੱਤਰ ਤਦ ਤੱਕ ਨਹੀਂ ਪ੍ਰਦਰਸ਼ਿਤ ਕੀਤੇ ਜਾਂਦੇ, ਜਦੋਂ ਤੱਕ ਤੁਸੀਂ ਉਹਨਾਂ \'ਤੇ ਟੈਪ ਨਹੀਂ ਕਰਦੇ।"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"ਕੀ ਡਾਟਾ ਸੇਵਰ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string> <string name="app_blocked_message" msgid="542972921087873023">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਐਪ ਇਸ ਵੇਲੇ ਉਪਲਬਧ ਨਹੀਂ ਹੈ।"</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"ਇਹ ਐਪ Android ਦੇ ਕਿਸੇ ਵਧੇਰੇ ਪੁਰਾਣੇ ਵਰਜਨ ਲਈ ਬਣਾਈ ਗਈ ਸੀ ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ। ਅੱਪਡੇਟਾਂ ਲਈ ਜਾਂਚ ਕਰੋ ਜਾਂ ਵਿਕਾਸਕਾਰ ਨਾਲ ਸੰਪਰਕ ਕਰੋ।"</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਦੀ ਜਾਂਚ ਕਰੋ"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"ਅੱਪਡੇਟ ਲਈ ਜਾਂਚ ਕਰੋ"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"ਤੁਹਾਨੂੰ ਨਵੇਂ ਸੁਨੇਹੇ ਪ੍ਰਾਪਤ ਹੋਏ ਹਨ"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"ਦੇਖਣ ਲਈ SMS ਐਪ ਖੋਲ੍ਹੋ"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"ਕੁਝ ਪ੍ਰਕਾਰਜਾਤਮਕਤਾ ਸੀਮਤ ਹੋ ਸਕਦੀ ਹੈ"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"ਗੱਲਬਾਤ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"ਗੁਰੱਪ ਗੱਲਬਾਤ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ਵਿਅਕਤੀਗਤ ਦ੍ਰਿਸ਼"</string> diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml index aa48ea6fa333..b2c760668a7e 100644 --- a/core/res/res/values-pl/strings.xml +++ b/core/res/res/values-pl/strings.xml @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Rozmowa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Rozmowa grupowa"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Widok osobisty"</string> diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml index 3400cb1bb0c3..303a28f507ae 100644 --- a/core/res/res/values-pt-rBR/strings.xml +++ b/core/res/res/values-pt-rBR/strings.xml @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> @@ -2044,7 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string> - <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ de <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualização pessoal"</string> diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml index 6ad26b5476ca..f07f23511ce4 100644 --- a/core/res/res/values-pt-rPT/strings.xml +++ b/core/res/res/values-pt-rPT/strings.xml @@ -1183,7 +1183,7 @@ <string name="unsupported_display_size_show" msgid="980129850974919375">"Mostrar sempre"</string> <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"A aplicação <xliff:g id="APP_NAME">%1$s</xliff:g> foi concebida para uma versão incompatível do SO Android e pode ter um comportamento inesperado. Pode estar disponível uma versão atualizada da aplicação."</string> <string name="unsupported_compile_sdk_show" msgid="1601210057960312248">"Mostrar sempre"</string> - <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Verificar se existem atualizações"</string> + <string name="unsupported_compile_sdk_check_update" msgid="1103639989147664456">"Verificar atualizações"</string> <string name="smv_application" msgid="3775183542777792638">"A aplicação <xliff:g id="APPLICATION">%1$s</xliff:g> (processo <xliff:g id="PROCESS">%2$s</xliff:g>) violou a política StrictMode auto-imposta."</string> <string name="smv_process" msgid="1398801497130695446">"O processo <xliff:g id="PROCESS">%1$s</xliff:g> violou a política StrictMode auto-imposta."</string> <string name="android_upgrading_title" product="default" msgid="7279077384220829683">"O telemóvel está a atualizar…"</string> @@ -1628,7 +1628,7 @@ <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter premidas ambas as teclas de volume durante alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, uma funcionalidade de acessibilidade. Esta pode alterar a forma como o seu dispositivo funciona.\n\nPode alterar este atalho para outra funcionalidade em Definições > Acessibilidade."</string> <string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string> <string name="accessibility_shortcut_off" msgid="3651336255403648739">"Não ativar"</string> - <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Pretende permitir que o serviço <xliff:g id="SERVICE">%1$s</xliff:g> tenha controlo total sobre o seu dispositivo?"</string> + <string name="accessibility_enable_service_title" msgid="3931558336268541484">"Permitir que o serviço <xliff:g id="SERVICE">%1$s</xliff:g> tenha controlo total sobre o seu dispositivo?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"Se ativar o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, o dispositivo não utilizará o bloqueio de ecrã para otimizar a encriptação de dados."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"O controlo total é adequado para aplicações que ajudam nas necessidades de acessibilidade, mas não para a maioria das aplicações."</string> <string name="accessibility_service_screen_control_title" msgid="190017412626919776">"Ver e controlar o ecrã"</string> @@ -1870,8 +1870,8 @@ <string name="importance_from_user" msgid="2782756722448800447">"Definiu a importância destas notificações."</string> <string name="importance_from_person" msgid="4235804979664465383">"É importante devido às pessoas envolvidas."</string> <string name="notification_history_title_placeholder" msgid="7748630986182249599">"Notificação de app personalizada"</string> - <string name="user_creation_account_exists" msgid="2239146360099708035">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> - <string name="user_creation_adding" msgid="7305185499667958364">"Pretende permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> + <string name="user_creation_account_exists" msgid="2239146360099708035">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g> (já existe um utilizador com esta conta)?"</string> + <string name="user_creation_adding" msgid="7305185499667958364">"Permitir que a aplicação <xliff:g id="APP">%1$s</xliff:g> crie um novo utilizador com a conta <xliff:g id="ACCOUNT">%2$s</xliff:g>?"</string> <string name="language_selection_title" msgid="52674936078683285">"Adicionar um idioma"</string> <string name="country_selection_title" msgid="5221495687299014379">"Preferência de região"</string> <string name="search_language_hint" msgid="7004225294308793583">"Intr. nome do idioma"</string> @@ -1889,7 +1889,7 @@ <string name="app_blocked_title" msgid="7353262160455028160">"A app não está disponível"</string> <string name="app_blocked_message" msgid="542972921087873023">"De momento, a app <xliff:g id="APP_NAME">%1$s</xliff:g> não está disponível."</string> <string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Esta aplicação foi concebida para uma versão mais antiga do Android e pode não funcionar corretamente. Experimente verificar se existem atualizações ou contacte o programador."</string> - <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar se existem atualizações"</string> + <string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Verificar atualizações"</string> <string name="new_sms_notification_title" msgid="6528758221319927107">"Tem mensagens novas"</string> <string name="new_sms_notification_content" msgid="3197949934153460639">"Abra a aplicação de SMS para ver"</string> <string name="profile_encrypted_title" msgid="9001208667521266472">"Algumas funcionalidades limitadas"</string> diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml index 3400cb1bb0c3..303a28f507ae 100644 --- a/core/res/res/values-pt/strings.xml +++ b/core/res/res/values-pt/strings.xml @@ -1309,8 +1309,8 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Depuração USB conectada"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Toque para desativar a depuração USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selecione para desativar a depuração USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração sem fio conectada"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração sem fio"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Depuração por Wi-Fi conectada"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Toque para desativar a depuração por Wi-Fi"</string> <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selecione para desativar a depuração sem fio."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modo Arcabouço de testes ativado"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Realize uma redefinição para configuração original para desativar o modo Arcabouço de testes."</string> @@ -2044,7 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversa"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversa em grupo"</string> - <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> + <string name="unread_convo_overflow" msgid="920517615597353833">"+ de <xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualização pessoal"</string> diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml index 3dbc019fbb9e..1db09174c0eb 100644 --- a/core/res/res/values-ro/strings.xml +++ b/core/res/res/values-ro/strings.xml @@ -1329,9 +1329,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Remedierea erorilor prin USB este conectată"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Atingeți pentru a dezactiva remedierea erorilor prin USB."</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Selectați pentru a dezactiva remedierea erorilor prin USB."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Remedierea erorilor prin wireless este activă"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Atingeți pentru a dezactiva remedierea erorilor prin wireless"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selectați pentru a dezactiva remedierea erorilor prin wireless."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Remedierea erorilor wireless este activă"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Atingeți pentru a dezactiva remedierea erorilor wireless"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Selectați pentru a dezactiva remedierea erorilor wireless."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modul Set de testare este activat"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Reveniți la setările din fabrică pentru a dezactiva modul Set de testare."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Consola din serie este activată"</string> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversație"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversație de grup"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Afișarea conținutului personal"</string> diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml index 7f4f005e8efa..3a96385e0709 100644 --- a/core/res/res/values-ru/strings.xml +++ b/core/res/res/values-ru/strings.xml @@ -307,7 +307,7 @@ <string name="permgroupdesc_calendar" msgid="6762751063361489379">"доступ к календарю"</string> <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string> <string name="permgroupdesc_sms" msgid="5726462398070064542">"отправлять и просматривать SMS-сообщения"</string> - <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы и медиафайлы"</string> + <string name="permgrouplab_storage" msgid="1938416135375282333">"Файлы и медиаконтент"</string> <string name="permgroupdesc_storage" msgid="6351503740613026600">"доступ к фото, мультимедиа и файлам на вашем устройстве"</string> <string name="permgrouplab_microphone" msgid="2480597427667420076">"Микрофон"</string> <string name="permgroupdesc_microphone" msgid="1047786732792487722">"записывать аудио"</string> @@ -548,7 +548,7 @@ <string name="biometric_not_recognized" msgid="5106687642694635888">"Не распознано"</string> <string name="biometric_error_canceled" msgid="8266582404844179778">"Аутентификация отменена"</string> <string name="biometric_error_device_not_secured" msgid="3129845065043995924">"Укажите PIN-код, пароль или графический ключ"</string> - <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть пальца. Повторите попытку."</string> + <string name="fingerprint_acquired_partial" msgid="8532380671091299342">"Отсканирована только часть отпечатка. Повторите попытку."</string> <string name="fingerprint_acquired_insufficient" msgid="2545149524031515411">"Не удалось распознать отпечаток. Повторите попытку."</string> <string name="fingerprint_acquired_imager_dirty" msgid="4694800187151533990">"Очистите сканер и повторите попытку."</string> <string name="fingerprint_acquired_too_fast" msgid="5151661932298844352">"Вы слишком быстро убрали палец. Повторите попытку."</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групповой чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Просмотр личных данных"</string> diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml index a2e556dd15a6..a131b181f516 100644 --- a/core/res/res/values-si/strings.xml +++ b/core/res/res/values-si/strings.xml @@ -2046,8 +2046,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"සංවාදය"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"සමූහ සංවාදය"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"පෞද්ගලික දසුන"</string> diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml index 8039c1afa014..aec983c0d653 100644 --- a/core/res/res/values-sk/strings.xml +++ b/core/res/res/values-sk/strings.xml @@ -533,7 +533,7 @@ <string name="permlab_manageFingerprint" msgid="7432667156322821178">"spravovať hardvér na snímanie odtlačkov prstov"</string> <string name="permdesc_manageFingerprint" msgid="2025616816437339865">"Umožňuje aplikácii zavolať metódy, ktoré pridávajú a odstraňujú vzory odtlačkov prstov."</string> <string name="permlab_useFingerprint" msgid="1001421069766751922">"použiť hardvér na snímanie odtlačkov prstov"</string> - <string name="permdesc_useFingerprint" msgid="412463055059323742">"Umožňuje aplikácii používať na overenie totožnosti hardvér na snímanie odtlačkov prstov."</string> + <string name="permdesc_useFingerprint" msgid="412463055059323742">"Umožňuje aplikácii používať na overenie hardvér na odtlačky prstov"</string> <string name="permlab_audioWrite" msgid="8501705294265669405">"upravovať hudobnú zbierku"</string> <string name="permdesc_audioWrite" msgid="8057399517013412431">"Umožňuje aplikácii upravovať hudobnú zbierku."</string> <string name="permlab_videoWrite" msgid="5940738769586451318">"upravovať zbierku videí"</string> @@ -1835,8 +1835,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hej Google“."</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hey Google“.\n\n"<annotation id="url">"Ďalšie informácie"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"Šetrič batérie predlžuje výdrž batérie:\n·zapnutím tmavého motívu;\n·vypnutím alebo obmedzením aktivity na pozadí, niektorých vizuálnych efektov a ďalších funkcií, ako napríklad „Hey Google“."</string> <string name="data_saver_description" msgid="4995164271550590517">"S cieľom znížiť spotrebu dát bráni šetrič dát niektorým aplikáciám odosielať alebo prijímať dáta na pozadí. Aplikácia, ktorú práve používate, môže využívať dáta, ale možno to bude robiť menej často. Znamená to napríklad, že sa nezobrazia obrázky, kým na ne neklepnete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Chcete zapnúť šetrič dát?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Zapnúť"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konverzácia"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinová konverzácia"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Osobné zobrazenie"</string> diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml index 2d742ef21e4b..5aa0e02e860b 100644 --- a/core/res/res/values-sl/strings.xml +++ b/core/res/res/values-sl/strings.xml @@ -566,7 +566,7 @@ <string name="fingerprint_error_lockout" msgid="7853461265604738671">"Preveč poskusov. Poskusite znova pozneje."</string> <string name="fingerprint_error_lockout_permanent" msgid="3895478283943513746">"Preveč poskusov. Tipalo prstnih odtisov je onemogočeno."</string> <string name="fingerprint_error_unable_to_process" msgid="1148553603490048742">"Poskusite znova."</string> - <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni včlanjenih prstnih odtisov."</string> + <string name="fingerprint_error_no_fingerprints" msgid="8671811719699072411">"Ni registriranih prstnih odtisov."</string> <string name="fingerprint_error_hw_not_present" msgid="578914350967423382">"Ta naprava nima tipala prstnih odtisov."</string> <string name="fingerprint_error_security_update_required" msgid="7750187320640856433">"Tipalo je začasno onemogočeno."</string> <string name="fingerprint_name_template" msgid="8941662088160289778">"Prst <xliff:g id="FINGERID">%d</xliff:g>"</string> @@ -578,8 +578,8 @@ <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"uporaba strojne opreme za odklepanje z obrazom"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"Aplikaciji omogoča uporabo strojne opreme za odklepanje z obrazom za preverj. pristnosti"</string> <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Odklepanje z obrazom"</string> - <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova prijavite obraz"</string> - <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za izboljšanje prepoznavanja znova prijavite svoj obraz"</string> + <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"Znova registrirajte obraz"</string> + <string name="face_recalibrate_notification_content" msgid="892757485125249962">"Za izboljšanje prepoznavanja znova registrirajte svoj obraz"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"Točnih podatkov o obrazu ni bilo mogoče zajeti. Poskusite znova."</string> <string name="face_acquired_too_bright" msgid="8070756048978079164">"Presvetlo. Poskusite z blažjo osvetlitvijo."</string> <string name="face_acquired_too_dark" msgid="252573548464426546">"Pretemno. Poskusite z močnejšo osvetlitvijo."</string> @@ -592,7 +592,7 @@ <string name="face_acquired_poor_gaze" msgid="4427153558773628020">"Glejte bolj naravnost v napravo."</string> <string name="face_acquired_not_detected" msgid="2945945257956443257">"Obraz nastavite naravnost pred telefon."</string> <string name="face_acquired_too_much_motion" msgid="8199691445085189528">"Preveč se premikate. Držite telefon pri miru."</string> - <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova prijavite svoj obraz."</string> + <string name="face_acquired_recalibrate" msgid="8724013080976469746">"Znova registrirajte svoj obraz."</string> <string name="face_acquired_too_different" msgid="4699657338753282542">"Obraza ni več mogoče prepoznati. Poskusite znova."</string> <string name="face_acquired_too_similar" msgid="7684650785108399370">"Preveč podobno, spremenite položaj."</string> <string name="face_acquired_pan_too_extreme" msgid="7822191262299152527">"Glejte malce bolj naravnost."</string> @@ -1560,7 +1560,7 @@ <string name="data_usage_limit_snoozed_body" msgid="545146591766765678">"Nastavljeno omejitev ste presegli za <xliff:g id="SIZE">%s</xliff:g>"</string> <string name="data_usage_restricted_title" msgid="126711424380051268">"Podatki v ozadju so omejeni"</string> <string name="data_usage_restricted_body" msgid="5338694433686077733">"Dotaknite se za odstr. omejitve."</string> - <string name="data_usage_rapid_title" msgid="2950192123248740375">"Visoka poraba mobilnih podatkov"</string> + <string name="data_usage_rapid_title" msgid="2950192123248740375">"Velik prenos mobilnih podatkov"</string> <string name="data_usage_rapid_body" msgid="3886676853263693432">"Vaše aplikacije so porabile več podatkov kot običajno"</string> <string name="data_usage_rapid_app_body" msgid="5425779218506513861">"Aplikacija <xliff:g id="APP">%s</xliff:g> je porabila več podatkov kot običajno"</string> <string name="ssl_certificate" msgid="5690020361307261997">"Varnostno potrdilo"</string> @@ -1837,7 +1837,7 @@ <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string> <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«.\n\n"<annotation id="url">"Več o tem"</annotation></string> <string name="battery_saver_description" msgid="7618492104632328184">"Funkcija varčevanja z energijo baterije tako podaljša čas delovanja baterije:\n·Vklopi temno temo,\n·izklopi ali omeji izvajanje dejavnosti v ozadju, nekaterih vizualnih učinkov in drugih funkcij, kot je »Hey Google«."</string> - <string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov varčevanje s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> + <string name="data_saver_description" msgid="4995164271550590517">"Zaradi zmanjševanja prenesene količine podatkov funkcija varčevanja s podatki nekaterim aplikacijam preprečuje, da bi v ozadju pošiljale ali prejemale podatke. Aplikacija, ki jo trenutno uporabljate, lahko prenaša podatke, vendar to morda počne manj pogosto. To na primer pomeni, da se slike ne prikažejo, dokler se jih ne dotaknete."</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"Vklop varčevanja s podatki?"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"Vklop"</string> <plurals name="zen_mode_duration_minutes_summary" formatted="false" msgid="2877101784123058273"> @@ -2063,7 +2063,7 @@ <string name="dynamic_mode_notification_channel_name" msgid="2986926422100223328">"Rutinsko informativno obvestilo o načinu delovanja"</string> <string name="dynamic_mode_notification_title" msgid="9205715501274608016">"Akumulator se bo morda izpraznil, preden ga običajno priključite na polnjenje"</string> <string name="dynamic_mode_notification_summary" msgid="4141614604437372157">"Vklopilo se je varčevanje z energijo akumulatorja za podaljšanje časa delovanja akumulatorja"</string> - <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo akumulatorja"</string> + <string name="battery_saver_notification_channel_name" msgid="3918243458067916913">"Varčevanje z energijo baterije"</string> <string name="battery_saver_off_notification_title" msgid="7637255960468032515">"Varčevanje z energijo baterije je izklopljeno"</string> <string name="battery_saver_charged_notification_summary" product="default" msgid="5544457317418624367">"Baterija v telefonu je dovolj napolnjena. Funkcije niso več omejene."</string> <string name="battery_saver_charged_notification_summary" product="tablet" msgid="4426317048139996888">"Baterija v tabličnem računalniku je dovolj napolnjena. Funkcije niso več omejene."</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pogovor"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Skupinski pogovor"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Pogled osebnega profila"</string> diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml index 460287d64fac..5e7351a38820 100644 --- a/core/res/res/values-sq/strings.xml +++ b/core/res/res/values-sq/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Korrigjuesi i USB-së është i lidhur"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Trokit për të çaktivizuar korrigjimin e USB-së"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Përzgjidhe për të çaktivizuar korrigjimin e gabimeve të USB-së"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi me lidhjen pa tel është lidhur"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin me lidhjen pa tel"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Zgjidhe për të çaktivizuar korrigjimin me lidhjen pa tel"</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Korrigjimi përmes Wi-Fi është lidhur"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Trokit për të çaktivizuar korrigjimin përmes Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Zgjidh për të çaktivizuar korrigjimin përmes Wi-Fi"</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Modaliteti i lidhjes së testimit është aktivizuar"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Kryej një rivendosje në cilësimet e fabrikës për të çaktivizuar \"Modalitetin e lidhjes së testimit\"."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Paneli komandues i serisë është aktivizuar"</string> diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml index d72c209714ba..995e949f72b3 100644 --- a/core/res/res/values-sr/strings.xml +++ b/core/res/res/values-sr/strings.xml @@ -701,7 +701,7 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"Захтева да сачувани подаци апликације буду шифровани."</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"Онемогућавање камера"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"Спречите коришћење свих камера уређаја."</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онемогућава функције закључавања екрана"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"Онемогућавање функција закљ. екрана"</string> <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"Спречава коришћење неких функција закључавања екрана."</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"Кућа"</item> @@ -2078,8 +2078,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Конверзација"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Групна конверзација"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Лични приказ"</string> diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml index 9b7318bedfe0..54eec00de8a1 100644 --- a/core/res/res/values-sv/strings.xml +++ b/core/res/res/values-sv/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Konversation"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Gruppkonversation"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personlig vy"</string> diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml index f6a831aa7275..7e9a1ea541c0 100644 --- a/core/res/res/values-sw/strings.xml +++ b/core/res/res/values-sw/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Mazungumzo"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Mazungumzo ya Kikundi"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Mwonekano wa binafsi"</string> diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml index 43eca0e927fb..71352403b8ed 100644 --- a/core/res/res/values-ta/strings.xml +++ b/core/res/res/values-ta/strings.xml @@ -237,10 +237,8 @@ <string name="global_actions" product="default" msgid="6410072189971495460">"தொலைபேசி விருப்பங்கள்"</string> <string name="global_action_lock" msgid="6949357274257655383">"திரைப் பூட்டு"</string> <string name="global_action_power_off" msgid="4404936470711393203">"பவர் ஆஃப்"</string> - <!-- no translation found for global_action_power_options (1185286119330160073) --> - <skip /> - <!-- no translation found for global_action_restart (4678451019561687074) --> - <skip /> + <string name="global_action_power_options" msgid="1185286119330160073">"பவர் பட்டன்"</string> + <string name="global_action_restart" msgid="4678451019561687074">"மீண்டும் தொடங்கு"</string> <string name="global_action_emergency" msgid="1387617624177105088">"அவசர அழைப்பு"</string> <string name="global_action_bug_report" msgid="5127867163044170003">"பிழை அறிக்கை"</string> <string name="global_action_logout" msgid="6093581310002476511">"அமர்வை முடிக்கிறது"</string> @@ -440,8 +438,7 @@ <string name="permlab_camera" msgid="6320282492904119413">"படங்கள் மற்றும் வீடியோக்களை எடுத்தல்"</string> <string name="permdesc_camera" msgid="1354600178048761499">"இந்த ஆப்ஸ் எப்போது வேண்டுமானாலும் கேமராவைப் பயன்படுத்தி படங்களை எடுக்கலாம், வீடியோக்களை ரெக்கார்டு செய்யலாம்."</string> <string name="permlab_systemCamera" msgid="3642917457796210580">"படங்களையும் வீடியோக்களையும் எடுப்பதற்கு சிஸ்டம் கேமராக்களை அணுக ஆப்ஸையோ சேவையையோ அனுமதி"</string> - <!-- no translation found for permdesc_systemCamera (5938360914419175986) --> - <skip /> + <string name="permdesc_systemCamera" msgid="5938360914419175986">"இந்த முன்னுரிமை பெற்ற அல்லது சிஸ்டம் ஆப்ஸால் சிஸ்டம் கேமராவைப் பயன்படுத்தி எப்போது வேண்டுமானாலும் படங்களை எடுக்கவோ வீடியோக்களை ரெக்கார்டு செய்யவோ முடியும். android.permission.CAMERA அனுமதியும் ஆப்ஸிற்குத் தேவை"</string> <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"கேமரா சாதனங்கள் திறக்கப்படும்போதோ மூடப்படும்போதோ அது குறித்த கால்பேக்குகளைப் பெற ஒரு ஆப்ஸையோ சேவையையோ அனுமதிக்கவும்."</string> <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"எந்தக் கேமரா சாதனமும் (எந்த ஆப்ஸாலும்) திறக்கப்படும்போதோ மூடப்படும்போதோ இந்த ஆப்ஸால் கால்பேக்குகளைப் பெற முடியும்."</string> <string name="permlab_vibrate" msgid="8596800035791962017">"அதிர்வைக் கட்டுப்படுத்துதல்"</string> @@ -1312,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB பிழைதிருத்தம் இணைக்கப்பட்டது"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB பிழைதிருத்தத்தை முடக்க, தேர்ந்தெடுக்கவும்."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"வயர்லெஸ் பிழைதிருத்தம் இணைக்கப்பட்டது"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"வயர்லெஸ் பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"வயர்லெஸ் பிழைதிருத்தத்தை முடக்க தேர்ந்தெடுக்கவும்."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"வைஃபை பிழைதிருத்தம் இணைக்கப்பட்டது"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"வைஃபை பிழைதிருத்தத்தை ஆஃப் செய்ய தட்டவும்"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"வைஃபை பிழைதிருத்தத்தை முடக்க தேர்ந்தெடுக்கவும்."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"\'தன்னியக்க சோதனைப்\' பயன்முறை இயக்கப்பட்டது"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"’தன்னியக்க சோதனைப்\' பயன்முறையை முடக்க ஆரம்பநிலைக்கு மீட்டமைக்கவும்."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"சீரியல் கன்சோல் இயக்கப்பட்டது"</string> @@ -1354,8 +1351,7 @@ <string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"ஆதரிக்கப்படாத <xliff:g id="NAME">%s</xliff:g>"</string> <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"சாதனம் இந்த <xliff:g id="NAME">%s</xliff:g>ஐ ஆதரிக்கவில்லை. ஆதரிக்கப்படும் வடிவமைப்பில் அமைக்க, தட்டவும்."</string> <string name="ext_media_unsupported_notification_message" product="tv" msgid="7744945987775645685">"சாதனம் இந்த <xliff:g id="NAME">%s</xliff:g>ஐ ஆதரிக்கவில்லை. ஆதரிக்கப்படும் வடிவமைப்பில் அமைக்க, தேர்ந்தெடுக்கவும்."</string> - <!-- no translation found for ext_media_unsupported_notification_message (7657357085538772913) --> - <skip /> + <string name="ext_media_unsupported_notification_message" product="automotive" msgid="7657357085538772913">"இந்தச் சாதனத்தில் இந்த <xliff:g id="NAME">%s</xliff:g> ஆதரிக்கப்படவில்லை."</string> <string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> அகற்றப்பட்டது"</string> <string name="ext_media_badremoval_notification_message" msgid="1986514704499809244">"உள்ளடக்கத்தை இழக்காமலிருக்க, அகற்றும் முன்பாக மீடியாவை வெளியேற்றவும்"</string> <string name="ext_media_nomedia_notification_title" msgid="742671636376975890">"<xliff:g id="NAME">%s</xliff:g> அகற்றப்பட்டது"</string> @@ -1623,24 +1619,15 @@ <string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"பரிந்துரைத்த அளவை விட ஒலியை அதிகரிக்கவா?\n\nநீண்ட நேரத்திற்கு அதிகளவில் ஒலி கேட்பது கேட்கும் திறனைப் பாதிக்கலாம்."</string> <string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"அணுகல்தன்மை ஷார்ட்கட்டைப் பயன்படுத்தவா?"</string> <string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string> - <!-- no translation found for accessibility_shortcut_multiple_service_warning_title (8417489297036013065) --> - <skip /> - <!-- no translation found for accessibility_shortcut_multiple_service_warning (3740723309483706911) --> - <skip /> - <!-- no translation found for accessibility_shortcut_multiple_service_list (6935581470716541531) --> - <skip /> - <!-- no translation found for accessibility_shortcut_talkback_warning_title (3410100187167382427) --> - <skip /> - <!-- no translation found for accessibility_shortcut_talkback_warning (8412954203626349109) --> - <skip /> - <!-- no translation found for accessibility_shortcut_single_service_warning_title (2819109500943271385) --> - <skip /> - <!-- no translation found for accessibility_shortcut_single_service_warning (6363127705112844257) --> - <skip /> - <!-- no translation found for accessibility_shortcut_on (5463618449556111344) --> - <skip /> - <!-- no translation found for accessibility_shortcut_off (3651336255403648739) --> - <skip /> + <string name="accessibility_shortcut_multiple_service_warning_title" msgid="8417489297036013065">"அணுகல்தன்மை அம்சங்களை ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருந்தால் அணுகல்தன்மை அம்சங்கள் ஆன் செய்யப்படும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nதற்போதைய அம்சங்கள்:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nதேர்ந்தெடுத்த அம்சங்களை அமைப்புகள் > அணுகல்தன்மைக்குச் சென்று உங்களால் மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string> + <string name="accessibility_shortcut_talkback_warning_title" msgid="3410100187167382427">"TalkBackகை ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_talkback_warning" msgid="8412954203626349109">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் கண் பார்வையற்ற அல்லது பார்வைக் குறைபாடு உள்ளவர்களுக்கு உதவும் TalkBack எனும் ஸ்கிரீன் ரீடர் ஆன் ஆகும். உங்கள் சாதனம் வேலை செய்யும் முறையை TalkBack முழுமையாக மாற்றும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_single_service_warning_title" msgid="2819109500943271385">"<xliff:g id="SERVICE">%1$s</xliff:g> ஐ ஆன் செய்யவா?"</string> + <string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் அணுகல்தன்மை அம்சமான <xliff:g id="SERVICE">%1$s</xliff:g> ஆன் ஆகும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string> + <string name="accessibility_shortcut_on" msgid="5463618449556111344">"ஆன் செய்"</string> + <string name="accessibility_shortcut_off" msgid="3651336255403648739">"ஆன் செய்யாதே"</string> <string name="accessibility_enable_service_title" msgid="3931558336268541484">"உங்கள் சாதனத்தை முழுமையாகக் கட்டுப்படுத்த <xliff:g id="SERVICE">%1$s</xliff:g> சேவையை அனுமதிக்க வேண்டுமா?"</string> <string name="accessibility_enable_service_encryption_warning" msgid="8603532708618236909">"<xliff:g id="SERVICE">%1$s</xliff:g> சேவையை ஆன் செய்தால் தரவு என்க்ரிப்ஷனை மேம்படுத்த சாதனம் திரைப் பூட்டைப் பயன்படுத்தாது."</string> <string name="accessibility_service_warning_description" msgid="291674995220940133">"உங்களுக்கு உதவக்கூடிய ஆப்ஸுக்குக் தேவையான அணுகல்தன்மையை அளித்து முழுக் கட்டுப்பாட்டையும் அளிக்கலாம், ஆனால் பெரும்பாலான ஆப்ஸுக்கு இது பொருந்தாது."</string> @@ -1651,10 +1638,8 @@ <string name="accessibility_dialog_button_allow" msgid="2092558122987144530">"அனுமதி"</string> <string name="accessibility_dialog_button_deny" msgid="4129575637812472671">"நிராகரி"</string> <string name="accessibility_select_shortcut_menu_title" msgid="6002726538854613272">"ஒரு அம்சத்தைப் பயன்படுத்த அதைத் தட்டவும்:"</string> - <!-- no translation found for accessibility_edit_shortcut_menu_button_title (239446795930436325) --> - <skip /> - <!-- no translation found for accessibility_edit_shortcut_menu_volume_title (1077294237378645981) --> - <skip /> + <string name="accessibility_edit_shortcut_menu_button_title" msgid="239446795930436325">"அணுகல்தன்மை பட்டன் மூலம் பயன்படுத்த விரும்பும் அம்சங்களைத் தேர்வுசெய்யுங்கள்"</string> + <string name="accessibility_edit_shortcut_menu_volume_title" msgid="1077294237378645981">"ஒலியளவு விசை ஷார்ட்கட் மூலம் பயன்படுத்த விரும்பும் அம்சங்களைத் தேர்வுசெய்யுங்கள்"</string> <string name="accessibility_uncheck_legacy_item_warning" msgid="8047830891064817447">"<xliff:g id="SERVICE_NAME">%s</xliff:g> ஆஃப் செய்யப்பட்டுள்ளது"</string> <string name="edit_accessibility_shortcut_menu_button" msgid="8885752738733772935">"ஷார்ட்கட்களை மாற்று"</string> <string name="done_accessibility_shortcut_menu_button" msgid="3668407723770815708">"முடிந்தது"</string> @@ -1662,23 +1647,15 @@ <string name="leave_accessibility_shortcut_on" msgid="6543362062336990814">"ஷார்ட்கட்டைப் பயன்படுத்து"</string> <string name="color_inversion_feature_name" msgid="326050048927789012">"வண்ணத்தை நேர் எதிராக மாற்றுதல்"</string> <string name="color_correction_feature_name" msgid="3655077237805422597">"வண்ணத் திருத்தம்"</string> - <!-- no translation found for accessibility_shortcut_enabling_service (5473495203759847687) --> - <skip /> - <!-- no translation found for accessibility_shortcut_disabling_service (8675244165062700619) --> - <skip /> + <string name="accessibility_shortcut_enabling_service" msgid="5473495203759847687">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆன் செய்யப்பட்டது."</string> + <string name="accessibility_shortcut_disabling_service" msgid="8675244165062700619">"ஒலியளவுக்கான விசைகளைப் பிடித்திருந்தீர்கள். <xliff:g id="SERVICE_NAME">%1$s</xliff:g> ஆஃப் செய்யப்பட்டது."</string> <string name="accessibility_shortcut_spoken_feedback" msgid="4228997042855695090">"<xliff:g id="SERVICE_NAME">%1$s</xliff:g>ஐப் பயன்படுத்த 3 விநாடிகளுக்கு இரண்டு ஒலியளவு பட்டன்களையும் அழுத்திப் பிடிக்கவும்"</string> - <!-- no translation found for accessibility_button_prompt_text (8343213623338605305) --> - <skip /> - <!-- no translation found for accessibility_gesture_prompt_text (8742535972130563952) --> - <skip /> - <!-- no translation found for accessibility_gesture_3finger_prompt_text (5211827854510660203) --> - <skip /> - <!-- no translation found for accessibility_button_instructional_text (8853928358872550500) --> - <skip /> - <!-- no translation found for accessibility_gesture_instructional_text (9196230728837090497) --> - <skip /> - <!-- no translation found for accessibility_gesture_3finger_instructional_text (3425123684990193765) --> - <skip /> + <string name="accessibility_button_prompt_text" msgid="8343213623338605305">"அணுகல்தன்மை பட்டனைத் தட்டுவதன் மூலம் பயன்படுத்த விரும்பும் அம்சத்தைத் தேர்ந்தெடுக்கவும்:"</string> + <string name="accessibility_gesture_prompt_text" msgid="8742535972130563952">"அணுகல்தன்மை சைகைக்கான அம்சத்தைத் தேர்வுசெய்யவும் (இரண்டு விரல்களால் திரையின் கீழிருந்து மேல் நோக்கி ஸ்வைப் செய்யவும்):"</string> + <string name="accessibility_gesture_3finger_prompt_text" msgid="5211827854510660203">"அணுகல்தன்மை சைகைக்கான அம்சத்தைத் தேர்வுசெய்யவும் (மூன்று விரல்களால் திரையின் கீழிருந்து மேல் நோக்கி ஸ்வைப் செய்யவும்):"</string> + <string name="accessibility_button_instructional_text" msgid="8853928358872550500">"அம்சங்களுக்கு இடையே மாற அணுகல்தன்மை பட்டனைத் தொட்டுப் பிடித்திருக்கவும்."</string> + <string name="accessibility_gesture_instructional_text" msgid="9196230728837090497">"அம்சங்களுக்கு இடையே மாற இரண்டு விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string> + <string name="accessibility_gesture_3finger_instructional_text" msgid="3425123684990193765">"அம்சங்களுக்கு இடையே மாற மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடித்திருக்கவும்."</string> <string name="accessibility_magnification_chooser_text" msgid="1502075582164931596">"பெரிதாக்கல்"</string> <string name="user_switched" msgid="7249833311585228097">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string> <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>க்கு மாறுகிறது…"</string> @@ -2049,8 +2026,7 @@ <item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ஃபைல்கள்</item> <item quantity="one"><xliff:g id="FILE_NAME_0">%s</xliff:g> + <xliff:g id="COUNT_1">%d</xliff:g> ஃபைல்</item> </plurals> - <!-- no translation found for chooser_no_direct_share_targets (1511722103987329028) --> - <skip /> + <string name="chooser_no_direct_share_targets" msgid="1511722103987329028">"பகிர்வதற்கு எவரும் பரிந்துரைக்கப்படவில்லை"</string> <string name="chooser_all_apps_button_label" msgid="3230427756238666328">"ஆப்ஸ் பட்டியல்"</string> <string name="usb_device_resolve_prompt_warn" msgid="325871329788064199">"இந்த ஆப்ஸிற்கு ரெக்கார்டு செய்வதற்கான அனுமதி வழங்கப்படவில்லை, எனினும் இந்த USB சாதனம் மூலம் ஆடியோவைப் பதிவுசெய்ய முடியும்."</string> <string name="accessibility_system_action_home_label" msgid="3234748160850301870">"முகப்பு"</string> @@ -2088,220 +2064,112 @@ <string name="resolver_no_work_apps_available_resolve" msgid="1244844292366099399">"இந்த உள்ளடக்கத்தை எந்தவொரு பணி ஆப்ஸாலும் திறக்க முடியாது"</string> <string name="resolver_no_personal_apps_available_share" msgid="5639102815174748732">"இந்த உள்ளடக்கத்தை எந்தவொரு தனிப்பட்ட ஆப்ஸும் ஆதரிக்காது"</string> <string name="resolver_no_personal_apps_available_resolve" msgid="5120671970531446978">"இந்த உள்ளடக்கத்தை எந்தவொரு தனிப்பட்ட ஆப்ஸாலும் திறக்க முடியாது"</string> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_ENTRY (8050953231914637819) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY (7164399703751688214) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_ENTRY (4447629474818217364) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ENTRY (973059024670737358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_ENTRY (4487435301206073787) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_ENTRY (768060297218652809) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ENTRY (7129527319490548930) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_ENTRY (2876126640607573252) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ENTRY (8952595089930109282) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_ENTRY (3013902515773728996) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_ENTRY (2974411408893410289) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_ENTRY (687618528751880721) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_ENTRY (6810596579655575381) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_ENTRY (2715929642540980259) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ENTRY (8557791623303951590) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_ENTRY (7382468767274580323) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_ENTRY (6730880791104286987) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_ENTRY (6432126539782267026) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_ENTRY (1730510161529488920) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ENTRY (3369885925003346830) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_ENTRY (9129139686191167829) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_ENTRY (2869929685874615358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_ENTRY (1238663472392741771) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_ENTRY (3988705848553894358) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_ENTRY (6186770686690993200) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_ENTRY (7043865376145617024) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_ENTRY (6144227308185112176) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_IN_PROGRESS (4233355366318061180) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_IN_PROGRESS (6742563947637715645) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_IN_PROGRESS (2033399698172403560) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_IN_PROGRESS (4795977251920732254) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_IN_PROGRESS (1090425878157254446) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_IN_PROGRESS (6476898876518094438) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_IN_PROGRESS (6006806734293747731) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_IN_PROGRESS (6546680489620881893) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_IN_PROGRESS (3506845511000727015) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_IN_PROGRESS (6709169861932992750) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_IN_PROGRESS (4013870911606478520) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_IN_PROGRESS (9032651188219523434) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_IN_PROGRESS (6584576506344491207) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_IN_PROGRESS (830981927724888114) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_IN_PROGRESS (7851790973098894802) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_IN_PROGRESS (1149560739586960121) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_IN_PROGRESS (5708964693522116025) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_IN_PROGRESS (7288103122966483455) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_IN_PROGRESS (4036752174056147753) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_IN_PROGRESS (5089536274515338566) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_IN_PROGRESS (6737197986936251958) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_IN_PROGRESS (5658767775619998623) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_IN_PROGRESS (665978313257653727) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_IN_PROGRESS (3857142652251836850) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_IN_PROGRESS (2695664012344346788) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_IN_PROGRESS (2695678959963807782) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_IN_PROGRESS (1230605365926493599) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_ERROR (1924844017037151535) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR (3372797822292089708) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR (1878443146720411381) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_ERROR (7664778312218023192) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_ERROR (2472944311643350302) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_ERROR (828089694480999120) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_ERROR (17619001007092511) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_ERROR (807214229604353614) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_ERROR (8644184447744175747) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR (3801002648649640407) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_ERROR (707397021218680753) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR (894358680773257820) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR (352466878146726991) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR (7353389721907138671) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR (2655263155490857920) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_ERROR (6903740900892931310) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR (5165901670447518687) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR (2856763216589267623) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR (817542684437829139) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR (5178635064113393143) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR (5391587926974531008) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR (4895494864493315868) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_ERROR (9017576601595353649) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR (1116993930995545742) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_ERROR (7559167306794441462) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_ERROR (2782926139511136588) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_ERROR (1890493954453456758) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUCCESS (4886243367747126325) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_SUCCESS (4053809277733513987) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_SUCCESS (8249342930499801740) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_SUCCESS (2339794542560381270) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_SUCCESS (6975608174152828954) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_SUCCESS (2846699261330463192) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_SUCCESS (5335414726057102801) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_SUCCESS (8868100318474971969) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS (6020936629725666932) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS (6944873647584595489) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_SUCCESS (2526483514124121988) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS (7662200333621664621) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS (2861223407953766632) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS (5345648571175243272) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS (3725278343103422466) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS (6998502547560297983) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS (8555433771162560361) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS (3555767296933606232) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS (6778051818199974237) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS (4080108758498911429) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS (7873675303000794343) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS (1763198215069819523) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SPN_SUCCESS (2053891977727320532) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS (8146602361895007345) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_ICCID_SUCCESS (8058678548991999545) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_IMPI_SUCCESS (2545608067978550571) --> - <skip /> - <!-- no translation found for PERSOSUBSTATE_SIM_NS_SP_SUCCESS (4352382949744625007) --> - <skip /> + <string name="PERSOSUBSTATE_SIM_NETWORK_ENTRY" msgid="8050953231914637819">"சிம் நெட்வொர்க் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ENTRY" msgid="7164399703751688214">"சிம் நெட்வொர்க் சப்செட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_ENTRY" msgid="4447629474818217364">"கார்ப்பரேட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ENTRY" msgid="973059024670737358">"சிம் சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SIM_ENTRY" msgid="4487435301206073787">"சிம் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ENTRY" msgid="768060297218652809">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ENTRY" msgid="7129527319490548930">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ENTRY" msgid="2876126640607573252">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ENTRY" msgid="8952595089930109282">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ENTRY" msgid="3013902515773728996">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_ENTRY" msgid="2974411408893410289">"RUIM network1 அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_ENTRY" msgid="687618528751880721">"RUIM network2 அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_ENTRY" msgid="6810596579655575381">"hrpd அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_ENTRY" msgid="2715929642540980259">"RUIM கார்ப்பரேட் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ENTRY" msgid="8557791623303951590">"RUIM சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_ENTRY" msgid="7382468767274580323">"RUIM அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ENTRY" msgid="6730880791104286987">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ENTRY" msgid="6432126539782267026">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ENTRY" msgid="1730510161529488920">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ENTRY" msgid="3369885925003346830">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ENTRY" msgid="9129139686191167829">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ENTRY" msgid="2869929685874615358">"PUKவை உள்ளிடுக"</string> + <string name="PERSOSUBSTATE_SIM_SPN_ENTRY" msgid="1238663472392741771">"SPN அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ENTRY" msgid="3988705848553894358">"SP Equivalent Home PLMN அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_ICCID_ENTRY" msgid="6186770686690993200">"ICCID அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_IMPI_ENTRY" msgid="7043865376145617024">"IMPI அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_ENTRY" msgid="6144227308185112176">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் பின்"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_IN_PROGRESS" msgid="4233355366318061180">"சிம் நெட்வொர்க் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_IN_PROGRESS" msgid="6742563947637715645">"சிம் நெட்வொர்க் சப்செட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_IN_PROGRESS" msgid="2033399698172403560">"சிம் சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_IN_PROGRESS" msgid="4795977251920732254">"கார்ப்பரேட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_IN_PROGRESS" msgid="1090425878157254446">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_IN_PROGRESS" msgid="6476898876518094438">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_IN_PROGRESS" msgid="6006806734293747731">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_IN_PROGRESS" msgid="6546680489620881893">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_IN_PROGRESS" msgid="3506845511000727015">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SIM_IN_PROGRESS" msgid="6709169861932992750">"சிம் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_IN_PROGRESS" msgid="4013870911606478520">"RUIM network1 அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_IN_PROGRESS" msgid="9032651188219523434">"RUIM network2 அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_IN_PROGRESS" msgid="6584576506344491207">"hrpd அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_IN_PROGRESS" msgid="830981927724888114">"RUIM சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_IN_PROGRESS" msgid="7851790973098894802">"RUIM கார்ப்பரேட் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SPN_IN_PROGRESS" msgid="1149560739586960121">"SPN அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_IN_PROGRESS" msgid="5708964693522116025">"SP Equivalent Home PLMN அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_ICCID_IN_PROGRESS" msgid="7288103122966483455">"ICCID அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_IMPI_IN_PROGRESS" msgid="4036752174056147753">"IMPI அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_IN_PROGRESS" msgid="5089536274515338566">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_IN_PROGRESS" msgid="6737197986936251958">"RUIM அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_IN_PROGRESS" msgid="5658767775619998623">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_IN_PROGRESS" msgid="665978313257653727">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_IN_PROGRESS" msgid="3857142652251836850">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_IN_PROGRESS" msgid="2695664012344346788">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_IN_PROGRESS" msgid="2695678959963807782">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_IN_PROGRESS" msgid="1230605365926493599">"PUKவை உள்ளிட்டு அன்லாக் கோரிக்கை வைக்கப்பட்டுள்ளது…"</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_ERROR" msgid="1924844017037151535">"சிம் நெட்வொர்க் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_ERROR" msgid="3372797822292089708">"சிம் நெட்வொர்க் சப்செட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_ERROR" msgid="1878443146720411381">"சிம் சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_ERROR" msgid="7664778312218023192">"கார்ப்பரேட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SIM_ERROR" msgid="2472944311643350302">"சிம் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_ERROR" msgid="828089694480999120">"RUIM Network1 அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_ERROR" msgid="17619001007092511">"RUIM Network2 அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_ERROR" msgid="807214229604353614">"hrpd அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_ERROR" msgid="8644184447744175747">"RUIM கார்ப்பரேட் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_ERROR" msgid="3801002648649640407">"RUIM சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_ERROR" msgid="707397021218680753">"RUIM அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_ERROR" msgid="894358680773257820">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_ERROR" msgid="352466878146726991">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_ERROR" msgid="7353389721907138671">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_ERROR" msgid="2655263155490857920">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_ERROR" msgid="6903740900892931310">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_ERROR" msgid="5165901670447518687">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_ERROR" msgid="2856763216589267623">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_ERROR" msgid="817542684437829139">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_ERROR" msgid="5178635064113393143">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_ERROR" msgid="5391587926974531008">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_ERROR" msgid="4895494864493315868">"PUKவை உள்ளிட்டு அன்லாக் செய்ய இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SPN_ERROR" msgid="9017576601595353649">"SPN அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_ERROR" msgid="1116993930995545742">"SP Equivalent Home PLMN அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_ICCID_ERROR" msgid="7559167306794441462">"ICCID அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_IMPI_ERROR" msgid="2782926139511136588">"IMPI அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_ERROR" msgid="1890493954453456758">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் கோரிக்கையைச் செயல்படுத்த இயலவில்லை."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUCCESS" msgid="4886243367747126325">"சிம் நெட்வொர்க் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_SUCCESS" msgid="4053809277733513987">"சிம் நெட்வொர்க் சப்செட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_SUCCESS" msgid="8249342930499801740">"சிம் சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_SUCCESS" msgid="2339794542560381270">"கார்ப்பரேட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SIM_SUCCESS" msgid="6975608174152828954">"சிம் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_SUCCESS" msgid="2846699261330463192">"RUIM Network1 அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_SUCCESS" msgid="5335414726057102801">"RUIM Network2 அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_SUCCESS" msgid="8868100318474971969">"hrpd அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_SUCCESS" msgid="6020936629725666932">"RUIM சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_SUCCESS" msgid="6944873647584595489">"RUIM கார்ப்பரேட் அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_SUCCESS" msgid="2526483514124121988">"RUIM அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_PUK_SUCCESS" msgid="7662200333621664621">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NETWORK_SUBSET_PUK_SUCCESS" msgid="2861223407953766632">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_CORPORATE_PUK_SUCCESS" msgid="5345648571175243272">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="3725278343103422466">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SIM_PUK_SUCCESS" msgid="6998502547560297983">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK1_PUK_SUCCESS" msgid="8555433771162560361">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_NETWORK2_PUK_SUCCESS" msgid="3555767296933606232">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_HRPD_PUK_SUCCESS" msgid="6778051818199974237">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_CORPORATE_PUK_SUCCESS" msgid="4080108758498911429">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_SERVICE_PROVIDER_PUK_SUCCESS" msgid="7873675303000794343">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_RUIM_RUIM_PUK_SUCCESS" msgid="1763198215069819523">"PUKவை உள்ளிட்டு அன்லாக் செய்யப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SPN_SUCCESS" msgid="2053891977727320532">"SPN அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_SP_EHPLMN_SUCCESS" msgid="8146602361895007345">"SP Equivalent Home PLMN அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_ICCID_SUCCESS" msgid="8058678548991999545">"ICCID அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_IMPI_SUCCESS" msgid="2545608067978550571">"IMPI அன்லாக் செயல்படுத்தப்பட்டது."</string> + <string name="PERSOSUBSTATE_SIM_NS_SP_SUCCESS" msgid="4352382949744625007">"நெட்வொர்க் சப்செட் சேவை வழங்குநர் அன்லாக் செயல்படுத்தப்பட்டது."</string> </resources> diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml index f9e95a6ed9c4..e0990a2740e7 100644 --- a/core/res/res/values-te/strings.xml +++ b/core/res/res/values-te/strings.xml @@ -293,7 +293,7 @@ <string name="android_system_label" msgid="5974767339591067210">"Android సిస్టమ్"</string> <string name="user_owner_label" msgid="8628726904184471211">"వ్యక్తిగత ప్రొఫైల్కి మార్చు"</string> <string name="managed_profile_label" msgid="7316778766973512382">"కార్యాలయ ప్రొఫైల్కి మార్చు"</string> - <string name="permgrouplab_contacts" msgid="4254143639307316920">"పరిచయాలు"</string> + <string name="permgrouplab_contacts" msgid="4254143639307316920">"కాంటాక్ట్లు"</string> <string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ పరిచయాలను యాక్సెస్ చేయడానికి"</string> <string name="permgrouplab_location" msgid="1858277002233964394">"స్థానం"</string> <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string> @@ -571,7 +571,7 @@ <string name="permdesc_manageFace" msgid="6204569688492710471">"వినియోగం కోసం ముఖ టెంప్లేట్లను జోడించే మరియు తొలగించే పద్ధతులను అమలు చేయడానికి యాప్ను అనుమతిస్తుంది."</string> <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ముఖంతో అన్లాక్ చేయగల హార్డ్వేర్ వినియోగం"</string> <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"ప్రమాణీకరణ కోసం ముఖంతో అన్లాక్ చేయగల హార్డ్వేర్ను ఉపయోగించడానికి యాప్ను అనుమతిస్తుంది"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ముఖంతో అన్లాక్"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ఫేస్ అన్లాక్"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"మీ ముఖాన్ని తిరిగి నమోదు చేయండి"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"గుర్తింపును మెరుగుపరచడానికి, దయచేసి మీ ముఖంను తిరిగి నమోదు చేసుకోండి"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"ముఖం డేటా సరిగ్గా రాలేదు. మళ్లీ ప్రయత్నించండి."</string> @@ -905,7 +905,7 @@ <string name="keyguard_accessibility_expand_lock_area" msgid="4215280881346033434">"అన్లాక్ ప్రాంతాన్ని విస్తరింపజేయండి."</string> <string name="keyguard_accessibility_slide_unlock" msgid="2968195219692413046">"స్లయిడ్ అన్లాక్."</string> <string name="keyguard_accessibility_pattern_unlock" msgid="8669128146589233293">"ఆకృతి అన్లాక్."</string> - <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ముఖంతో అన్లాక్."</string> + <string name="keyguard_accessibility_face_unlock" msgid="632407612842329815">"ఫేస్ అన్లాక్."</string> <string name="keyguard_accessibility_pin_unlock" msgid="4020864007967340068">"పిన్ అన్లాక్."</string> <string name="keyguard_accessibility_sim_pin_unlock" msgid="4895939120871890557">"Sim పిన్ అన్లాక్."</string> <string name="keyguard_accessibility_sim_puk_unlock" msgid="3459003464041899101">"Sim Puk అన్లాక్."</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"సంభాషణ"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"గ్రూప్ సంభాషణ"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"వ్యక్తిగత వీక్షణ"</string> diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml index 041423d9b0d8..83f7a1bcf6ab 100644 --- a/core/res/res/values-th/strings.xml +++ b/core/res/res/values-th/strings.xml @@ -567,11 +567,11 @@ <string-array name="fingerprint_error_vendor"> </string-array> <string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string> - <string name="permlab_manageFace" msgid="4569549381889283282">"จัดการฮาร์ดแวร์ Face Unlock"</string> + <string name="permlab_manageFace" msgid="4569549381889283282">"จัดการฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string> <string name="permdesc_manageFace" msgid="6204569688492710471">"อนุญาตให้แอปเรียกใช้วิธีเพิ่มและลบเทมเพลตใบหน้าสำหรับการใช้งาน"</string> - <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ใช้ฮาร์ดแวร์ Face Unlock"</string> - <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"อนุญาตให้แอปใช้ฮาร์ดแวร์ Face Unlock เพื่อตรวจสอบสิทธิ์"</string> - <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"Face Unlock"</string> + <string name="permlab_useFaceAuthentication" msgid="1011430526454859030">"ใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้า"</string> + <string name="permdesc_useFaceAuthentication" msgid="3115697017684668012">"อนุญาตให้แอปใช้ฮาร์ดแวร์การปลดล็อกด้วยใบหน้าเพื่อตรวจสอบสิทธิ์"</string> + <string name="face_recalibrate_notification_name" msgid="6006095897989257026">"ปลดล็อกด้วยใบหน้า"</string> <string name="face_recalibrate_notification_title" msgid="5944930528030496897">"ลงทะเบียนใบหน้าอีกครั้ง"</string> <string name="face_recalibrate_notification_content" msgid="892757485125249962">"โปรดลงทะเบียนใบหน้าอีกครั้งเพื่อปรับปรุงการจดจำ"</string> <string name="face_acquired_insufficient" msgid="2150805835949162453">"บันทึกข้อมูลใบหน้าที่ถูกต้องไม่ได้ ลองอีกครั้ง"</string> @@ -597,15 +597,15 @@ <string-array name="face_acquired_vendor"> </string-array> <string name="face_error_hw_not_available" msgid="5085202213036026288">"ยืนยันใบหน้าไม่ได้ ฮาร์ดแวร์ไม่พร้อมใช้งาน"</string> - <string name="face_error_timeout" msgid="522924647742024699">"ลองใช้ Face Unlock อีกครั้ง"</string> + <string name="face_error_timeout" msgid="522924647742024699">"ลองใช้การปลดล็อกด้วยใบหน้าอีกครั้ง"</string> <string name="face_error_no_space" msgid="5649264057026021723">"จัดเก็บข้อมูลใบหน้าใหม่ไม่ได้ ลบข้อมูลเก่าออกไปก่อน"</string> <string name="face_error_canceled" msgid="2164434737103802131">"ยกเลิกการดำเนินการกับใบหน้าแล้ว"</string> - <string name="face_error_user_canceled" msgid="8553045452825849843">"ผู้ใช้ยกเลิกการใช้ Face Unlock"</string> + <string name="face_error_user_canceled" msgid="8553045452825849843">"ผู้ใช้ยกเลิกการใช้การปลดล็อกด้วยใบหน้า"</string> <string name="face_error_lockout" msgid="7864408714994529437">"ดำเนินการหลายครั้งเกินไป ลองอีกครั้งในภายหลัง"</string> - <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ลองหลายครั้งเกินไป ปิดใช้ Face Unlock แล้ว"</string> + <string name="face_error_lockout_permanent" msgid="8277853602168960343">"ลองหลายครั้งเกินไป ปิดใช้การปลดล็อกด้วยใบหน้าแล้ว"</string> <string name="face_error_unable_to_process" msgid="5723292697366130070">"ยืนยันใบหน้าไม่ได้ ลองอีกครั้ง"</string> - <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่า Face Unlock"</string> - <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับ Face Unlock"</string> + <string name="face_error_not_enrolled" msgid="7369928733504691611">"คุณยังไม่ได้ตั้งค่าการปลดล็อกด้วยใบหน้า"</string> + <string name="face_error_hw_not_present" msgid="1070600921591729944">"อุปกรณ์นี้ไม่รองรับการปลดล็อกด้วยใบหน้า"</string> <string name="face_error_security_update_required" msgid="5076017208528750161">"ปิดใช้เซ็นเซอร์ชั่วคราวแล้ว"</string> <string name="face_name_template" msgid="3877037340223318119">"ใบหน้า <xliff:g id="FACEID">%d</xliff:g>"</string> <string-array name="face_error_vendor"> @@ -835,7 +835,7 @@ <string name="lockscreen_pattern_wrong" msgid="2940138714468358458">"ลองอีกครั้ง"</string> <string name="lockscreen_password_wrong" msgid="8605355913868947490">"ลองอีกครั้ง"</string> <string name="lockscreen_storage_locked" msgid="634993789186443380">"ปลดล็อกฟีเจอร์และข้อมูลทั้งหมด"</string> - <string name="faceunlock_multiple_failures" msgid="681991538434031708">"มีความพยายามที่จะใช้ Face Unlock เกินขีดจำกัด"</string> + <string name="faceunlock_multiple_failures" msgid="681991538434031708">"ลองใช้การปลดล็อกด้วยใบหน้าเกินจำนวนครั้งที่กำหนดแล้ว"</string> <string name="lockscreen_missing_sim_message_short" msgid="1248431165144893792">"ไม่มีซิมการ์ด"</string> <string name="lockscreen_missing_sim_message" product="tablet" msgid="8596805728510570760">"ไม่มีซิมการ์ดในแท็บเล็ต"</string> <string name="lockscreen_missing_sim_message" product="tv" msgid="2582768023352171073">"ไม่มีซิมการ์ดในอุปกรณ์ Android TV"</string> @@ -1789,8 +1789,8 @@ <string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string> <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string> <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string> - <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> - <string name="battery_saver_description" msgid="7618492104632328184">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Hey Google”"</string> + <string name="battery_saver_description_with_learn_more" msgid="1817385558636532621">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”\n\n"<annotation id="url">"ดูข้อมูลเพิ่มเติม"</annotation></string> + <string name="battery_saver_description" msgid="7618492104632328184">"โหมดประหยัดแบตเตอรี่จะดำเนินการดังต่อไปนี้เพื่อยืดอายุการใช้งานแบตเตอรี่\n·เปิดธีมมืด\n·ปิดหรือจำกัดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง และฟีเจอร์อื่นๆ อย่างเช่น “Ok Google”"</string> <string name="data_saver_description" msgid="4995164271550590517">"เพื่อช่วยลดปริมาณการใช้อินเทอร์เน็ต โปรแกรมประหยัดอินเทอร์เน็ตจะช่วยป้องกันไม่ให้บางแอปส่งหรือรับข้อมูลโดยการใช้อินเทอร์เน็ตอยู่เบื้องหลัง แอปที่คุณกำลังใช้งานสามารถเข้าถึงอินเทอร์เน็ตได้ แต่อาจไม่บ่อยเท่าเดิม ตัวอย่างเช่น ภาพต่างๆ จะไม่แสดงจนกว่าคุณจะแตะที่ภาพเหล่านั้น"</string> <string name="data_saver_enable_title" msgid="7080620065745260137">"เปิดการประหยัดอินเทอร์เน็ตไหม"</string> <string name="data_saver_enable_button" msgid="4399405762586419726">"เปิด"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"การสนทนา"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"บทสนทนากลุ่ม"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"มุมมองส่วนตัว"</string> diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml index 0b1ee6549424..773020b0c88e 100644 --- a/core/res/res/values-tl/strings.xml +++ b/core/res/res/values-tl/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Pag-uusap"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Panggrupong Pag-uusap"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Personal na view"</string> diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml index 5861589e5ff8..69f41dd9a52b 100644 --- a/core/res/res/values-tr/strings.xml +++ b/core/res/res/values-tr/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Görüşme"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Grup Görüşmesi"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Kişisel görünüm"</string> diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml index 0cb185c11533..c9d29a224329 100644 --- a/core/res/res/values-uk/strings.xml +++ b/core/res/res/values-uk/strings.xml @@ -1349,9 +1349,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"Налагодження USB підключено"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"Торкніться, щоб вимкнути налагоджувач USB"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"Виберіть, щоб вимкнути налагодження за USB"</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Бездротове налагодження підключено"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Натисніть, щоб вимкнути бездротове налагодження"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Виберіть, щоб вимкнути бездротове налагодження."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Налагодження через Wi-Fi активне"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Натисніть, щоб вимкнути налагодження через Wi-Fi"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Виберіть, щоб вимкнути налагодження через Wi-Fi."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Увімкнено режим автоматизованого тестування"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Щоб вимкнути режим автоматизованого тестування, відновіть заводські налаштування."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Послідовну консоль увімкнено"</string> @@ -2112,8 +2112,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Чат"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Груповий чат"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Особистий перегляд"</string> diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml index e71789802ba1..216f62425d81 100644 --- a/core/res/res/values-ur/strings.xml +++ b/core/res/res/values-ur/strings.xml @@ -698,8 +698,8 @@ <string name="policydesc_encryptedStorage" msgid="1102516950740375617">"مطالبہ کریں کہ اسٹور کردہ ایپ کا ڈیٹا مرموز کیا جائے۔"</string> <string name="policylab_disableCamera" msgid="5749486347810162018">"کیمروں کو غیر فعال کریں"</string> <string name="policydesc_disableCamera" msgid="3204405908799676104">"سبھی آلے کے کیمروں کا استعمال روکیں۔"</string> - <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"کچھ سکرین قفل خصوصیات غیر فعال کریں"</string> - <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"اسکرین قفل کی کچھ خصوصیات کے استعمال کو روکیں۔"</string> + <string name="policylab_disableKeyguardFeatures" msgid="5071855750149949741">"کچھ اسکرین لاک خصوصیات غیرفعال کریں"</string> + <string name="policydesc_disableKeyguardFeatures" msgid="6641673177041195957">"اسکرین لاک کی کچھ خصوصیات کے استعمال کو روکیں۔"</string> <string-array name="phoneTypes"> <item msgid="8996339953292723951">"گھر"</item> <item msgid="7740243458912727194">"موبائل"</item> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"گفتگو"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"گروپ گفتگو"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"+<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"ذاتی ملاحظہ"</string> diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml index d2dde7104834..a1c9faa7d2f5 100644 --- a/core/res/res/values-uz/strings.xml +++ b/core/res/res/values-uz/strings.xml @@ -1309,9 +1309,9 @@ <string name="adb_active_notification_title" msgid="408390247354560331">"USB orqali nosozliklarni aniqlash"</string> <string name="adb_active_notification_message" msgid="5617264033476778211">"USB orqali nosozliklarni aniqlashni faolsizlantirish uchun bosing"</string> <string name="adb_active_notification_message" product="tv" msgid="6624498401272780855">"USB orqali nosozliklarni tuzatishni o‘chirib qo‘yish uchun bosing."</string> - <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Simsiz tarmoq nosozliklari faqat ulangan tarmoqda aniqlanadi"</string> - <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing"</string> - <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Simsiz tarmoqdagi nosozliklar aniqlanishini faolsizlantirish uchun bosing."</string> + <string name="adbwifi_active_notification_title" msgid="6147343659168302473">"Wi-Fi orqali debagging yoqildi"</string> + <string name="adbwifi_active_notification_message" msgid="930987922852867972">"Wi-Fi orqali debagging uzilishi uchun bosing"</string> + <string name="adbwifi_active_notification_message" product="tv" msgid="8633421848366915478">"Wi-Fi orqali debaggingni faolsizlantirish uchun bosing."</string> <string name="test_harness_mode_notification_title" msgid="2282785860014142511">"Xavfsizlik sinovi rejimi yoqildi"</string> <string name="test_harness_mode_notification_message" msgid="3039123743127958420">"Xavfsizlik sinovi rejimini faolsizlantirish uchun zavod sozlamalariga qaytaring."</string> <string name="console_running_notification_title" msgid="6087888939261635904">"Davomiy port terminali yoqildi"</string> diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml index cbe131fca08c..7e24e64199bc 100644 --- a/core/res/res/values-vi/strings.xml +++ b/core/res/res/values-vi/strings.xml @@ -1299,7 +1299,7 @@ <string name="usb_supplying_notification_title" msgid="5378546632408101811">"Đang sạc thiết bị được kết nối qua USB"</string> <string name="usb_mtp_notification_title" msgid="1065989144124499810">"Đã bật truyền tệp qua USB"</string> <string name="usb_ptp_notification_title" msgid="5043437571863443281">"Đã bật chế độ PTP qua USB"</string> - <string name="usb_tether_notification_title" msgid="8828527870612663771">"Đã bật chia sẻ kết nối qua USB"</string> + <string name="usb_tether_notification_title" msgid="8828527870612663771">"Đã bật tính năng chia sẻ Internet qua USB"</string> <string name="usb_midi_notification_title" msgid="7404506788950595557">"Đã bật chế độ MIDI qua USB"</string> <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Đã kết nối phụ kiện USB"</string> <string name="usb_notification_message" msgid="4715163067192110676">"Nhấn để biết thêm tùy chọn."</string> @@ -1573,7 +1573,7 @@ <string name="display_manager_overlay_display_title" msgid="1480158037150469170">"<xliff:g id="NAME">%1$s</xliff:g>: <xliff:g id="WIDTH">%2$d</xliff:g>x<xliff:g id="HEIGHT">%3$d</xliff:g>, <xliff:g id="DPI">%4$d</xliff:g> dpi"</string> <string name="display_manager_overlay_display_secure_suffix" msgid="2810034719482834679">", an toàn"</string> <string name="kg_forgot_pattern_button_text" msgid="406145459223122537">"Đã quên hình"</string> - <string name="kg_wrong_pattern" msgid="1342812634464179931">"Hình không chính xác"</string> + <string name="kg_wrong_pattern" msgid="1342812634464179931">"Hình mở khóa không chính xác"</string> <string name="kg_wrong_password" msgid="2384677900494439426">"Mật khẩu sai"</string> <string name="kg_wrong_pin" msgid="3680925703673166482">"PIN sai"</string> <plurals name="kg_too_many_failed_attempts_countdown" formatted="false" msgid="236717428673283568"> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Cuộc trò chuyện"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Cuộc trò chuyện nhóm"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Chế độ xem cá nhân"</string> diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml index 5f921bc65bdf..18eb7d998aac 100644 --- a/core/res/res/values-zh-rCN/strings.xml +++ b/core/res/res/values-zh-rCN/strings.xml @@ -681,7 +681,7 @@ <string name="policylab_resetPassword" msgid="214556238645096520">"更改锁屏方式"</string> <string name="policydesc_resetPassword" msgid="4626419138439341851">"更改锁屏方式。"</string> <string name="policylab_forceLock" msgid="7360335502968476434">"锁定屏幕"</string> - <string name="policydesc_forceLock" msgid="1008844760853899693">"控制屏幕锁定的方式和时间。"</string> + <string name="policydesc_forceLock" msgid="1008844760853899693">"控制锁屏的方式和时间。"</string> <string name="policylab_wipeData" msgid="1359485247727537311">"清除所有数据"</string> <string name="policydesc_wipeData" product="tablet" msgid="7245372676261947507">"恢复出厂设置时,系统会在不发出警告的情况下清除平板电脑上的数据。"</string> <string name="policydesc_wipeData" product="tv" msgid="513862488950801261">"不事先发出警告就以恢复出厂设置的方式清空 Android TV 设备中的数据。"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"对话"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群组对话"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"个人视图"</string> diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml index d85b271a37c6..e6d539541b63 100644 --- a/core/res/res/values-zh-rHK/strings.xml +++ b/core/res/res/values-zh-rHK/strings.xml @@ -1561,7 +1561,7 @@ <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"螢幕投放到裝置"</string> <string name="media_route_chooser_searching" msgid="6119673534251329535">"正在搜尋裝置…"</string> <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"設定"</string> - <string name="media_route_controller_disconnect" msgid="7362617572732576959">"停止連接"</string> + <string name="media_route_controller_disconnect" msgid="7362617572732576959">"中斷連線"</string> <string name="media_route_status_scanning" msgid="8045156315309594482">"正在掃瞄…"</string> <string name="media_route_status_connecting" msgid="5845597961412010540">"正在連線..."</string> <string name="media_route_status_available" msgid="1477537663492007608">"可用"</string> @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人檢視模式"</string> diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml index 88301a9cc41a..59b5cdcbd90d 100644 --- a/core/res/res/values-zh-rTW/strings.xml +++ b/core/res/res/values-zh-rTW/strings.xml @@ -2044,8 +2044,7 @@ <string name="conversation_single_line_name_display" msgid="8958948312915255999">"<xliff:g id="SENDER_NAME">%1$s</xliff:g>:"</string> <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"對話"</string> <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"群組對話"</string> - <!-- no translation found for unread_convo_overflow (920517615597353833) --> - <skip /> + <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string> <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string> <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string> <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"個人檢視模式"</string> diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp index 8d51a6000086..1e16ee052899 100644 --- a/core/tests/coretests/Android.bp +++ b/core/tests/coretests/Android.bp @@ -72,6 +72,7 @@ android_test { ":BinderDeathRecipientHelperApp1", ":BinderDeathRecipientHelperApp2", ], + required: ["com.android.cts.helpers.aosp"], } // Rules to copy all the test apks to the intermediate raw resource directory diff --git a/core/tests/coretests/AndroidTest.xml b/core/tests/coretests/AndroidTest.xml index ed9d3f54ef3d..04952bdfa389 100644 --- a/core/tests/coretests/AndroidTest.xml +++ b/core/tests/coretests/AndroidTest.xml @@ -24,6 +24,9 @@ <option name="test-file-name" value="BinderDeathRecipientHelperApp1.apk" /> <option name="test-file-name" value="BinderDeathRecipientHelperApp2.apk" /> </target_preparer> + + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInteractionHelperInstaller" /> + <option name="test-tag" value="FrameworksCoreTests" /> <test class="com.android.tradefed.testtype.AndroidJUnitTest" > <option name="package" value="com.android.frameworks.coretests" /> diff --git a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java index 94d85e63cc5f..4dd4d1c7bd12 100644 --- a/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java +++ b/core/tests/coretests/src/android/print/IPrintManagerParametersTest.java @@ -41,6 +41,7 @@ import android.print.test.services.PrintServiceCallbacks; import android.print.test.services.PrinterDiscoverySessionCallbacks; import android.print.test.services.StubbablePrinterDiscoverySession; import android.printservice.recommendation.IRecommendationsChangeListener; +import android.support.test.uiautomator.UiDevice; import androidx.test.filters.LargeTest; import androidx.test.filters.MediumTest; @@ -71,6 +72,10 @@ public class IPrintManagerParametersTest extends BasePrintTest { private IPrintManager mIPrintManager; + public static UiDevice getUiDevice() { + return UiDevice.getInstance(getInstrumentation()); + } + /** * Create a new IPrintManagerParametersTest and setup basic fields. */ diff --git a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java index 4bfffd72d835..a9f251e5c3a7 100644 --- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java +++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java @@ -69,7 +69,6 @@ import java.util.concurrent.atomic.AtomicLong; @RunWith(AndroidJUnit4.class) @MediumTest -@Presubmit public class EditorCursorDragTest { private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName(); @@ -97,6 +96,7 @@ public class EditorCursorDragTest { mMotionEvents.clear(); } + @Presubmit @Test public void testCursorDrag_horizontal_whenTextViewContentsFitOnScreen() throws Throwable { String text = "Hello world!"; diff --git a/core/tests/overlaytests/host/Android.bp b/core/tests/overlaytests/host/Android.bp index a2fcef56b780..2b38cca2db36 100644 --- a/core/tests/overlaytests/host/Android.bp +++ b/core/tests/overlaytests/host/Android.bp @@ -16,7 +16,7 @@ java_test_host { name: "OverlayHostTests", srcs: ["src/**/*.java"], libs: ["tradefed"], - test_suites: ["general-tests"], + test_suites: ["device-tests"], target_required: [ "OverlayHostTests_NonPlatformSignatureOverlay", "OverlayHostTests_PlatformSignatureStaticOverlay", diff --git a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java index eec7be22c78b..d898d222b8de 100644 --- a/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java +++ b/core/tests/overlaytests/host/src/com/android/server/om/hosttest/InstallOverlayTests.java @@ -78,14 +78,9 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { } @Test - public void failToInstallPlatformSignedStaticOverlay() throws Exception { - try { - installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk"); - fail("installed a static overlay"); - } catch (Exception e) { - // Expected. - } - assertFalse(overlayManagerContainsPackage(SIG_OVERLAY_PACKAGE_NAME)); + public void installedIsStaticOverlayIsMutable() throws Exception { + installPackage("OverlayHostTests_PlatformSignatureStaticOverlay.apk"); + assertTrue(isOverlayMutable(SIG_OVERLAY_PACKAGE_NAME)); } @Test @@ -229,6 +224,10 @@ public class InstallOverlayTests extends BaseHostJUnit4Test { return shell("cmd overlay list").contains(pkg); } + private boolean isOverlayMutable(String pkg) throws Exception { + return shell("cmd overlay dump ismutable " + pkg).contains("true"); + } + private String shell(final String cmd) throws Exception { return getDevice().executeShellCommand(cmd); } diff --git a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk index cc7704b0ce98..f3c0abd8293f 100644 --- a/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/SignatureOverlay/Android.mk @@ -20,7 +20,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_NonPlatformSignatureOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_bad include $(BUILD_PACKAGE) @@ -28,7 +28,8 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureStaticOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests +LOCAL_CERTIFICATE := platform LOCAL_MANIFEST_FILE := static/AndroidManifest.xml LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_static include $(BUILD_PACKAGE) @@ -37,7 +38,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_PlatformSignatureOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 diff --git a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk index f8607f44bda6..878f05d57662 100644 --- a/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk +++ b/core/tests/overlaytests/host/test-apps/UpdateOverlay/Android.mk @@ -19,7 +19,7 @@ LOCAL_MODULE_TAGS := tests LOCAL_SRC_FILES := $(call all-java-files-under,src) LOCAL_PACKAGE_NAME := OverlayHostTests_UpdateOverlay LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_STATIC_JAVA_LIBRARIES := androidx.test.rules LOCAL_USE_AAPT2 := true LOCAL_AAPT_FLAGS := --no-resource-removal @@ -31,7 +31,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV1 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 @@ -43,7 +43,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_FrameworkOverlayV2 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_CERTIFICATE := platform LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2 @@ -57,7 +57,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV1 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v1 LOCAL_AAPT_FLAGS += --version-code 1 --version-name v1 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v1/res @@ -68,7 +68,7 @@ include $(CLEAR_VARS) LOCAL_MODULE_TAGS := tests LOCAL_PACKAGE_NAME := OverlayHostTests_AppOverlayV2 LOCAL_SDK_VERSION := current -LOCAL_COMPATIBILITY_SUITE := general-tests +LOCAL_COMPATIBILITY_SUITE := device-tests LOCAL_AAPT_FLAGS := --custom-package $(my_package_prefix)_v2 LOCAL_AAPT_FLAGS += --version-code 2 --version-name v2 LOCAL_RESOURCE_DIR := $(LOCAL_PATH)/app/v2/res diff --git a/core/tests/overlaytests/remount/host/Android.bp b/core/tests/overlaytests/remount/Android.bp index 3825c55f3b4b..5757cfe75514 100644 --- a/core/tests/overlaytests/remount/host/Android.bp +++ b/core/tests/overlaytests/remount/Android.bp @@ -21,8 +21,12 @@ java_test_host { ], test_suites: ["general-tests"], java_resources: [ + ":com.android.overlaytest.overlaid", + ":com.android.overlaytest.overlay", ":OverlayRemountedTest_SharedLibrary", ":OverlayRemountedTest_SharedLibraryOverlay", ":OverlayRemountedTest_Target", + ":OverlayRemountedTest_TargetUpgrade", + ":OverlayRemountedTest_Overlay", ], } diff --git a/core/tests/overlaytests/remount/host/AndroidTest.xml b/core/tests/overlaytests/remount/AndroidTest.xml index 087b7313693d..087b7313693d 100644 --- a/core/tests/overlaytests/remount/host/AndroidTest.xml +++ b/core/tests/overlaytests/remount/AndroidTest.xml diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java new file mode 100644 index 000000000000..3fa8bcd6cbf0 --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayApexTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.overlaytest.remounted; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class OverlayApexTest extends OverlayRemountedTestBase { + private static final String OVERLAID_APEX = "com.android.overlaytest.overlaid.apex"; + private static final String OVERLAY_APEX = "com.android.overlaytest.overlay.apex"; + + @Test + public void testApkInApexCanBeOverlaid() throws Exception { + final String targetResource = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + + // The target APK will be installed inside the overlaid APEX. + mPreparer.pushResourceFile(OVERLAID_APEX, + "/system/apex/com.android.overlaytest.overlaid.apex") + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .reboot() + .setOverlayEnabled(OVERLAY_PACKAGE, false); + + // The resource is not currently overlaid. + assertResource(targetResource, "false"); + + // Overlay the resource. + mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true); + assertResource(targetResource, "true"); + } + + @Test + public void testApkInApexCanOverlay() throws Exception { + final String targetResource = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + + // The overlay APK will be installed inside the overlay APEX. + mPreparer.pushResourceFile(OVERLAY_APEX, + "/system/apex/com.android.overlaytest.overlay.apex") + .installResourceApk(TARGET_APK, TARGET_PACKAGE) + .reboot() + .setOverlayEnabled(OVERLAY_PACKAGE, false); + + // The resource is not currently overlaid. + assertResource(targetResource, "false"); + + // Overlay the resource. + mPreparer.setOverlayEnabled(OVERLAY_PACKAGE, true); + assertResource(targetResource, "true"); + } +} diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java new file mode 100644 index 000000000000..14b5bf6eacba --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlayRemountedTestBase.java @@ -0,0 +1,74 @@ +/* + * 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.overlaytest.remounted; + +import static org.junit.Assert.fail; + +import com.android.tradefed.device.DeviceNotAvailableException; +import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; + +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.RuleChain; +import org.junit.rules.TemporaryFolder; + +public class OverlayRemountedTestBase extends BaseHostJUnit4Test { + private static final long ASSERT_RESOURCE_TIMEOUT_MS = 30000; + static final String TARGET_APK = "OverlayRemountedTest_Target.apk"; + static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target"; + static final String OVERLAY_APK = "OverlayRemountedTest_Overlay.apk"; + static final String OVERLAY_PACKAGE = "com.android.overlaytest.remounted.target.overlay"; + + private final TemporaryFolder mTemporaryFolder = new TemporaryFolder(); + protected final SystemPreparer mPreparer = new SystemPreparer(mTemporaryFolder, + this::getDevice); + + @Rule + public final RuleChain ruleChain = RuleChain.outerRule(mTemporaryFolder).around(mPreparer); + + @Before + public void startBefore() throws DeviceNotAvailableException { + getDevice().waitForDeviceAvailable(); + } + + /** Builds the full name of a resource in the form package:type/entry. */ + String resourceName(String pkg, String type, String entry) { + return String.format("%s:%s/%s", pkg, type, entry); + } + + void assertResource(String resourceName, String expectedValue) + throws DeviceNotAvailableException { + String result = null; + + final long endMillis = System.currentTimeMillis() + ASSERT_RESOURCE_TIMEOUT_MS; + while (System.currentTimeMillis() <= endMillis) { + result = getDevice().executeShellCommand( + String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName)); + if (result.equals(expectedValue + "\n") || + result.endsWith("-> " + expectedValue + "\n")) { + return; + } + + try { + Thread.sleep(200); + } catch (InterruptedException ignore) { + } + } + + fail(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result)); + } +} diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java index 06b2ac8f9e22..7f2c060b13fc 100644 --- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java @@ -16,23 +16,13 @@ package com.android.overlaytest.remounted; -import static org.junit.Assert.assertTrue; - -import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; -import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test; -import org.junit.Before; -import org.junit.Rule; import org.junit.Test; -import org.junit.rules.RuleChain; -import org.junit.rules.TemporaryFolder; import org.junit.runner.RunWith; @RunWith(DeviceJUnit4ClassRunner.class) -public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { - private static final String TARGET_APK = "OverlayRemountedTest_Target.apk"; - private static final String TARGET_PACKAGE = "com.android.overlaytest.remounted.target"; +public class OverlaySharedLibraryTest extends OverlayRemountedTestBase { private static final String SHARED_LIBRARY_APK = "OverlayRemountedTest_SharedLibrary.apk"; private static final String SHARED_LIBRARY_PACKAGE = @@ -42,17 +32,6 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { private static final String SHARED_LIBRARY_OVERLAY_PACKAGE = "com.android.overlaytest.remounted.shared_library.overlay"; - public final TemporaryFolder temporaryFolder = new TemporaryFolder(); - public final SystemPreparer preparer = new SystemPreparer(temporaryFolder, this::getDevice); - - @Rule - public final RuleChain ruleChain = RuleChain.outerRule(temporaryFolder).around(preparer); - - @Before - public void startBefore() throws DeviceNotAvailableException { - getDevice().waitForDeviceAvailable(); - } - @Test public void testSharedLibrary() throws Exception { final String targetResource = resourceName(TARGET_PACKAGE, "bool", @@ -60,7 +39,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool", "shared_library_overlaid"); - preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") + mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") .installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE) .reboot() .setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, false) @@ -71,7 +50,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { assertResource(libraryResource, "false"); // Overlay the shared library resource. - preparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true); + mPreparer.setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true); assertResource(targetResource, "true"); assertResource(libraryResource, "true"); } @@ -83,7 +62,7 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { final String libraryResource = resourceName(SHARED_LIBRARY_PACKAGE, "bool", "shared_library_overlaid"); - preparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") + mPreparer.pushResourceFile(SHARED_LIBRARY_APK, "/product/app/SharedLibrary.apk") .installResourceApk(SHARED_LIBRARY_OVERLAY_APK, SHARED_LIBRARY_OVERLAY_PACKAGE) .setOverlayEnabled(SHARED_LIBRARY_OVERLAY_PACKAGE, true) .reboot() @@ -92,18 +71,4 @@ public class OverlaySharedLibraryTest extends BaseHostJUnit4Test { assertResource(targetResource, "true"); assertResource(libraryResource, "true"); } - - /** Builds the full name of a resource in the form package:type/entry. */ - String resourceName(String pkg, String type, String entry) { - return String.format("%s:%s/%s", pkg, type, entry); - } - - void assertResource(String resourceName, String expectedValue) - throws DeviceNotAvailableException { - final String result = getDevice().executeShellCommand( - String.format("cmd overlay lookup %s %s", TARGET_PACKAGE, resourceName)); - assertTrue(String.format("expected: <[%s]> in: <[%s]>", expectedValue, result), - result.equals(expectedValue + "\n") || - result.endsWith("-> " + expectedValue + "\n")); - } } diff --git a/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java new file mode 100644 index 000000000000..70e342370545 --- /dev/null +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/PackagedUpgradedTest.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.overlaytest.remounted; + +import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; + +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(DeviceJUnit4ClassRunner.class) +public class PackagedUpgradedTest extends OverlayRemountedTestBase { + private static final String TARGET_UPGRADE_APK = "OverlayRemountedTest_TargetUpgrade.apk"; + + @Test + public void testTargetUpgrade() throws Exception { + final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + final String targetReference = resourceName(TARGET_PACKAGE, "bool", "target_reference"); + + mPreparer.pushResourceFile(TARGET_APK, "/product/app/OverlayTarget.apk") + .reboot() + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .setOverlayEnabled(OVERLAY_PACKAGE, true); + + assertResource(targetReference, "@" + 0x7f010000 + " -> true"); + assertResource(targetOverlaid, "true"); + + mPreparer.installResourceApk(TARGET_UPGRADE_APK, TARGET_PACKAGE); + + assertResource(targetReference, "@" + 0x7f0100ff + " -> true"); + assertResource(targetOverlaid, "true"); + } + + @Test + public void testTargetRelocated() throws Exception { + final String targetOverlaid = resourceName(TARGET_PACKAGE, "bool", "target_overlaid"); + final String originalPath = "/product/app/OverlayTarget.apk"; + + mPreparer.pushResourceFile(TARGET_APK, originalPath) + .reboot() + .installResourceApk(OVERLAY_APK, OVERLAY_PACKAGE) + .setOverlayEnabled(OVERLAY_PACKAGE, true); + + assertResource(targetOverlaid, "true"); + + mPreparer.remount(); + getDevice().deleteFile(originalPath); + mPreparer.pushResourceFile(TARGET_UPGRADE_APK, "/product/app/OverlayTarget2.apk") + .reboot(); + + assertResource(targetOverlaid, "true"); + } +} diff --git a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java index 8696091239c2..bb72d0ee1d03 100644 --- a/core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java +++ b/core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java @@ -18,8 +18,6 @@ package com.android.overlaytest.remounted; import static org.junit.Assert.assertTrue; -import static java.util.concurrent.TimeUnit.MILLISECONDS; - import com.android.tradefed.device.DeviceNotAvailableException; import com.android.tradefed.device.ITestDevice; @@ -32,10 +30,6 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.util.ArrayList; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.FutureTask; -import java.util.concurrent.TimeoutException; class SystemPreparer extends ExternalResource { private static final long OVERLAY_ENABLE_TIMEOUT_MS = 30000; @@ -58,7 +52,7 @@ class SystemPreparer extends ExternalResource { SystemPreparer pushResourceFile(String resourcePath, String outputPath) throws DeviceNotAvailableException, IOException { final ITestDevice device = mDeviceProvider.getDevice(); - device.executeAdbCommand("remount"); + remount(); assertTrue(device.pushFile(copyResourceToTemp(resourcePath), outputPath)); mPushedFiles.add(outputPath); return this; @@ -69,42 +63,37 @@ class SystemPreparer extends ExternalResource { throws DeviceNotAvailableException, IOException { final ITestDevice device = mDeviceProvider.getDevice(); final File tmpFile = copyResourceToTemp(resourcePath); - final String result = device.installPackage(tmpFile, true); + final String result = device.installPackage(tmpFile, true /* reinstall */); Assert.assertNull(result); mInstalledPackages.add(packageName); return this; } - /** Sets the enable state of an overlay pacakage. */ + /** Sets the enable state of an overlay package. */ SystemPreparer setOverlayEnabled(String packageName, boolean enabled) - throws ExecutionException, DeviceNotAvailableException { + throws DeviceNotAvailableException { final ITestDevice device = mDeviceProvider.getDevice(); + final String enable = enabled ? "enable" : "disable"; // Wait for the overlay to change its enabled state. - final FutureTask<Boolean> enabledListener = new FutureTask<>(() -> { - while (true) { - device.executeShellCommand(String.format("cmd overlay %s %s", - enabled ? "enable" : "disable", packageName)); - - final String result = device.executeShellCommand("cmd overlay dump " + packageName); - final int startIndex = result.indexOf("mIsEnabled"); - final int endIndex = result.indexOf('\n', startIndex); - if (result.substring(startIndex, endIndex).contains((enabled) ? "true" : "false")) { - return true; - } + final long endMillis = System.currentTimeMillis() + OVERLAY_ENABLE_TIMEOUT_MS; + String result; + while (System.currentTimeMillis() <= endMillis) { + device.executeShellCommand(String.format("cmd overlay %s %s", enable, packageName)); + result = device.executeShellCommand("cmd overlay dump isenabled " + + packageName); + if (((enabled) ? "true\n" : "false\n").equals(result)) { + return this; } - }); - final Executor executor = (cmd) -> new Thread(cmd).start(); - executor.execute(enabledListener); - try { - enabledListener.get(OVERLAY_ENABLE_TIMEOUT_MS, MILLISECONDS); - } catch (InterruptedException ignored) { - } catch (TimeoutException e) { - throw new IllegalStateException(device.executeShellCommand("cmd overlay list")); + try { + Thread.sleep(200); + } catch (InterruptedException ignore) { + } } - return this; + throw new IllegalStateException(String.format("Failed to %s overlay %s:\n%s", enable, + packageName, device.executeShellCommand("cmd overlay list"))); } /** Restarts the device and waits until after boot is completed. */ @@ -114,6 +103,11 @@ class SystemPreparer extends ExternalResource { return this; } + SystemPreparer remount() throws DeviceNotAvailableException { + mDeviceProvider.getDevice().executeAdbCommand("remount"); + return this; + } + /** Copies a file within the host test jar to a temporary file on the host machine. */ private File copyResourceToTemp(String resourcePath) throws IOException { final File tempFile = mHostTempFolder.newFile(resourcePath); @@ -138,7 +132,7 @@ class SystemPreparer extends ExternalResource { protected void after() { final ITestDevice device = mDeviceProvider.getDevice(); try { - device.executeAdbCommand("remount"); + remount(); for (final String file : mPushedFiles) { device.deleteFile(file); } diff --git a/core/tests/overlaytests/remount/target/Android.bp b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp index 83f9f28b3f48..a1fdbfd3542c 100644 --- a/core/tests/overlaytests/remount/target/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/Overlay/Android.bp @@ -1,4 +1,4 @@ -// Copyright (C) 2018 The Android Open Source Project +// 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. @@ -13,8 +13,9 @@ // limitations under the License. android_test_helper_app { - name: "OverlayRemountedTest_Target", - srcs: ["src/**/*.java"], - sdk_version: "test_current", - libs: ["OverlayRemountedTest_SharedLibrary"], + name: "OverlayRemountedTest_Overlay", + sdk_version: "current", + apex_available: [ + "com.android.overlaytest.overlay", + ], } diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml new file mode 100644 index 000000000000..d6d706c2da62 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Overlay/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.overlaytest.remounted.target.overlay"> + <application android:hasCode="false" /> + <overlay android:targetPackage="com.android.overlaytest.remounted.target" + android:targetName="TestResources" /> +</manifest>
\ No newline at end of file diff --git a/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml new file mode 100644 index 000000000000..675e44f19f95 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.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> + <bool name="target_overlaid">true</bool> +</resources> diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp index ffb0572c3fd0..ffb0572c3fd0 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/Android.bp diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/AndroidManifest.xml index 06e3f6a99410..06e3f6a99410 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/AndroidManifest.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/overlayable.xml index 1b06f6d7530b..1b06f6d7530b 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/overlayable.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/overlayable.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/public.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/public.xml index 5b9db163a274..5b9db163a274 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/public.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/public.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/values.xml index 2dc47a7ecf61..2dc47a7ecf61 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibrary/res/values/values.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/Android.bp b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp index 0d29aec909d5..0d29aec909d5 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/Android.bp +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/Android.bp diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/AndroidManifest.xml index 53a4e61949da..53a4e61949da 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/AndroidManifest.xml diff --git a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/res/values/values.xml index f66448a8d991..f66448a8d991 100644 --- a/core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/res/values/values.xml diff --git a/core/tests/overlaytests/remount/test-apps/Target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp new file mode 100644 index 000000000000..19947b1ea51a --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/Android.bp @@ -0,0 +1,28 @@ +// 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_helper_app { + name: "OverlayRemountedTest_Target", + sdk_version: "test_current", + apex_available: [ + "com.android.overlaytest.overlaid", + ], + libs: ["OverlayRemountedTest_SharedLibrary"], +} + +android_test_helper_app { + name: "OverlayRemountedTest_TargetUpgrade", + resource_dirs: ["res_upgrade"], + sdk_version: "test_current", +} diff --git a/core/tests/overlaytests/remount/target/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/Target/AndroidManifest.xml index dc07dca16718..d1c7b7e8bb9d 100644 --- a/core/tests/overlaytests/remount/target/AndroidManifest.xml +++ b/core/tests/overlaytests/remount/test-apps/Target/AndroidManifest.xml @@ -19,8 +19,7 @@ package="com.android.overlaytest.remounted.target"> <application> - <uses-library android:name="android.test.runner" /> <uses-library android:name="com.android.overlaytest.remounted.shared_library" - android:required="true" /> + android:required="false" /> </application> </manifest> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml new file mode 100644 index 000000000000..4aa5bcee8f3d --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <overlayable name="TestResources"> + <policy type="public"> + <item type="bool" name="target_overlaid" /> + </policy> + </overlayable> +</resources> diff --git a/core/tests/overlaytests/remount/target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml index b5f444a5eb72..76253a95b766 100644 --- a/core/tests/overlaytests/remount/target/res/values/values.xml +++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml @@ -17,4 +17,10 @@ <resources xmlns:sharedlib="http://schemas.android.com/apk/res/com.android.overlaytest.remounted.shared_library"> <bool name="uses_shared_library_overlaid">@sharedlib:bool/shared_library_overlaid</bool> + + <!-- This resource has a different id in the updated version of this target app to test that the + idmap is regenerated when the target is updated. --> + <bool name="target_overlaid">false</bool> + <public type="bool" name="target_overlaid" id="0x7f010000" /> + <bool name="target_reference">@bool/target_overlaid</bool> </resources> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml new file mode 100644 index 000000000000..4aa5bcee8f3d --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml @@ -0,0 +1,24 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<resources> + <overlayable name="TestResources"> + <policy type="public"> + <item type="bool" name="target_overlaid" /> + </policy> + </overlayable> +</resources> diff --git a/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml new file mode 100644 index 000000000000..f552cb0776ab --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.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. + --> +<resources> + <!-- This resource has a different id in the updated target app than the base target app to test + that the idmap is regenerated when the target is updated. --> + <bool name="target_overlaid">false</bool> + <public type="bool" name="target_overlaid" id="0x7f0100ff" /> + <bool name="target_reference">@bool/target_overlaid</bool> +</resources>
\ No newline at end of file diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp new file mode 100644 index 000000000000..e6ebd5ea76d8 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/Android.bp @@ -0,0 +1,42 @@ +// 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. + +genrule { + name: "com.android.overlaytest.overlaid.pem", + out: ["com.android.overlaytest.overlaid.pem"], + cmd: "openssl genrsa -out $(out) 4096", +} + +genrule { + name: "com.android.overlaytest.overlaid.pubkey", + srcs: [":com.android.overlaytest.overlaid.pem"], + out: ["com.android.overlaytest.overlaid.pubkey"], + tools: ["avbtool"], + cmd: "$(location avbtool) extract_public_key --key $(in) --output $(out)", +} + +apex_key { + name: "com.android.overlaytest.overlaid.key", + public_key: ":com.android.overlaytest.overlaid.pubkey", + private_key: ":com.android.overlaytest.overlaid.pem", +} + +apex { + name: "com.android.overlaytest.overlaid", + manifest: "manifest.json", + file_contexts: ":apex.test-file_contexts", + key: "com.android.overlaytest.overlaid.key", + apps: ["OverlayRemountedTest_Target"], + installable: false, +} diff --git a/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json b/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json new file mode 100644 index 000000000000..9a5102fde11f --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlaid_apex/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.overlaytest.overlaid", + "version": "1" +} diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp new file mode 100644 index 000000000000..07f27ee55d39 --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/Android.bp @@ -0,0 +1,42 @@ +// 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. + +genrule { + name: "com.android.overlaytest.overlay.pem", + out: ["com.android.overlaytest.overlay.pem"], + cmd: "openssl genrsa -out $(out) 4096", +} + +genrule { + name: "com.android.overlaytest.overlay.pubkey", + srcs: [":com.android.overlaytest.overlay.pem"], + out: ["com.android.overlaytest.overlay.pubkey"], + tools: ["avbtool"], + cmd: "$(location avbtool) extract_public_key --key $(in) --output $(out)", +} + +apex_key { + name: "com.android.overlaytest.overlay.key", + public_key: ":com.android.overlaytest.overlay.pubkey", + private_key: ":com.android.overlaytest.overlay.pem", +} + +apex { + name: "com.android.overlaytest.overlay", + manifest: "manifest.json", + file_contexts: ":apex.test-file_contexts", + key: "com.android.overlaytest.overlay.key", + apps: ["OverlayRemountedTest_Overlay"], + installable: false, +} diff --git a/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json b/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json new file mode 100644 index 000000000000..ac5f84659eef --- /dev/null +++ b/core/tests/overlaytests/remount/test-apps/overlay_apex/manifest.json @@ -0,0 +1,4 @@ +{ + "name": "com.android.overlaytest.overlay", + "version": "1" +}
\ No newline at end of file diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json index 63a6b4088abb..18086ec0313e 100644 --- a/data/etc/services.core.protolog.json +++ b/data/etc/services.core.protolog.json @@ -1213,6 +1213,12 @@ "group": "WM_SHOW_TRANSACTIONS", "at": "com\/android\/server\/wm\/WindowSurfaceController.java" }, + "315395835": { + "message": "Trying to add window with invalid user=%d", + "level": "WARN", + "group": "WM_ERROR", + "at": "com\/android\/server\/wm\/WindowManagerService.java" + }, "342460966": { "message": "DRAG %s: pos=(%d,%d)", "level": "INFO", diff --git a/libs/androidfw/ApkAssets.cpp b/libs/androidfw/ApkAssets.cpp index 918e7af12d31..05f4d6b63a4c 100644 --- a/libs/androidfw/ApkAssets.cpp +++ b/libs/androidfw/ApkAssets.cpp @@ -385,7 +385,7 @@ std::unique_ptr<const ApkAssets> ApkAssets::LoadOverlay(const std::string& idmap const StringPiece idmap_data( reinterpret_cast<const char*>(idmap_asset->getBuffer(true /*wordAligned*/)), static_cast<size_t>(idmap_asset->getLength())); - std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_data); + std::unique_ptr<const LoadedIdmap> loaded_idmap = LoadedIdmap::Load(idmap_path, idmap_data); if (loaded_idmap == nullptr) { LOG(ERROR) << "failed to load IDMAP " << idmap_path; return {}; @@ -538,8 +538,9 @@ bool ApkAssets::IsUpToDate() const { // Loaders are invalidated by the app, not the system, so assume they are up to date. return true; } + return (!loaded_idmap_ || loaded_idmap_->IsUpToDate()) && + last_mod_time_ == getFileModDate(path_.c_str()); - return last_mod_time_ == getFileModDate(path_.c_str()); } } // namespace android diff --git a/libs/androidfw/Idmap.cpp b/libs/androidfw/Idmap.cpp index 0b2fd9ec982d..eb6ee9525bb9 100644 --- a/libs/androidfw/Idmap.cpp +++ b/libs/androidfw/Idmap.cpp @@ -20,6 +20,7 @@ #include "android-base/logging.h" #include "android-base/stringprintf.h" +#include "androidfw/misc.h" #include "androidfw/ResourceTypes.h" #include "androidfw/Util.h" #include "utils/ByteOrder.h" @@ -192,7 +193,9 @@ static bool IsValidIdmapHeader(const StringPiece& data) { return true; } -LoadedIdmap::LoadedIdmap(const Idmap_header* header, +LoadedIdmap::LoadedIdmap(std::string&& idmap_path, + const time_t last_mod_time, + const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, const Idmap_overlay_entry* overlay_entries, @@ -201,7 +204,9 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header, data_header_(data_header), target_entries_(target_entries), overlay_entries_(overlay_entries), - string_pool_(string_pool) { + string_pool_(string_pool), + idmap_path_(std::move(idmap_path)), + idmap_last_mod_time_(last_mod_time) { size_t length = strnlen(reinterpret_cast<const char*>(header_->overlay_path), arraysize(header_->overlay_path)); @@ -212,7 +217,8 @@ LoadedIdmap::LoadedIdmap(const Idmap_header* header, target_apk_path_.assign(reinterpret_cast<const char*>(header_->target_path), length); } -std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_data) { +std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_path, + const StringPiece& idmap_data) { ATRACE_CALL(); if (!IsValidIdmapHeader(idmap_data)) { return {}; @@ -275,10 +281,14 @@ std::unique_ptr<const LoadedIdmap> LoadedIdmap::Load(const StringPiece& idmap_da // Can't use make_unique because LoadedIdmap constructor is private. std::unique_ptr<LoadedIdmap> loaded_idmap = std::unique_ptr<LoadedIdmap>( - new LoadedIdmap(header, data_header, target_entries, overlay_entries, - idmap_string_pool.release())); + new LoadedIdmap(idmap_path.to_string(), getFileModDate(idmap_path.data()), header, + data_header, target_entries, overlay_entries, idmap_string_pool.release())); return std::move(loaded_idmap); } +bool LoadedIdmap::IsUpToDate() const { + return idmap_last_mod_time_ == getFileModDate(idmap_path_.c_str()); +} + } // namespace android diff --git a/libs/androidfw/include/androidfw/Idmap.h b/libs/androidfw/include/androidfw/Idmap.h index ccb57f373473..ecc1ce65d124 100644 --- a/libs/androidfw/include/androidfw/Idmap.h +++ b/libs/androidfw/include/androidfw/Idmap.h @@ -142,7 +142,13 @@ class IdmapResMap { class LoadedIdmap { public: // Loads an IDMAP from a chunk of memory. Returns nullptr if the IDMAP data was malformed. - static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_data); + static std::unique_ptr<const LoadedIdmap> Load(const StringPiece& idmap_path, + const StringPiece& idmap_data); + + // Returns the path to the IDMAP. + inline const std::string& IdmapPath() const { + return idmap_path_; + } // Returns the path to the RRO (Runtime Resource Overlay) APK for which this IDMAP was generated. inline const std::string& OverlayApkPath() const { @@ -167,6 +173,10 @@ class LoadedIdmap { return OverlayDynamicRefTable(data_header_, overlay_entries_, target_assigned_package_id); } + // Returns whether the idmap file on disk has not been modified since the construction of this + // LoadedIdmap. + bool IsUpToDate() const; + protected: // Exposed as protected so that tests can subclass and mock this class out. LoadedIdmap() = default; @@ -177,13 +187,17 @@ class LoadedIdmap { const Idmap_overlay_entry* overlay_entries_; const std::unique_ptr<ResStringPool> string_pool_; + const std::string idmap_path_; std::string overlay_apk_path_; std::string target_apk_path_; + const time_t idmap_last_mod_time_; private: DISALLOW_COPY_AND_ASSIGN(LoadedIdmap); - explicit LoadedIdmap(const Idmap_header* header, + explicit LoadedIdmap(std::string&& idmap_path, + time_t last_mod_time, + const Idmap_header* header, const Idmap_data_header* data_header, const Idmap_target_entry* target_entries, const Idmap_overlay_entry* overlay_entries, diff --git a/libs/androidfw/tests/Idmap_test.cpp b/libs/androidfw/tests/Idmap_test.cpp index 41ba637da5d7..7aa0dbbafab3 100644 --- a/libs/androidfw/tests/Idmap_test.cpp +++ b/libs/androidfw/tests/Idmap_test.cpp @@ -38,7 +38,7 @@ class IdmapTest : public ::testing::Test { protected: void SetUp() override { // Move to the test data directory so the idmap can locate the overlay APK. - std::string original_path = base::GetExecutableDirectory(); + original_path = base::GetExecutableDirectory(); chdir(GetTestDataPath().c_str()); system_assets_ = ApkAssets::Load("system/system.apk"); @@ -49,10 +49,14 @@ class IdmapTest : public ::testing::Test { overlayable_assets_ = ApkAssets::Load("overlayable/overlayable.apk"); ASSERT_NE(nullptr, overlayable_assets_); + } + + void TearDown() override { chdir(original_path.c_str()); } protected: + std::string original_path; std::unique_ptr<const ApkAssets> system_assets_; std::unique_ptr<const ApkAssets> overlay_assets_; std::unique_ptr<const ApkAssets> overlayable_assets_; @@ -221,8 +225,7 @@ TEST_F(IdmapTest, OverlaidResourceHasSameName) { TEST_F(IdmapTest, OverlayLoaderInterop) { std::string contents; - auto loader_assets = ApkAssets::LoadTable(GetTestDataPath() + "/loader/resources.arsc", - PROPERTY_LOADER); + auto loader_assets = ApkAssets::LoadTable("loader/resources.arsc", PROPERTY_LOADER); AssetManager2 asset_manager; asset_manager.SetApkAssets({overlayable_assets_.get(), loader_assets.get(), @@ -241,4 +244,25 @@ TEST_F(IdmapTest, OverlayLoaderInterop) { ASSERT_EQ(GetStringFromApkAssets(asset_manager, val, cookie), "loader"); } +TEST_F(IdmapTest, OverlayAssetsIsUpToDate) { + std::string idmap_contents; + ASSERT_TRUE(base::ReadFileToString("overlay/overlay.idmap", &idmap_contents)); + + TemporaryFile temp_file; + ASSERT_TRUE(base::WriteStringToFile(idmap_contents, temp_file.path)); + + auto apk_assets = ApkAssets::LoadOverlay(temp_file.path); + ASSERT_NE(nullptr, apk_assets); + ASSERT_TRUE(apk_assets->IsUpToDate()); + + unlink(temp_file.path); + ASSERT_FALSE(apk_assets->IsUpToDate()); + sleep(2); + + base::WriteStringToFile("hello", temp_file.path); + sleep(2); + + ASSERT_FALSE(apk_assets->IsUpToDate()); +} + } // namespace diff --git a/media/java/android/media/tv/tuner/Tuner.java b/media/java/android/media/tv/tuner/Tuner.java index 48aed349c39a..861eeea3bc34 100644 --- a/media/java/android/media/tv/tuner/Tuner.java +++ b/media/java/android/media/tv/tuner/Tuner.java @@ -394,7 +394,7 @@ public class Tuner implements AutoCloseable { private native Lnb nativeOpenLnbByName(String name); private native Descrambler nativeOpenDescramblerByHandle(int handle); - private native Descrambler nativeOpenDemuxByhandle(int handle); + private native int nativeOpenDemuxByhandle(int handle); private native DvrRecorder nativeOpenDvrRecorder(long bufferSize); private native DvrPlayback nativeOpenDvrPlayback(long bufferSize); @@ -985,7 +985,7 @@ public class Tuner implements AutoCloseable { boolean granted = mTunerResourceManager.requestDescrambler(request, descramblerHandle); if (granted) { mDescramblerHandle = descramblerHandle[0]; - nativeOpenDescramblerByHandle(mDescramblerHandle); + mDescrambler = nativeOpenDescramblerByHandle(mDescramblerHandle); } return granted; } diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp index fc9b91c76a4f..a31f177d66ab 100644 --- a/media/jni/android_media_MediaCodec.cpp +++ b/media/jni/android_media_MediaCodec.cpp @@ -676,8 +676,6 @@ status_t JMediaCodec::getOutputFrame( if (buffer->size() > 0) { std::shared_ptr<C2Buffer> c2Buffer = buffer->asC2Buffer(); if (c2Buffer) { - // asC2Buffer clears internal reference, so set the reference again. - buffer->copy(c2Buffer); switch (c2Buffer->data().type()) { case C2BufferData::LINEAR: { std::unique_ptr<JMediaCodecLinearBlock> context{new JMediaCodecLinearBlock}; @@ -2526,7 +2524,7 @@ static void android_media_MediaCodec_setAudioPresentation( codec->selectAudioPresentation((int32_t)presentationId, (int32_t)programId); } -static void android_media_MediaCodec_native_init(JNIEnv *env) { +static void android_media_MediaCodec_native_init(JNIEnv *env, jclass) { ScopedLocalRef<jclass> clazz( env, env->FindClass("android/media/MediaCodec")); CHECK(clazz.get() != NULL); @@ -2983,7 +2981,7 @@ static void android_media_MediaCodec_LinearBlock_native_obtain( } static jboolean android_media_MediaCodec_LinearBlock_checkCompatible( - JNIEnv *env, jobjectArray codecNames) { + JNIEnv *env, jclass, jobjectArray codecNames) { std::vector<std::string> names; PopulateNamesVector(env, codecNames, &names); bool isCompatible = false; diff --git a/media/jni/android_media_tv_Tuner.cpp b/media/jni/android_media_tv_Tuner.cpp index ac7fe5d0403d..7579ca58b37b 100644 --- a/media/jni/android_media_tv_Tuner.cpp +++ b/media/jni/android_media_tv_Tuner.cpp @@ -880,10 +880,12 @@ jobject JTuner::getFrontendIds() { jobject JTuner::openFrontendById(int id) { sp<IFrontend> fe; - mTuner->openFrontendById(id, [&](Result, const sp<IFrontend>& frontend) { + Result res; + mTuner->openFrontendById(id, [&](Result r, const sp<IFrontend>& frontend) { fe = frontend; + res = r; }); - if (fe == nullptr) { + if (res != Result::SUCCESS || fe == nullptr) { ALOGE("Failed to open frontend"); return NULL; } @@ -906,7 +908,7 @@ jobject JTuner::openFrontendById(int id) { (jint) jId); } -jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AnalogFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -915,7 +917,7 @@ jobject JTuner::getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabil return env->NewObject(clazz, capsInit, typeCap, sifStandardCap); } -jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Atsc3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIII)V"); @@ -930,7 +932,7 @@ jobject JTuner::getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabili codeRateCap, fecCap, demodOutputFormatCap); } -jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/AtscFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(I)V"); @@ -939,7 +941,7 @@ jobject JTuner::getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap); } -jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbcFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(III)V"); @@ -950,7 +952,7 @@ jobject JTuner::getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap, fecCap, annexCap); } -jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IJI)V"); @@ -961,7 +963,7 @@ jobject JTuner::getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit return env->NewObject(clazz, capsInit, modulationCap, innerfecCap, standard); } -jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/DvbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIIIIZZ)V"); @@ -978,7 +980,7 @@ jobject JTuner::getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilit coderateCap, hierarchyCap, guardIntervalCap, isT2Supported, isMisoSupported); } -jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/Isdbs3FrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -988,7 +990,7 @@ jobject JTuner::getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabil return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } -jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbsFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(II)V"); @@ -998,7 +1000,7 @@ jobject JTuner::getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabili return env->NewObject(clazz, capsInit, modulationCap, coderateCap); } -jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps) { +jobject JTuner::getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps) { jclass clazz = env->FindClass("android/media/tv/tuner/frontend/IsdbtFrontendCapabilities"); jmethodID capsInit = env->GetMethodID(clazz, "<init>", "(IIIII)V"); @@ -1044,31 +1046,58 @@ jobject JTuner::getFrontendInfo(int id) { jobject jcaps = NULL; switch(feInfo.type) { case FrontendType::ANALOG: - jcaps = getAnalogFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::analogCaps + == caps.getDiscriminator()) { + jcaps = getAnalogFrontendCaps(env, caps); + } break; case FrontendType::ATSC3: - jcaps = getAtsc3FrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atsc3Caps + == caps.getDiscriminator()) { + jcaps = getAtsc3FrontendCaps(env, caps); + } break; case FrontendType::ATSC: - jcaps = getAtscFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::atscCaps + == caps.getDiscriminator()) { + jcaps = getAtscFrontendCaps(env, caps); + } break; case FrontendType::DVBC: - jcaps = getDvbcFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbcCaps + == caps.getDiscriminator()) { + jcaps = getDvbcFrontendCaps(env, caps); + } break; case FrontendType::DVBS: - jcaps = getDvbsFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbsCaps + == caps.getDiscriminator()) { + jcaps = getDvbsFrontendCaps(env, caps); + } break; case FrontendType::DVBT: - jcaps = getDvbtFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::dvbtCaps + == caps.getDiscriminator()) { + jcaps = getDvbtFrontendCaps(env, caps); + } break; case FrontendType::ISDBS: - jcaps = getIsdbsFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbsCaps + == caps.getDiscriminator()) { + jcaps = getIsdbsFrontendCaps(env, caps); + } break; case FrontendType::ISDBS3: - jcaps = getIsdbs3FrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbs3Caps + == caps.getDiscriminator()) { + jcaps = getIsdbs3FrontendCaps(env, caps); + } break; case FrontendType::ISDBT: - jcaps = getIsdbtFrontendCaps(env, caps); + if (FrontendInfo::FrontendCapabilities::hidl_discriminator::isdbtCaps + == caps.getDiscriminator()) { + jcaps = getIsdbtFrontendCaps(env, caps); + } break; default: break; @@ -2308,7 +2337,7 @@ static void android_media_tv_Tuner_native_init(JNIEnv *env) { gFields.dvrPlaybackContext = env->GetFieldID(dvrPlaybackClazz, "mNativeContext", "J"); gFields.dvrPlaybackInitID = env->GetMethodID(dvrPlaybackClazz, "<init>", "()V"); gFields.onDvrPlaybackStatusID = - env->GetMethodID(dvrRecorderClazz, "onPlaybackStatusChanged", "(I)V"); + env->GetMethodID(dvrPlaybackClazz, "onPlaybackStatusChanged", "(I)V"); jclass linearBlockClazz = env->FindClass("android/media/MediaCodec$LinearBlock"); gFields.linearBlockInitID = env->GetMethodID(linearBlockClazz, "<init>", "()V"); @@ -3101,6 +3130,11 @@ static jobject android_media_tv_Tuner_get_demux_caps(JNIEnv* env, jobject thiz) return tuner->getDemuxCaps(); } +static jint android_media_tv_Tuner_open_demux(JNIEnv* env, jobject thiz, jint /* handle */) { + sp<JTuner> tuner = getTuner(env, thiz); + return (jint) tuner->openDemux(); +} + static jint android_media_tv_Tuner_attach_filter(JNIEnv *env, jobject dvr, jobject filter) { sp<Dvr> dvrSp = getDvr(env, dvr); if (dvrSp == NULL) { @@ -3425,6 +3459,7 @@ static const JNINativeMethod gTunerMethods[] = { (void *)android_media_tv_Tuner_open_dvr_playback }, { "nativeGetDemuxCapabilities", "()Landroid/media/tv/tuner/DemuxCapabilities;", (void *)android_media_tv_Tuner_get_demux_caps }, + { "nativeOpenDemuxByhandle", "(I)I", (void *)android_media_tv_Tuner_open_demux }, }; static const JNINativeMethod gFilterMethods[] = { diff --git a/media/jni/android_media_tv_Tuner.h b/media/jni/android_media_tv_Tuner.h index 73fc38dbdec8..6749ba085739 100644 --- a/media/jni/android_media_tv_Tuner.h +++ b/media/jni/android_media_tv_Tuner.h @@ -188,9 +188,9 @@ struct JTuner : public RefBase { jobject openDvr(DvrType type, jlong bufferSize); jobject getDemuxCaps(); jobject getFrontendStatus(jintArray types); + Result openDemux(); protected: - Result openDemux(); virtual ~JTuner(); private: @@ -204,15 +204,15 @@ private: sp<ILnb> mLnb; sp<IDemux> mDemux; uint32_t mDemuxId; - static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); - static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities caps); + static jobject getAnalogFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getAtsc3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getAtscFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbcFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getDvbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbs3FrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbsFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); + static jobject getIsdbtFrontendCaps(JNIEnv *env, FrontendInfo::FrontendCapabilities& caps); }; } // namespace android diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml index 062f7bd8615e..d105e4415ca3 100644 --- a/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_bouncer.xml @@ -18,15 +18,14 @@ Car has solid black background instead of a transparent one --> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:layout_width="match_parent" - android:layout_height="match_parent" - android:background="@android:color/black" - android:fitsSystemWindows="true"> + android:layout_width="match_parent" + android:layout_height="match_parent" + android:background="@android:color/black" + android:fitsSystemWindows="true"> <include style="@style/BouncerSecurityContainer" layout="@layout/keyguard_host_view" android:layout_width="wrap_content" android:layout_height="wrap_content" /> -</FrameLayout> - +</FrameLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml b/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml new file mode 100644 index 000000000000..3e35df9d9b0c --- /dev/null +++ b/packages/CarSystemUI/res-keyguard/layout/keyguard_container.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?><!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License. + --> + +<!-- Car customizations + Car has solid black background instead of a transparent one +--> +<LinearLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/keyguard_container" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:gravity="center"/>
\ No newline at end of file diff --git a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml index 6ecab5182f13..534c51e0febe 100644 --- a/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml +++ b/packages/CarSystemUI/res/layout/car_fullscreen_user_switcher.xml @@ -18,7 +18,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/fullscreen_user_switcher" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + android:background="@color/car_user_switcher_background_color"> <LinearLayout android:id="@+id/container" diff --git a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml index 067e359e0e49..35423231bb97 100644 --- a/packages/CarSystemUI/res/layout/sysui_overlay_window.xml +++ b/packages/CarSystemUI/res/layout/sysui_overlay_window.xml @@ -29,6 +29,11 @@ android:layout="@layout/notification_panel_container" android:layout_marginBottom="@dimen/navigation_bar_height"/> + <ViewStub android:id="@+id/keyguard_stub" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/keyguard_container" /> + <ViewStub android:id="@+id/fullscreen_user_switcher_stub" android:layout_width="match_parent" android:layout_height="match_parent" diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml index 0b56d05cc66f..bf1bf38cdb92 100644 --- a/packages/CarSystemUI/res/values/config.xml +++ b/packages/CarSystemUI/res/values/config.xml @@ -71,8 +71,9 @@ <!-- Car System UI's OverlayViewsMediator--> <string-array name="config_carSystemUIOverlayViewsMediators" translatable="false"> - <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item> <item>com.android.systemui.car.notification.NotificationPanelViewMediator</item> + <item>com.android.systemui.car.keyguard.CarKeyguardViewMediator</item> + <item>com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator</item> </string-array> <!-- SystemUI Services: The classes of the stuff to start. --> diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java index c275536e4d92..4ea48ba24fa9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java @@ -24,6 +24,7 @@ import android.content.Context; import com.android.keyguard.KeyguardViewController; import com.android.systemui.car.CarDeviceProvisionedController; import com.android.systemui.car.CarDeviceProvisionedControllerImpl; +import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.dagger.SystemUIRootComponent; import com.android.systemui.dock.DockManager; import com.android.systemui.dock.DockManagerImpl; @@ -146,7 +147,7 @@ public abstract class CarSystemUIModule { @Binds abstract KeyguardViewController bindKeyguardViewController( - CarStatusBarKeyguardViewManager keyguardViewManager); + CarKeyguardViewController carKeyguardViewController); @Binds abstract DeviceProvisionedController bindDeviceProvisionedController( diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java new file mode 100644 index 000000000000..707ee4fed84d --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -0,0 +1,369 @@ +/* + * 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.keyguard; + +import android.car.Car; +import android.car.user.CarUserManager; +import android.content.Context; +import android.os.Bundle; +import android.os.Handler; +import android.util.Log; +import android.view.View; +import android.view.ViewGroup; +import android.view.ViewRootImpl; + +import com.android.internal.widget.LockPatternUtils; +import com.android.keyguard.KeyguardUpdateMonitor; +import com.android.keyguard.KeyguardViewController; +import com.android.keyguard.ViewMediatorCallback; +import com.android.systemui.R; +import com.android.systemui.SystemUIFactory; +import com.android.systemui.car.CarServiceProvider; +import com.android.systemui.dagger.qualifiers.Main; +import com.android.systemui.keyguard.DismissCallbackRegistry; +import com.android.systemui.navigationbar.car.CarNavigationBarController; +import com.android.systemui.plugins.FalsingManager; +import com.android.systemui.statusbar.phone.BiometricUnlockController; +import com.android.systemui.statusbar.phone.KeyguardBouncer; +import com.android.systemui.statusbar.phone.KeyguardBypassController; +import com.android.systemui.statusbar.phone.NotificationPanelViewController; +import com.android.systemui.statusbar.phone.StatusBar; +import com.android.systemui.statusbar.policy.KeyguardStateController; +import com.android.systemui.window.OverlayViewController; +import com.android.systemui.window.OverlayViewGlobalStateController; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Automotive implementation of the {@link KeyguardViewController}. It controls the Keyguard View + * that is mounted to the SystemUIOverlayWindow. + */ +@Singleton +public class CarKeyguardViewController extends OverlayViewController implements + KeyguardViewController { + private static final String TAG = "CarKeyguardViewController"; + private static final boolean DEBUG = true; + + private final Context mContext; + private final Handler mHandler; + private final CarServiceProvider mCarServiceProvider; + private final KeyguardStateController mKeyguardStateController; + private final KeyguardUpdateMonitor mKeyguardUpdateMonitor; + private final LockPatternUtils mLockPatternUtils; + private final FalsingManager mFalsingManager; + private final KeyguardBypassController mKeyguardBypassController; + private final DismissCallbackRegistry mDismissCallbackRegistry; + private final ViewMediatorCallback mViewMediatorCallback; + private final CarNavigationBarController mCarNavigationBarController; + // Needed to instantiate mBouncer. + private final KeyguardBouncer.BouncerExpansionCallback + mExpansionCallback = new KeyguardBouncer.BouncerExpansionCallback() { + @Override + public void onFullyShown() { + } + + @Override + public void onStartingToHide() { + } + + @Override + public void onStartingToShow() { + } + + @Override + public void onFullyHidden() { + } + }; + private final CarUserManager.UserLifecycleListener mUserLifecycleListener = (e) -> { + if (e.getEventType() == CarUserManager.USER_LIFECYCLE_EVENT_TYPE_UNLOCKED) { + revealKeyguardIfBouncerPrepared(); + } + }; + + private KeyguardBouncer mBouncer; + private OnKeyguardCancelClickedListener mKeyguardCancelClickedListener; + private boolean mShowing; + + @Inject + public CarKeyguardViewController( + Context context, + @Main Handler mainHandler, + CarServiceProvider carServiceProvider, + OverlayViewGlobalStateController overlayViewGlobalStateController, + KeyguardStateController keyguardStateController, + KeyguardUpdateMonitor keyguardUpdateMonitor, + BiometricUnlockController biometricUnlockController, + ViewMediatorCallback viewMediatorCallback, + CarNavigationBarController carNavigationBarController, + /* The params below are only used to reuse KeyguardBouncer */ + LockPatternUtils lockPatternUtils, + DismissCallbackRegistry dismissCallbackRegistry, + FalsingManager falsingManager, + KeyguardBypassController keyguardBypassController) { + + super(R.id.keyguard_stub, overlayViewGlobalStateController); + + mContext = context; + mHandler = mainHandler; + mCarServiceProvider = carServiceProvider; + mKeyguardStateController = keyguardStateController; + mKeyguardUpdateMonitor = keyguardUpdateMonitor; + mLockPatternUtils = lockPatternUtils; + mFalsingManager = falsingManager; + mKeyguardBypassController = keyguardBypassController; + mDismissCallbackRegistry = dismissCallbackRegistry; + mViewMediatorCallback = viewMediatorCallback; + mCarNavigationBarController = carNavigationBarController; + + biometricUnlockController.setKeyguardViewController(this); + registerUserSwitchedListener(); + } + + @Override + public void onFinishInflate() { + mBouncer = SystemUIFactory.getInstance().createKeyguardBouncer(mContext, + mViewMediatorCallback, mLockPatternUtils, + getLayout().findViewById(R.id.keyguard_container), mDismissCallbackRegistry, + mExpansionCallback, mKeyguardStateController, mFalsingManager, + mKeyguardBypassController); + } + + @Override + public void notifyKeyguardAuthenticated(boolean strongAuth) { + mBouncer.notifyKeyguardAuthenticated(strongAuth); + } + + @Override + public void showBouncer(boolean scrimmed) { + if (mShowing && !mBouncer.isShowing()) { + mBouncer.show(/* resetSecuritySelection= */ false); + } + } + + @Override + public void show(Bundle options) { + if (mShowing) return; + + mShowing = true; + mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false); + mCarNavigationBarController.showAllKeyguardButtons(/* isSetUp= */ true); + start(); + reset(/* hideBouncerWhenShowing= */ false); + notifyKeyguardUpdateMonitor(); + } + + @Override + public void hide(long startTime, long fadeoutDuration) { + if (!mShowing) return; + + mViewMediatorCallback.readyForKeyguardDone(); + mShowing = false; + mKeyguardStateController.notifyKeyguardState(mShowing, /* occluded= */ false); + mBouncer.hide(/* destroyView= */ true); + mCarNavigationBarController.hideAllKeyguardButtons(/* isSetUp= */ true); + stop(); + mKeyguardStateController.notifyKeyguardDoneFading(); + mViewMediatorCallback.keyguardGone(); + notifyKeyguardUpdateMonitor(); + } + + @Override + public void reset(boolean hideBouncerWhenShowing) { + if (mShowing) { + if (mBouncer != null) { + if (!mBouncer.isSecure()) { + dismissAndCollapse(); + } + mBouncer.show(/* resetSecuritySelection= */ true); + } + mKeyguardUpdateMonitor.sendKeyguardReset(); + notifyKeyguardUpdateMonitor(); + } + } + + @Override + public void onFinishedGoingToSleep() { + mBouncer.onScreenTurnedOff(); + } + + @Override + public void onCancelClicked() { + mBouncer.hide(/* destroyView= */ true); + mKeyguardCancelClickedListener.onCancelClicked(); + } + + @Override + public boolean isShowing() { + return mShowing; + } + + @Override + public void dismissAndCollapse() { + hide(/* startTime= */ 0, /* fadeoutDuration= */ 0); + } + + @Override + public void startPreHideAnimation(Runnable finishRunnable) { + mBouncer.startPreHideAnimation(finishRunnable); + } + + @Override + public void setNeedsInput(boolean needsInput) { + getLayout().setFocusable(needsInput); + } + + /** + * Add listener for keyguard cancel clicked. + */ + public void registerOnKeyguardCancelClickedListener( + OnKeyguardCancelClickedListener keyguardCancelClickedListener) { + mKeyguardCancelClickedListener = keyguardCancelClickedListener; + } + + /** + * Remove listener for keyguard cancel clicked. + */ + public void unregisterOnKeyguardCancelClickedListener( + OnKeyguardCancelClickedListener keyguardCancelClickedListener) { + mKeyguardCancelClickedListener = null; + } + + @Override + public ViewRootImpl getViewRootImpl() { + return ((View) getLayout().getParent()).getViewRootImpl(); + } + + @Override + public boolean isBouncerShowing() { + return mBouncer.isShowing(); + } + + @Override + public boolean bouncerIsOrWillBeShowing() { + return mBouncer.isShowing() || mBouncer.inTransit(); + } + + @Override + public void keyguardGoingAway() { + // no-op + } + + @Override + public void onStartedGoingToSleep() { + // no-op + } + + @Override + public void onStartedWakingUp() { + // no-op + } + + @Override + public void onScreenTurningOn() { + // no-op + } + + @Override + public void onScreenTurnedOn() { + // no-op + } + + @Override + public void setOccluded(boolean occluded, boolean animate) { + // no-op + } + + @Override + public boolean shouldDisableWindowAnimationsForUnlock() { + return false; + } + + @Override + public boolean isGoingToNotificationShade() { + return false; + } + + @Override + public boolean isUnlockWithWallpaper() { + return false; + } + + @Override + public boolean shouldSubtleWindowAnimationsForUnlock() { + return false; + } + + @Override + public void registerStatusBar(StatusBar statusBar, ViewGroup container, + NotificationPanelViewController notificationPanelViewController, + BiometricUnlockController biometricUnlockController, + DismissCallbackRegistry dismissCallbackRegistry, ViewGroup lockIconContainer, + View notificationContainer, KeyguardBypassController bypassController, + FalsingManager falsingManager) { + // no-op + } + + /** + * Hides Keyguard so that the transitioning Bouncer can be hidden until it is prepared. To be + * called by {@link com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator} + * when a new user is selected. + */ + public void hideKeyguardToPrepareBouncer() { + getLayout().setVisibility(View.INVISIBLE); + } + + private void revealKeyguardIfBouncerPrepared() { + int reattemptDelayMillis = 50; + Runnable revealKeyguard = () -> { + if (!mBouncer.inTransit() || !mBouncer.isSecure()) { + getLayout().setVisibility(View.VISIBLE); + } else { + if (DEBUG) { + Log.d(TAG, "revealKeyguardIfBouncerPrepared: Bouncer is not prepared " + + "yet so reattempting after " + reattemptDelayMillis + "ms."); + } + mHandler.postDelayed(this::revealKeyguardIfBouncerPrepared, reattemptDelayMillis); + } + }; + mHandler.post(revealKeyguard); + } + + private void notifyKeyguardUpdateMonitor() { + mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(mShowing); + if (mBouncer != null) { + mKeyguardUpdateMonitor.sendKeyguardBouncerChanged(isBouncerShowing()); + } + } + + private void registerUserSwitchedListener() { + mCarServiceProvider.addListener(car -> { + CarUserManager userManager = (CarUserManager) car.getCarManager(Car.CAR_USER_SERVICE); + userManager.addListener(Runnable::run, mUserLifecycleListener); + }); + } + + /** + * Defines a callback for keyguard cancel button clicked listeners. + */ + public interface OnKeyguardCancelClickedListener { + /** + * Called when keyguard cancel button is clicked. + */ + void onCancelClicked(); + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java new file mode 100644 index 000000000000..db0f5d82e210 --- /dev/null +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewMediator.java @@ -0,0 +1,54 @@ +/* + * 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.keyguard; + +import com.android.systemui.car.userswitcher.FullScreenUserSwitcherViewController; +import com.android.systemui.window.OverlayViewMediator; + +import javax.inject.Inject; +import javax.inject.Singleton; + +/** + * Manages events originating from the Keyguard service that cause Keyguard or other OverlayWindow + * Components to appear or disappear. + */ +@Singleton +public class CarKeyguardViewMediator implements OverlayViewMediator { + + private final CarKeyguardViewController mCarKeyguardViewController; + private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController; + + @Inject + public CarKeyguardViewMediator( + CarKeyguardViewController carKeyguardViewController, + FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController + ) { + mCarKeyguardViewController = carKeyguardViewController; + mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController; + } + + @Override + public void registerListeners() { + mCarKeyguardViewController.registerOnKeyguardCancelClickedListener( + mFullScreenUserSwitcherViewController::start); + } + + @Override + public void setupOverlayContentViewControllers() { + // no-op + } +} diff --git a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java index 50e43bea65eb..149531f75029 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/userswitcher/FullscreenUserSwitcherViewMediator.java @@ -16,20 +16,9 @@ package com.android.systemui.car.userswitcher; -import android.content.BroadcastReceiver; -import android.content.Context; -import android.content.Intent; -import android.content.IntentFilter; -import android.content.res.Resources; -import android.os.Handler; - -import com.android.systemui.R; -import com.android.systemui.dagger.qualifiers.Main; -import com.android.systemui.keyguard.ScreenLifecycle; +import com.android.systemui.car.keyguard.CarKeyguardViewController; import com.android.systemui.plugins.statusbar.StatusBarStateController; import com.android.systemui.statusbar.StatusBarState; -import com.android.systemui.statusbar.car.CarStatusBar; -import com.android.systemui.statusbar.car.CarStatusBarKeyguardViewManager; import com.android.systemui.window.OverlayViewMediator; import javax.inject.Inject; @@ -42,47 +31,24 @@ import javax.inject.Singleton; public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator { private static final String TAG = FullscreenUserSwitcherViewMediator.class.getSimpleName(); - private final Context mContext; - private final CarStatusBarKeyguardViewManager mCarStatusBarKeyguardViewManager; - private final Handler mMainHandler; private final StatusBarStateController mStatusBarStateController; private final FullScreenUserSwitcherViewController mFullScreenUserSwitcherViewController; - private final ScreenLifecycle mScreenLifecycle; - private final CarStatusBar mCarStatusBar; - private final boolean mIsUserSwitcherEnabled; + private final CarKeyguardViewController mCarKeyguardViewController; @Inject public FullscreenUserSwitcherViewMediator( - Context context, - @Main Resources resources, - @Main Handler mainHandler, - CarStatusBarKeyguardViewManager carStatusBarKeyguardViewManager, - CarStatusBar carStatusBar, StatusBarStateController statusBarStateController, - FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController, - ScreenLifecycle screenLifecycle) { - mContext = context; - - mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher); + CarKeyguardViewController carKeyguardViewController, + FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) { - mMainHandler = mainHandler; - - mCarStatusBarKeyguardViewManager = carStatusBarKeyguardViewManager; - mCarStatusBar = carStatusBar; mStatusBarStateController = statusBarStateController; mFullScreenUserSwitcherViewController = fullScreenUserSwitcherViewController; - mScreenLifecycle = screenLifecycle; + mCarKeyguardViewController = carKeyguardViewController; } @Override public void registerListeners() { - registerUserSwitcherShowListeners(); registerUserSwitcherHideListeners(); - registerHideKeyguardListeners(); - } - - private void registerUserSwitcherShowListeners() { - mCarStatusBarKeyguardViewManager.addOnKeyguardCancelClickedListener(this::show); } private void registerUserSwitcherHideListeners() { @@ -97,37 +63,6 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator { }); } - private void registerHideKeyguardListeners() { - mStatusBarStateController.addCallback(new StatusBarStateController.StateListener() { - @Override - public void onStateChanged(int newState) { - if (newState != StatusBarState.FULLSCREEN_USER_SWITCHER) { - return; - } - dismissKeyguardWhenUserSwitcherNotDisplayed(newState); - } - }); - - mScreenLifecycle.addObserver(new ScreenLifecycle.Observer() { - @Override - public void onScreenTurnedOn() { - dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState()); - } - }); - - mContext.registerReceiver(new BroadcastReceiver() { - @Override - public void onReceive(Context context, Intent intent) { - if (!intent.getAction().equals(Intent.ACTION_USER_SWITCHED)) { - return; - } - - // Try to dismiss the keyguard after every user switch. - dismissKeyguardWhenUserSwitcherNotDisplayed(mStatusBarStateController.getState()); - } - }, new IntentFilter(Intent.ACTION_USER_SWITCHED)); - } - @Override public void setupOverlayContentViewControllers() { mFullScreenUserSwitcherViewController.setUserGridSelectionListener(this::onUserSelected); @@ -135,33 +70,13 @@ public class FullscreenUserSwitcherViewMediator implements OverlayViewMediator { /** * Every time user clicks on an item in the switcher, we hide the switcher. - * - * We dismiss the entire keyguard if user clicked on the foreground user (user we're already - * logged in as). */ private void onUserSelected(UserGridRecyclerView.UserRecord record) { - hide(); - if (record.mType == UserGridRecyclerView.UserRecord.FOREGROUND_USER) { - mCarStatusBar.dismissKeyguard(); - } - } - - // We automatically dismiss keyguard unless user switcher is being shown above the keyguard. - private void dismissKeyguardWhenUserSwitcherNotDisplayed(int state) { - if (!mIsUserSwitcherEnabled) { - return; // Not using the full screen user switcher. + if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) { + mCarKeyguardViewController.hideKeyguardToPrepareBouncer(); } - if (state == StatusBarState.FULLSCREEN_USER_SWITCHER - && !mFullScreenUserSwitcherViewController.isVisible()) { - // Current execution path continues to set state after this, thus we deffer the - // dismissal to the next execution cycle. - - // Dismiss the keyguard if switcher is not visible. - // TODO(b/150402329): Remove once keyguard is implemented using Overlay Window - // abstractions. - mMainHandler.post(mCarStatusBar::dismissKeyguard); - } + hide(); } private void hide() { diff --git a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java index dd29f8dac387..6b4f3e37bc18 100644 --- a/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java +++ b/packages/CarSystemUI/src/com/android/systemui/window/OverlayWindowModule.java @@ -16,6 +16,7 @@ package com.android.systemui.window; +import com.android.systemui.car.keyguard.CarKeyguardViewMediator; import com.android.systemui.car.notification.NotificationPanelViewMediator; import com.android.systemui.car.userswitcher.FullscreenUserSwitcherViewMediator; @@ -29,12 +30,6 @@ import dagger.multibindings.IntoMap; */ @Module public abstract class OverlayWindowModule { - /** Injects FullscreenUserSwitcherViewsMediator. */ - @Binds - @IntoMap - @ClassKey(FullscreenUserSwitcherViewMediator.class) - public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator( - FullscreenUserSwitcherViewMediator overlayViewsMediator); /** Injects NotificationPanelViewMediator. */ @Binds @@ -42,4 +37,18 @@ public abstract class OverlayWindowModule { @ClassKey(NotificationPanelViewMediator.class) public abstract OverlayViewMediator bindNotificationPanelViewMediator( NotificationPanelViewMediator notificationPanelViewMediator); + + /** Inject into CarKeyguardViewMediator. */ + @Binds + @IntoMap + @ClassKey(CarKeyguardViewMediator.class) + public abstract OverlayViewMediator bindCarKeyguardViewMediator( + CarKeyguardViewMediator carKeyguardViewMediator); + + /** Injects FullscreenUserSwitcherViewsMediator. */ + @Binds + @IntoMap + @ClassKey(FullscreenUserSwitcherViewMediator.class) + public abstract OverlayViewMediator bindFullscreenUserSwitcherViewsMediator( + FullscreenUserSwitcherViewMediator overlayViewsMediator); } diff --git a/packages/CarrierDefaultApp/res/values-hu/strings.xml b/packages/CarrierDefaultApp/res/values-hu/strings.xml index 4ae6ea67bb06..a492e47242af 100644 --- a/packages/CarrierDefaultApp/res/values-hu/strings.xml +++ b/packages/CarrierDefaultApp/res/values-hu/strings.xml @@ -8,7 +8,7 @@ <string name="portal_notification_detail" msgid="2295729385924660881">"Koppintson a(z) %s webhely meglátogatásához"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"Vegye fel a kapcsolatot szolgáltatójával (%s)"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Nincs mobiladat-kapcsolat"</string> - <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy barangolási csomagot a következőn keresztül: %s"</string> + <string name="no_mobile_data_connection" msgid="544980465184147010">"Adjon hozzá előfizetést vagy roamingcsomagot a következőn keresztül: %s"</string> <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Mobiladat-állapot"</string> <string name="action_bar_label" msgid="4290345990334377177">"Bejelentkezés a mobilhálózatra"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Biztonsági problémák vannak azzal a hálózattal, amelyhez csatlakozni szeretne."</string> diff --git a/packages/CarrierDefaultApp/res/values-ky/strings.xml b/packages/CarrierDefaultApp/res/values-ky/strings.xml index 199476f47be0..bf4c8c323827 100644 --- a/packages/CarrierDefaultApp/res/values-ky/strings.xml +++ b/packages/CarrierDefaultApp/res/values-ky/strings.xml @@ -8,7 +8,7 @@ <string name="portal_notification_detail" msgid="2295729385924660881">"%s сайтына баш багуу үчүн басыңыз"</string> <string name="no_data_notification_detail" msgid="3112125343857014825">"%s Интернет провайдери менен байланышыңыз"</string> <string name="no_mobile_data_connection_title" msgid="7449525772416200578">"Мобилдик Интернет жок"</string> - <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу дайындарды же роуминг планын кошуу"</string> + <string name="no_mobile_data_connection" msgid="544980465184147010">"%s аркылуу дайын-даректерди же роуминг планын кошуу"</string> <string name="mobile_data_status_notification_channel_name" msgid="833999690121305708">"Мобилдик Интернеттин абалы"</string> <string name="action_bar_label" msgid="4290345990334377177">"Мобилдик тармакка кирүү"</string> <string name="ssl_error_warning" msgid="3127935140338254180">"Кошулайын деген тармагыңызда коопсуздук көйгөйлөрү бар."</string> diff --git a/packages/PrintSpooler/tests/outofprocess/Android.bp b/packages/PrintSpooler/tests/outofprocess/Android.bp index c6dc26370ebc..0e028b04aaaf 100644 --- a/packages/PrintSpooler/tests/outofprocess/Android.bp +++ b/packages/PrintSpooler/tests/outofprocess/Android.bp @@ -27,4 +27,5 @@ android_test { sdk_version: "test_current", test_suites: ["device-tests"], + required: ["com.android.cts.helpers.aosp"], } diff --git a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml index b649e82d10bc..922d73511815 100644 --- a/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml +++ b/packages/PrintSpooler/tests/outofprocess/AndroidTest.xml @@ -18,6 +18,8 @@ <option name="test-file-name" value="PrintSpoolerOutOfProcessTests.apk" /> </target_preparer> + <target_preparer class="com.android.compatibility.common.tradefed.targetprep.DeviceInteractionHelperInstaller" /> + <option name="test-suite-tag" value="apct" /> <option name="test-tag" value="PrintSpoolerOutOfProcessTests" /> <option name="config-descriptor:metadata" key="component" value="print" /> diff --git a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java index 61c2f54a2bf9..132545b2d5d2 100644 --- a/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java +++ b/packages/PrintSpooler/tests/outofprocess/src/com/android/printspooler/outofprocess/tests/WorkflowTest.java @@ -36,6 +36,7 @@ import android.print.test.services.FirstPrintService; import android.print.test.services.PrinterDiscoverySessionCallbacks; import android.print.test.services.StubbablePrinterDiscoverySession; import android.support.test.uiautomator.By; +import android.support.test.uiautomator.UiDevice; import android.support.test.uiautomator.UiObject; import android.support.test.uiautomator.UiObjectNotFoundException; import android.support.test.uiautomator.UiSelector; @@ -78,6 +79,10 @@ public class WorkflowTest extends BasePrintTest { void accept(T t) throws InterruptedException; } + public static UiDevice getUiDevice() { + return UiDevice.getInstance(getInstrumentation()); + } + /** * Execute {@code waiter} until {@code condition} is met. * diff --git a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java index ff40d8e00603..450bdb161933 100644 --- a/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java +++ b/packages/SettingsLib/src/com/android/settingslib/location/SettingsInjector.java @@ -202,6 +202,12 @@ public class SettingsInjector { } /** + * Gives descendants a chance to log Preference click event + */ + protected void logPreferenceClick(Intent intent) { + } + + /** * Returns the settings parsed from the attributes of the * {@link SettingInjectorService#META_DATA_NAME} tag, or null. * @@ -315,6 +321,7 @@ public class SettingsInjector { // Settings > Location. Intent settingIntent = new Intent(); settingIntent.setClassName(mInfo.packageName, mInfo.settingsActivity); + logPreferenceClick(settingIntent); // Sometimes the user may navigate back to "Settings" and launch another different // injected setting after one injected setting has been launched. // diff --git a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java index 9d7e2c821297..b1234f291b74 100644 --- a/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java +++ b/packages/SettingsLib/src/com/android/settingslib/net/DataUsageUtils.java @@ -18,11 +18,15 @@ package com.android.settingslib.net; import android.content.Context; import android.net.NetworkTemplate; +import android.telephony.SubscriptionInfo; import android.telephony.SubscriptionManager; import android.telephony.TelephonyManager; import android.util.Log; import com.android.internal.util.ArrayUtils; + +import java.util.List; + /** * Utils class for data usage */ @@ -33,26 +37,42 @@ public class DataUsageUtils { * Return mobile NetworkTemplate based on {@code subId} */ public static NetworkTemplate getMobileTemplate(Context context, int subId) { - final TelephonyManager telephonyManager = context.getSystemService( - TelephonyManager.class); - final SubscriptionManager subscriptionManager = context.getSystemService( - SubscriptionManager.class); - final NetworkTemplate mobileAll = NetworkTemplate.buildTemplateMobileAll( - telephonyManager.getSubscriberId()); - - if (!subscriptionManager.isActiveSubscriptionId(subId)) { - Log.i(TAG, "Subscription is not active: " + subId); - return mobileAll; + final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class); + final int mobileDefaultSubId = telephonyManager.getSubscriptionId(); + + final SubscriptionManager subscriptionManager = + context.getSystemService(SubscriptionManager.class); + final List<SubscriptionInfo> subInfoList = + subscriptionManager.getAvailableSubscriptionInfoList(); + if (subInfoList == null) { + Log.i(TAG, "Subscription is not inited: " + subId); + return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); } - final String[] mergedSubscriberIds = telephonyManager.createForSubscriptionId(subId) - .getMergedImsisFromGroup(); + for (SubscriptionInfo subInfo : subInfoList) { + if ((subInfo != null) && (subInfo.getSubscriptionId() == subId)) { + return getNormalizedMobileTemplate(telephonyManager, subId); + } + } + Log.i(TAG, "Subscription is not active: " + subId); + return getMobileTemplateForSubId(telephonyManager, mobileDefaultSubId); + } + private static NetworkTemplate getNormalizedMobileTemplate( + TelephonyManager telephonyManager, int subId) { + final NetworkTemplate mobileTemplate = getMobileTemplateForSubId(telephonyManager, subId); + final String[] mergedSubscriberIds = telephonyManager + .createForSubscriptionId(subId).getMergedImsisFromGroup(); if (ArrayUtils.isEmpty(mergedSubscriberIds)) { Log.i(TAG, "mergedSubscriberIds is null."); - return mobileAll; + return mobileTemplate; } - return NetworkTemplate.normalize(mobileAll, mergedSubscriberIds); + return NetworkTemplate.normalize(mobileTemplate, mergedSubscriberIds); + } + + private static NetworkTemplate getMobileTemplateForSubId( + TelephonyManager telephonyManager, int subId) { + return NetworkTemplate.buildTemplateMobileAll(telephonyManager.getSubscriberId(subId)); } } diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index c6f03271f931..133d375b8c6e 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -670,7 +670,7 @@ </activity> <activity android:name=".controls.management.ControlsProviderSelectorActivity" - android:label="Controls Providers" + android:label="@string/controls_providers_title" android:theme="@style/Theme.ControlsManagement" android:showForAllUsers="true" android:clearTaskOnLaunch="true" @@ -679,6 +679,15 @@ android:visibleToInstantApps="true"> </activity> + <activity android:name=".controls.management.ControlsEditingActivity" + android:theme="@style/Theme.ControlsManagement" + android:excludeFromRecents="true" + android:showForAllUsers="true" + android:finishOnTaskLaunch="true" + android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden" + android:visibleToInstantApps="true"> + </activity> + <activity android:name=".controls.management.ControlsFavoritingActivity" android:theme="@style/Theme.ControlsManagement" android:excludeFromRecents="true" diff --git a/packages/SystemUI/res/anim/bottomsheet_in.xml b/packages/SystemUI/res/anim/bottomsheet_in.xml new file mode 100644 index 000000000000..0d5efeb2be1e --- /dev/null +++ b/packages/SystemUI/res/anim/bottomsheet_in.xml @@ -0,0 +1,26 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> + +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@*android:anim/accelerate_decelerate_interpolator" + android:zAdjustment="top"> + + <translate android:fromYDelta="100%" + android:toYDelta="0" + android:startOffset="@android:integer/config_shortAnimTime" + android:duration="@*android:integer/config_mediumAnimTime"/> +</set> diff --git a/packages/SystemUI/res/anim/bottomsheet_out.xml b/packages/SystemUI/res/anim/bottomsheet_out.xml new file mode 100644 index 000000000000..01f8d2d6b2a3 --- /dev/null +++ b/packages/SystemUI/res/anim/bottomsheet_out.xml @@ -0,0 +1,25 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 The Android Open Source Project + ~ + ~ Licensed under the Apache License, Version 2.0 (the "License"); + ~ you may not use this file except in compliance with the License. + ~ You may obtain a copy of the License at + ~ + ~ http://www.apache.org/licenses/LICENSE-2.0 + ~ + ~ Unless required by applicable law or agreed to in writing, software + ~ distributed under the License is distributed on an "AS IS" BASIS, + ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + ~ See the License for the specific language governing permissions and + ~ limitations under the License + --> +<set xmlns:android="http://schemas.android.com/apk/res/android" + android:interpolator="@*android:anim/accelerate_interpolator" + android:zAdjustment="top"> + + <translate xmlns:android="http://schemas.android.com/apk/res/android" + android:fromYDelta="0" + android:toYDelta="100%" + android:duration="@*android:integer/config_shortAnimTime" /> +</set> diff --git a/cmds/statsd/AndroidTest.xml b/packages/SystemUI/res/drawable/rounded_bg_top.xml index afe30a269093..988ab5874b07 100644 --- a/cmds/statsd/AndroidTest.xml +++ b/packages/SystemUI/res/drawable/rounded_bg_top.xml @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="utf-8"?> -<!-- Copyright (C) 2017 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. @@ -13,14 +13,10 @@ See the License for the specific language governing permissions and limitations under the License. --> -<configuration description="Config for statsd_test"> - <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer"> - <option name="cleanup" value="true" /> - <option name="push" value="statsd_test->/data/nativetest/statsd_test" /> - </target_preparer> - <option name="test-suite-tag" value="apct" /> - <test class="com.android.tradefed.testtype.GTest" > - <option name="native-test-device-path" value="/data/nativetest" /> - <option name="module-name" value="statsd_test" /> - </test> -</configuration>
\ No newline at end of file +<shape xmlns:android="http://schemas.android.com/apk/res/android" + android:shape="rectangle"> + <solid android:color="?android:attr/colorPrimaryDark" /> + <corners + android:topLeftRadius="?android:attr/dialogCornerRadius" + android:topRightRadius="?android:attr/dialogCornerRadius" /> +</shape> diff --git a/packages/SystemUI/res/layout/app_ops_info.xml b/packages/SystemUI/res/layout/app_ops_info.xml index bfa252c5a14b..8342a2a4a560 100644 --- a/packages/SystemUI/res/layout/app_ops_info.xml +++ b/packages/SystemUI/res/layout/app_ops_info.xml @@ -19,8 +19,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" android:id="@+id/app_ops_info" - android:clickable="true" android:clipChildren="false" android:clipToPadding="false" android:orientation="vertical" diff --git a/packages/SystemUI/res/layout/controls_base_item.xml b/packages/SystemUI/res/layout/controls_base_item.xml index db81e2348cd8..55c9083e4147 100644 --- a/packages/SystemUI/res/layout/controls_base_item.xml +++ b/packages/SystemUI/res/layout/controls_base_item.xml @@ -45,7 +45,8 @@ android:textAppearance="@style/TextAppearance.Control.Status" android:paddingTop="@dimen/control_padding_adjustment" android:paddingStart="@dimen/control_status_padding" - android:clickable="true" + android:screenReaderFocusable="false" + android:clickable="false" android:focusable="false" android:singleLine="true" android:ellipsize="marquee" diff --git a/packages/SystemUI/res/layout/controls_detail_dialog.xml b/packages/SystemUI/res/layout/controls_detail_dialog.xml index f2de45a57ff6..34b603f4bc3d 100644 --- a/packages/SystemUI/res/layout/controls_detail_dialog.xml +++ b/packages/SystemUI/res/layout/controls_detail_dialog.xml @@ -15,9 +15,76 @@ limitations under the License. --> -<FrameLayout +<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" - android:id="@+id/controls_activity_view" + android:id="@+id/control_detail_root" android:layout_width="match_parent" - android:layout_height="match_parent" /> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/controls_activity_view_top_offset" + android:orientation="vertical"> + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:orientation="horizontal" + android:layout_marginBottom="10dp"> + <ImageView + android:id="@+id/control_detail_close" + android:contentDescription="@string/accessibility_desc_close" + android:src="@drawable/ic_close" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="12dp" /> + <Space + android:layout_width="0dp" + android:layout_weight="1" + android:layout_height="1dp" /> + <ImageView + android:id="@+id/control_detail_open_in_app" + android:src="@drawable/ic_open_in_new" + android:background="?android:attr/selectableItemBackgroundBorderless" + android:tint="@color/control_primary_text" + android:layout_width="48dp" + android:layout_height="48dp" + android:padding="12dp" /> + </LinearLayout> + + <LinearLayout + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:paddingTop="@dimen/controls_activity_view_top_padding" + android:paddingLeft="@dimen/controls_activity_view_side_padding" + android:paddingRight="@dimen/controls_activity_view_side_padding" + android:background="@drawable/rounded_bg_top" + android:orientation="vertical"> + <TextView + android:id="@+id/title" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.ControlDialog" + android:clickable="false" + android:focusable="false" + android:maxLines="1" + android:ellipsize="end" /> + <TextView + android:id="@+id/subtitle" + android:layout_marginTop="6dp" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:textAppearance="@style/TextAppearance.ControlDialog" + android:clickable="false" + android:focusable="false" + android:maxLines="1" + android:ellipsize="end" /> + + <FrameLayout + android:id="@+id/controls_activity_view" + android:layout_width="match_parent" + android:layout_height="0dp" + android:layout_marginTop="10dp" + android:layout_weight="1" /> + + </LinearLayout> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_horizontal_divider_withEmpty.xml b/packages/SystemUI/res/layout/controls_horizontal_divider_withEmpty.xml new file mode 100644 index 000000000000..90b3398e3de2 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_horizontal_divider_withEmpty.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="vertical" + android:layout_width="match_parent" + android:layout_height="wrap_content" +> + + <View + android:layout_width="match_parent" + android:layout_height="@dimen/controls_management_list_margin" + /> + + <FrameLayout + android:id="@+id/frame" + android:layout_width="match_parent" + android:layout_height="@dimen/control_height" + android:visibility="gone" + > + </FrameLayout> + <View + android:id="@+id/divider" + android:layout_width="match_parent" + android:layout_height="1dp" + android:layout_marginBottom="10dp" + android:layout_marginStart="40dp" + android:layout_marginEnd="40dp" + android:background="#4dffffff" /> +</LinearLayout> diff --git a/packages/SystemUI/res/layout/controls_management.xml b/packages/SystemUI/res/layout/controls_management.xml index 9d5eb63ba795..ae57563cfb09 100644 --- a/packages/SystemUI/res/layout/controls_management.xml +++ b/packages/SystemUI/res/layout/controls_management.xml @@ -29,6 +29,8 @@ android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" + android:focusable="false" + android:clickable="false" android:gravity="center_vertical"> <FrameLayout diff --git a/packages/SystemUI/res/layout/controls_management_apps.xml b/packages/SystemUI/res/layout/controls_management_apps.xml index 42d73f3cc9ce..94df9d8f4775 100644 --- a/packages/SystemUI/res/layout/controls_management_apps.xml +++ b/packages/SystemUI/res/layout/controls_management_apps.xml @@ -14,18 +14,11 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> -<androidx.core.widget.NestedScrollView +<androidx.recyclerview.widget.RecyclerView xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/list" android:layout_width="match_parent" - android:layout_height="0dp" - android:layout_weight="1" - android:orientation="vertical" - android:layout_marginTop="@dimen/controls_management_list_margin"> + android:layout_height="match_parent" + android:layout_marginTop="@dimen/controls_management_list_margin" +/> - <androidx.recyclerview.widget.RecyclerView - android:id="@+id/list" - android:layout_width="match_parent" - android:layout_height="match_parent" - /> - -</androidx.core.widget.NestedScrollView> diff --git a/packages/SystemUI/res/layout/controls_management_editing.xml b/packages/SystemUI/res/layout/controls_management_editing.xml new file mode 100644 index 000000000000..8a14ec3666b2 --- /dev/null +++ b/packages/SystemUI/res/layout/controls_management_editing.xml @@ -0,0 +1,27 @@ +<?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. + --> + +<androidx.recyclerview.widget.RecyclerView + xmlns:android="http://schemas.android.com/apk/res/android" + android:id="@+id/list" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:clipChildren="false" + android:clipToPadding="false" + android:paddingTop="@dimen/controls_management_list_margin" +/> + diff --git a/packages/SystemUI/res/layout/notification_conversation_info.xml b/packages/SystemUI/res/layout/notification_conversation_info.xml index 87cb5c7f746c..9dc502efab43 100644 --- a/packages/SystemUI/res/layout/notification_conversation_info.xml +++ b/packages/SystemUI/res/layout/notification_conversation_info.xml @@ -20,7 +20,7 @@ android:id="@+id/notification_guts" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clickable="true" + android:focusable="true" android:clipChildren="false" android:clipToPadding="true" android:orientation="vertical" diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml index dc94697f32fa..5399f57c322f 100644 --- a/packages/SystemUI/res/layout/notification_guts.xml +++ b/packages/SystemUI/res/layout/notification_guts.xml @@ -19,8 +19,8 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" + android:focusable="true" android:id="@+id/notification_guts" android:visibility="gone" - android:clickable="true" android:gravity="top|start" android:theme="@*android:style/Theme.DeviceDefault.Light"/> diff --git a/packages/SystemUI/res/layout/notification_info.xml b/packages/SystemUI/res/layout/notification_info.xml index 73b711d275f3..5b363820e4e2 100644 --- a/packages/SystemUI/res/layout/notification_info.xml +++ b/packages/SystemUI/res/layout/notification_info.xml @@ -20,7 +20,7 @@ android:id="@+id/notification_guts" android:layout_width="match_parent" android:layout_height="wrap_content" - android:clickable="true" + android:focusable="true" android:clipChildren="false" android:clipToPadding="true" android:orientation="vertical" diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 6a8a4b9ac2fd..2a4d5ef921f7 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -1250,6 +1250,12 @@ <dimen name="control_base_item_margin">2dp</dimen> <dimen name="control_status_padding">3dp</dimen> + <!-- Home Controls activity view detail panel--> + <dimen name="controls_activity_view_top_padding">25dp</dimen> + <dimen name="controls_activity_view_side_padding">12dp</dimen> + <dimen name="controls_activity_view_top_offset">200dp</dimen> + <dimen name="controls_activity_view_text_size">17sp</dimen> + <!-- Home Controls management screens --> <dimen name="controls_management_top_padding">48dp</dimen> <dimen name="controls_management_side_padding">8dp</dimen> diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml index 566d143208fc..7c0b6054dddb 100644 --- a/packages/SystemUI/res/values/strings.xml +++ b/packages/SystemUI/res/values/strings.xml @@ -2670,8 +2670,11 @@ <string name="controls_favorite_default_title">Controls</string> <!-- Controls management controls screen subtitle [CHAR LIMIT=NONE] --> <string name="controls_favorite_subtitle">Choose controls to access from the power menu</string> - <!-- Controls management controls screen, user direction for rearranging controls [CHAR LIMIT=NONE] --> - <string name="controls_favorite_rearrange">Hold and drag a control to move it</string> + <!-- Controls management editing screen, user direction for rearranging controls [CHAR LIMIT=NONE] --> + <string name="controls_favorite_rearrange">Hold & drag to rearrange controls</string> + + <!-- Controls management editing screen, text to indicate that all the favorites have been removed [CHAR LIMIT=NONE] --> + <string name="controls_favorite_removed">All controls removed</string> <!-- Controls management controls screen error on load message [CHAR LIMIT=60] --> <string name="controls_favorite_load_error">The list of all controls could not be loaded.</string> diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 3e02b30c376b..118aa5b3f96a 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -671,6 +671,19 @@ <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item> </style> + <style name="Theme.SystemUI.Dialog.Control.DetailPanel" parent="@android:style/Theme.DeviceDefault.Dialog.NoActionBar"> + <item name="android:windowAnimationStyle">@style/Animation.Bottomsheet</item> + <item name="android:windowFullscreen">true</item> + <item name="android:windowIsFloating">false</item> + <item name="android:windowBackground">@null</item> + <item name="android:backgroundDimEnabled">true</item> + </style> + + <style name="Animation.Bottomsheet"> + <item name="android:windowEnterAnimation">@anim/bottomsheet_in</item> + <item name="android:windowExitAnimation">@anim/bottomsheet_out</item> + </style> + <style name="Control" /> <style name="Control.MenuItem"> @@ -713,6 +726,11 @@ <item name="android:textSize">@dimen/control_text_size</item> <item name="android:textColor">@color/control_secondary_text</item> </style> + <style name="TextAppearance.ControlDialog"> + <item name="android:fontFamily">@*android:string/config_headlineFontFamilyMedium</item> + <item name="android:textSize">@dimen/controls_activity_view_text_size</item> + <item name="android:textColor">@color/control_primary_text</item> + </style> <style name="Control.ListPopupWindow" parent="@*android:style/Widget.DeviceDefault.ListPopupWindow"> <item name="android:overlapAnchor">true</item> diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java index 34a0268201f4..4794847d8be1 100644 --- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java +++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/PinnedStackListenerForwarder.java @@ -18,7 +18,6 @@ package com.android.systemui.shared.system; import android.content.ComponentName; import android.content.pm.ParceledListSlice; -import android.graphics.Rect; import android.view.DisplayInfo; import android.view.IPinnedStackController; import android.view.IPinnedStackListener; @@ -53,9 +52,9 @@ public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub { } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { + public void onMovementBoundsChanged(boolean fromImeAdjustment) { for (PinnedStackListener listener : mListeners) { - listener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment); + listener.onMovementBoundsChanged(fromImeAdjustment); } } @@ -108,7 +107,7 @@ public class PinnedStackListenerForwarder extends IPinnedStackListener.Stub { public static class PinnedStackListener { public void onListenerRegistered(IPinnedStackController controller) {} - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) {} + public void onMovementBoundsChanged(boolean fromImeAdjustment) {} public void onImeVisibilityChanged(boolean imeVisible, int imeHeight) {} diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java index 1e1ce4e6d159..5c3d17ce0e2b 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java @@ -19,7 +19,9 @@ import static android.view.ViewRootImpl.NEW_INSETS_MODE_FULL; import static android.view.ViewRootImpl.sNewInsetsMode; import static android.view.WindowInsets.Type.ime; import static android.view.WindowInsets.Type.systemBars; + import static com.android.systemui.DejankUtils.whitelistIpcs; + import static java.lang.Integer.max; import android.app.Activity; @@ -28,7 +30,6 @@ import android.app.admin.DevicePolicyManager; import android.content.Context; import android.content.Intent; import android.content.res.ColorStateList; -import android.graphics.Rect; import android.metrics.LogMaker; import android.os.Handler; import android.os.Looper; diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java index 2f103940f3e4..03ccc1c91487 100644 --- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java +++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java @@ -147,6 +147,28 @@ public interface KeyguardViewController { */ ViewRootImpl getViewRootImpl(); + /** + * Notifies that the user has authenticated by other means than using the bouncer, for example, + * fingerprint. + */ + void notifyKeyguardAuthenticated(boolean strongAuth); + + /** + * Shows the Bouncer. + * + */ + void showBouncer(boolean scrimmed); + + /** + * Returns {@code true} when the bouncer is currently showing + */ + boolean isBouncerShowing(); + + /** + * When bouncer is fully visible or it is showing but animation didn't finish yet. + */ + boolean bouncerIsOrWillBeShowing(); + // TODO: Deprecate registerStatusBar in KeyguardViewController interface. It is currently // only used for testing purposes in StatusBarKeyguardViewManager, and it prevents us from // achieving complete abstraction away from where the Keyguard View is mounted. diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java index 61e6f39c054f..71dbbbc9da50 100644 --- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java +++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleStackView.java @@ -1349,7 +1349,8 @@ public class BubbleStackView extends FrameLayout { if (show && mShouldShowManageEducation && mManageEducationView.getVisibility() != VISIBLE - && mIsExpanded) { + && mIsExpanded + && mExpandedBubble.getExpandedView() != null) { mManageEducationView.setAlpha(0); mManageEducationView.setVisibility(VISIBLE); mManageEducationView.post(() -> { @@ -1909,7 +1910,8 @@ public class BubbleStackView extends FrameLayout { Log.d(TAG, "updateExpandedBubble()"); } mExpandedViewContainer.removeAllViews(); - if (mIsExpanded && mExpandedBubble != null) { + if (mIsExpanded && mExpandedBubble != null + && mExpandedBubble.getExpandedView() != null) { BubbleExpandedView bev = mExpandedBubble.getExpandedView(); mExpandedViewContainer.addView(bev); bev.populateExpandedView(); @@ -1929,7 +1931,7 @@ public class BubbleStackView extends FrameLayout { if (!mExpandedViewYAnim.isRunning()) { // We're not animating so set the value mExpandedViewContainer.setTranslationY(y); - if (mExpandedBubble != null) { + if (mExpandedBubble != null && mExpandedBubble.getExpandedView() != null) { mExpandedBubble.getExpandedView().updateView(); } } else { @@ -1967,7 +1969,7 @@ public class BubbleStackView extends FrameLayout { } private void updatePointerPosition() { - if (mExpandedBubble == null) { + if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) { return; } int index = getBubbleIndex(mExpandedBubble); @@ -2049,7 +2051,7 @@ public class BubbleStackView extends FrameLayout { * a back key down/up event pair is forwarded to the bubble Activity. */ boolean performBackPressIfNeeded() { - if (!isExpanded() || mExpandedBubble == null) { + if (!isExpanded() || mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) { return false; } return mExpandedBubble.getExpandedView().performBackPressIfNeeded(); diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt index dec60073a55e..5891a7f705c8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt @@ -18,10 +18,34 @@ package com.android.systemui.controls import android.content.ComponentName import android.service.controls.Control +import android.service.controls.DeviceTypes + +interface ControlInterface { + val favorite: Boolean + val component: ComponentName + val controlId: String + val title: CharSequence + val subtitle: CharSequence + val removed: Boolean + get() = false + @DeviceTypes.DeviceType val deviceType: Int +} data class ControlStatus( val control: Control, - val component: ComponentName, - var favorite: Boolean, - val removed: Boolean = false -) + override val component: ComponentName, + override var favorite: Boolean, + override val removed: Boolean = false +) : ControlInterface { + override val controlId: String + get() = control.controlId + + override val title: CharSequence + get() = control.title + + override val subtitle: CharSequence + get() = control.subtitle + + @DeviceTypes.DeviceType override val deviceType: Int + get() = control.deviceType +} diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt index 6e59ac162657..40606c2689e5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlInfo.kt @@ -16,6 +16,7 @@ package com.android.systemui.controls.controller +import android.service.controls.Control import android.service.controls.DeviceTypes /** @@ -39,6 +40,14 @@ data class ControlInfo( companion object { private const val SEPARATOR = ":" + fun fromControl(control: Control): ControlInfo { + return ControlInfo( + control.controlId, + control.title, + control.subtitle, + control.deviceType + ) + } } /** @@ -49,13 +58,4 @@ data class ControlInfo( override fun toString(): String { return "$SEPARATOR$controlId$SEPARATOR$controlTitle$SEPARATOR$deviceType" } - - class Builder { - lateinit var controlId: String - lateinit var controlTitle: CharSequence - lateinit var controlSubtitle: CharSequence - var deviceType: Int = DeviceTypes.TYPE_UNKNOWN - - fun build() = ControlInfo(controlId, controlTitle, controlSubtitle, deviceType) - } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt index 568fb289027d..7cab847d52f7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt @@ -148,6 +148,18 @@ interface ControlsController : UserAwareController { fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo> /** + * Get all the favorites for a given structure. + * + * @param componentName the name of the service that provides the [Control] + * @param structureName the name of the structure + * @return a list of the current favorites in that structure + */ + fun getFavoritesForStructure( + componentName: ComponentName, + structureName: CharSequence + ): List<ControlInfo> + + /** * Adds a single favorite to a given component and structure * @param componentName the name of the service that provides the [Control] * @param structureName the name of the structure that holds the [Control] diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt index 8805694616a4..6d34009169d5 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt @@ -544,6 +544,15 @@ class ControlsControllerImpl @Inject constructor ( override fun getFavoritesForComponent(componentName: ComponentName): List<StructureInfo> = Favorites.getStructuresForComponent(componentName) + override fun getFavoritesForStructure( + componentName: ComponentName, + structureName: CharSequence + ): List<ControlInfo> { + return Favorites.getControlsForStructure( + StructureInfo(componentName, structureName, emptyList()) + ) + } + override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) { pw.println("ControlsController state:") pw.println(" Available: $available") 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 946a2365585a..3bed55912332 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/dagger/ControlsModule.kt @@ -22,6 +22,7 @@ import com.android.systemui.controls.controller.ControlsBindingControllerImpl import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.ControlsControllerImpl import com.android.systemui.controls.controller.ControlsFavoritePersistenceWrapper +import com.android.systemui.controls.management.ControlsEditingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsListingControllerImpl @@ -73,6 +74,13 @@ abstract class ControlsModule { @Binds @IntoMap + @ClassKey(ControlsEditingActivity::class) + abstract fun provideControlsEditingActivity( + activity: ControlsEditingActivity + ): Activity + + @Binds + @IntoMap @ClassKey(ControlsRequestDialog::class) abstract fun provideControlsRequestDialog( activity: ControlsRequestDialog diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt index 11181e56838e..175ed061c714 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/AllModel.kt @@ -37,23 +37,22 @@ import com.android.systemui.controls.controller.ControlInfo * @property controls List of controls as returned by loading * @property initialFavoriteIds sorted ids of favorite controls. * @property noZoneString text to use as header for all controls that have blank or `null` zone. + * @property controlsModelCallback callback to notify that favorites have changed for the first time */ class AllModel( private val controls: List<ControlStatus>, initialFavoriteIds: List<String>, - private val emptyZoneString: CharSequence + private val emptyZoneString: CharSequence, + private val controlsModelCallback: ControlsModel.ControlsModelCallback ) : ControlsModel { - override val favorites: List<ControlInfo.Builder> + private var modified = false + + override val favorites: List<ControlInfo> get() = favoriteIds.mapNotNull { id -> val control = controls.firstOrNull { it.control.controlId == id }?.control control?.let { - ControlInfo.Builder().apply { - controlId = it.controlId - controlTitle = it.title - controlSubtitle = it.subtitle - deviceType = it.deviceType - } + ControlInfo.fromControl(it) } } @@ -66,14 +65,18 @@ class AllModel( override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { val toChange = elements.firstOrNull { - it is ControlWrapper && it.controlStatus.control.controlId == controlId - } as ControlWrapper? + it is ControlStatusWrapper && it.controlStatus.control.controlId == controlId + } as ControlStatusWrapper? if (favorite == toChange?.controlStatus?.favorite) return - if (favorite) { + val changed: Boolean = if (favorite) { favoriteIds.add(controlId) } else { favoriteIds.remove(controlId) } + if (changed && !modified) { + modified = true + controlsModelCallback.onFirstChange() + } toChange?.let { it.controlStatus.favorite = favorite } @@ -84,9 +87,9 @@ class AllModel( it.control.zone ?: "" } val output = mutableListOf<ElementWrapper>() - var emptyZoneValues: Sequence<ControlWrapper>? = null + var emptyZoneValues: Sequence<ControlStatusWrapper>? = null for (zoneName in map.orderedKeys) { - val values = map.getValue(zoneName).asSequence().map { ControlWrapper(it) } + val values = map.getValue(zoneName).asSequence().map { ControlStatusWrapper(it) } if (TextUtils.isEmpty(zoneName)) { emptyZoneValues = values } else { diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt index 1291dd98932e..607934c3bae7 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlAdapter.kt @@ -28,6 +28,7 @@ import android.widget.TextView import androidx.recyclerview.widget.GridLayoutManager import androidx.recyclerview.widget.RecyclerView import com.android.systemui.R +import com.android.systemui.controls.ControlInterface import com.android.systemui.controls.ui.RenderInfo private typealias ModelFavoriteChanger = (String, Boolean) -> Unit @@ -35,11 +36,10 @@ private typealias ModelFavoriteChanger = (String, Boolean) -> Unit /** * Adapter for binding [Control] information to views. * - * The model for this adapter is provided by a [FavoriteModel] that is set using + * The model for this adapter is provided by a [ControlModel] that is set using * [changeFavoritesModel]. This allows for updating the model if there's a reload. * - * @param layoutInflater an inflater for the views in the containing [RecyclerView] - * @param onlyFavorites set to true to only display favorites instead of all controls + * @property elevation elevation of each control view */ class ControlAdapter( private val elevation: Float @@ -48,11 +48,12 @@ class ControlAdapter( companion object { private const val TYPE_ZONE = 0 private const val TYPE_CONTROL = 1 + private const val TYPE_DIVIDER = 2 } val spanSizeLookup = object : GridLayoutManager.SpanSizeLookup() { override fun getSpanSize(position: Int): Int { - return if (getItemViewType(position) == TYPE_ZONE) 2 else 1 + return if (getItemViewType(position) != TYPE_CONTROL) 2 else 1 } } @@ -78,6 +79,10 @@ class ControlAdapter( TYPE_ZONE -> { ZoneHolder(layoutInflater.inflate(R.layout.controls_zone_header, parent, false)) } + TYPE_DIVIDER -> { + DividerHolder(layoutInflater.inflate( + R.layout.controls_horizontal_divider_withEmpty, parent, false)) + } else -> throw IllegalStateException("Wrong viewType: $viewType") } } @@ -95,11 +100,26 @@ class ControlAdapter( } } + override fun onBindViewHolder(holder: Holder, position: Int, payloads: MutableList<Any>) { + if (payloads.isEmpty()) { + super.onBindViewHolder(holder, position, payloads) + } else { + model?.let { + val el = it.elements[position] + if (el is ControlInterface) { + holder.updateFavorite(el.favorite) + } + } + } + } + override fun getItemViewType(position: Int): Int { model?.let { return when (it.elements.get(position)) { is ZoneNameWrapper -> TYPE_ZONE - is ControlWrapper -> TYPE_CONTROL + is ControlStatusWrapper -> TYPE_CONTROL + is ControlInfoWrapper -> TYPE_CONTROL + is DividerWrapper -> TYPE_DIVIDER } } ?: throw IllegalStateException("Getting item type for null model") } @@ -115,6 +135,24 @@ sealed class Holder(view: View) : RecyclerView.ViewHolder(view) { * Bind the data from the model into the view */ abstract fun bindData(wrapper: ElementWrapper) + + open fun updateFavorite(favorite: Boolean) {} +} + +/** + * Holder for using with [DividerWrapper] to display a divider between zones. + * + * The divider can be shown or hidden. It also has a frame view the height of a control, that can + * be toggled visible or gone. + */ +private class DividerHolder(view: View) : Holder(view) { + private val frame: View = itemView.requireViewById(R.id.frame) + private val divider: View = itemView.requireViewById(R.id.divider) + override fun bindData(wrapper: ElementWrapper) { + wrapper as DividerWrapper + frame.visibility = if (wrapper.showNone) View.VISIBLE else View.GONE + divider.visibility = if (wrapper.showDivider) View.VISIBLE else View.GONE + } } /** @@ -130,11 +168,14 @@ private class ZoneHolder(view: View) : Holder(view) { } /** - * Holder for using with [ControlWrapper] to display names of zones. + * Holder for using with [ControlStatusWrapper] to display names of zones. * @param favoriteCallback this callback will be called whenever the favorite state of the * [Control] this view represents changes. */ -private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChanger) : Holder(view) { +internal class ControlHolder( + view: View, + val favoriteCallback: ModelFavoriteChanger +) : Holder(view) { private val icon: ImageView = itemView.requireViewById(R.id.icon) private val title: TextView = itemView.requireViewById(R.id.title) private val subtitle: TextView = itemView.requireViewById(R.id.subtitle) @@ -144,20 +185,23 @@ private class ControlHolder(view: View, val favoriteCallback: ModelFavoriteChang } override fun bindData(wrapper: ElementWrapper) { - wrapper as ControlWrapper - val data = wrapper.controlStatus - val renderInfo = getRenderInfo(data.component, data.control.deviceType) - title.text = data.control.title - subtitle.text = data.control.subtitle - favorite.isChecked = data.favorite - removed.text = if (data.removed) "Removed" else "" + wrapper as ControlInterface + val renderInfo = getRenderInfo(wrapper.component, wrapper.deviceType) + title.text = wrapper.title + subtitle.text = wrapper.subtitle + favorite.isChecked = wrapper.favorite + removed.text = if (wrapper.removed) "Removed" else "" itemView.setOnClickListener { favorite.isChecked = !favorite.isChecked - favoriteCallback(data.control.controlId, favorite.isChecked) + favoriteCallback(wrapper.controlId, favorite.isChecked) } applyRenderInfo(renderInfo) } + override fun updateFavorite(favorite: Boolean) { + this.favorite.isChecked = favorite + } + private fun getRenderInfo( component: ComponentName, @DeviceTypes.DeviceType deviceType: Int diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt new file mode 100644 index 000000000000..ee1ce7ab3d83 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsEditingActivity.kt @@ -0,0 +1,176 @@ +/* + * 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.management + +import android.app.Activity +import android.content.ComponentName +import android.content.Intent +import android.os.Bundle +import android.view.View +import android.view.ViewStub +import android.widget.Button +import android.widget.TextView +import androidx.recyclerview.widget.GridLayoutManager +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.R +import com.android.systemui.broadcast.BroadcastDispatcher +import com.android.systemui.controls.controller.ControlsControllerImpl +import com.android.systemui.controls.controller.StructureInfo +import com.android.systemui.settings.CurrentUserTracker +import javax.inject.Inject + +/** + * Activity for rearranging and removing controls for a given structure + */ +class ControlsEditingActivity @Inject constructor( + private val controller: ControlsControllerImpl, + broadcastDispatcher: BroadcastDispatcher +) : Activity() { + + companion object { + private const val TAG = "ControlsEditingActivity" + private const val EXTRA_STRUCTURE = ControlsFavoritingActivity.EXTRA_STRUCTURE + private val SUBTITLE_ID = R.string.controls_favorite_rearrange + private val EMPTY_TEXT_ID = R.string.controls_favorite_removed + } + + private lateinit var component: ComponentName + private lateinit var structure: CharSequence + private lateinit var model: FavoritesModel + private lateinit var subtitle: TextView + private lateinit var saveButton: View + + private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) { + private val startingUser = controller.currentUserId + + override fun onUserSwitched(newUserId: Int) { + if (newUserId != startingUser) { + stopTracking() + finish() + } + } + } + + override fun onBackPressed() { + finish() + } + + override fun onCreate(savedInstanceState: Bundle?) { + super.onCreate(savedInstanceState) + + intent.getParcelableExtra<ComponentName>(Intent.EXTRA_COMPONENT_NAME)?.let { + component = it + } ?: run(this::finish) + + intent.getCharSequenceExtra(EXTRA_STRUCTURE)?.let { + structure = it + } ?: run(this::finish) + + bindViews() + + bindButtons() + + setUpList() + + currentUserTracker.startTracking() + } + + private fun bindViews() { + setContentView(R.layout.controls_management) + requireViewById<ViewStub>(R.id.stub).apply { + layoutResource = R.layout.controls_management_editing + inflate() + } + requireViewById<TextView>(R.id.title).text = structure + subtitle = requireViewById<TextView>(R.id.subtitle).apply { + setText(SUBTITLE_ID) + } + } + + private fun bindButtons() { + requireViewById<Button>(R.id.other_apps).apply { + visibility = View.VISIBLE + setText(R.string.controls_menu_add) + setOnClickListener { + saveFavorites() + val intent = Intent(this@ControlsEditingActivity, + ControlsFavoritingActivity::class.java).apply { + putExtras(this@ControlsEditingActivity.intent) + putExtra(ControlsFavoritingActivity.EXTRA_SINGLE_STRUCTURE, true) + } + startActivity(intent) + finish() + } + } + + saveButton = requireViewById<Button>(R.id.done).apply { + isEnabled = false + setText(R.string.save) + setOnClickListener { + saveFavorites() + finishAffinity() + } + } + } + + private fun saveFavorites() { + controller.replaceFavoritesForStructure( + StructureInfo(component, structure, model.favorites)) + } + + private val favoritesModelCallback = object : FavoritesModel.FavoritesModelCallback { + override fun onNoneChanged(showNoFavorites: Boolean) { + if (showNoFavorites) { + subtitle.setText(EMPTY_TEXT_ID) + } else { + subtitle.setText(SUBTITLE_ID) + } + } + + override fun onFirstChange() { + saveButton.isEnabled = true + } + } + + private fun setUpList() { + val controls = controller.getFavoritesForStructure(component, structure) + model = FavoritesModel(component, controls, favoritesModelCallback) + val elevation = resources.getFloat(R.dimen.control_card_elevation) + val adapter = ControlAdapter(elevation) + val recycler = requireViewById<RecyclerView>(R.id.list) + val margin = resources + .getDimensionPixelSize(R.dimen.controls_card_margin) + val itemDecorator = MarginItemDecorator(margin, margin) + + recycler.apply { + this.adapter = adapter + layoutManager = GridLayoutManager(recycler.context, 2).apply { + spanSizeLookup = adapter.spanSizeLookup + } + addItemDecoration(itemDecorator) + } + adapter.changeModel(model) + model.attachAdapter(adapter) + ItemTouchHelper(model.itemTouchHelperCallback).attachToRecyclerView(recycler) + } + + override fun onDestroy() { + currentUserTracker.stopTracking() + super.onDestroy() + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt index fe1e6328820d..6f34deeb8547 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt @@ -61,6 +61,7 @@ class ControlsFavoritingActivity @Inject constructor( // If provided, show this structure page first const val EXTRA_STRUCTURE = "extra_structure" + const val EXTRA_SINGLE_STRUCTURE = "extra_single_structure" private const val TOOLTIP_PREFS_KEY = Prefs.Key.CONTROLS_STRUCTURE_SWIPE_TOOLTIP_COUNT private const val TOOLTIP_MAX_SHOWN = 2 } @@ -131,6 +132,12 @@ class ControlsFavoritingActivity @Inject constructor( currentUserTracker.startTracking() } + private val controlsModelCallback = object : ControlsModel.ControlsModelCallback { + override fun onFirstChange() { + doneButton.isEnabled = true + } + } + private fun loadControls() { component?.let { statusText.text = resources.getText(com.android.internal.R.string.loading) @@ -142,15 +149,20 @@ class ControlsFavoritingActivity @Inject constructor( val error = data.errorOnLoad val controlsByStructure = allControls.groupBy { it.control.structure ?: "" } listOfStructures = controlsByStructure.map { - StructureContainer(it.key, AllModel(it.value, favoriteKeys, emptyZoneString)) + StructureContainer(it.key, AllModel( + it.value, favoriteKeys, emptyZoneString, controlsModelCallback)) }.sortedWith(comparator) val structureIndex = listOfStructures.indexOfFirst { sc -> sc.structureName == structureExtra }.let { if (it == -1) 0 else it } + // If we were requested to show a single structure, set the list to just that one + if (intent.getBooleanExtra(EXTRA_SINGLE_STRUCTURE, false)) { + listOfStructures = listOf(listOfStructures[structureIndex]) + } + executor.execute { - doneButton.isEnabled = true structurePager.adapter = StructureAdapter(listOfStructures) structurePager.setCurrentItem(structureIndex) if (error) { @@ -239,8 +251,11 @@ class ControlsFavoritingActivity @Inject constructor( } } + val title = structureExtra + ?: (appName ?: resources.getText(R.string.controls_favorite_default_title)) + setTitle(title) titleView = requireViewById<TextView>(R.id.title).apply { - text = appName ?: resources.getText(R.string.controls_favorite_default_title) + text = title } requireViewById<TextView>(R.id.subtitle).text = resources.getText(R.string.controls_favorite_subtitle) @@ -272,7 +287,7 @@ class ControlsFavoritingActivity @Inject constructor( setOnClickListener { if (component == null) return@setOnClickListener listOfStructures.forEach { - val favoritesForStorage = it.model.favorites.map { it.build() } + val favoritesForStorage = it.model.favorites controller.replaceFavoritesForStructure( StructureInfo(component!!, it.structureName, favoritesForStorage) ) diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt index a995a2ebfd25..37b6d15c0afe 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsModel.kt @@ -16,6 +16,9 @@ package com.android.systemui.controls.management +import android.content.ComponentName +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.controls.ControlInterface import com.android.systemui.controls.ControlStatus import com.android.systemui.controls.controller.ControlInfo @@ -27,12 +30,12 @@ import com.android.systemui.controls.controller.ControlInfo interface ControlsModel { /** - * List of favorites (builders) in order. + * List of favorites in order. * * This should be obtained prior to storing the favorites using * [ControlsController.replaceFavoritesForComponent]. */ - val favorites: List<ControlInfo.Builder> + val favorites: List<ControlInfo> /** * List of all the elements to display by the corresponding [RecyclerView]. @@ -48,6 +51,24 @@ interface ControlsModel { * Move an item (in elements) from one position to another. */ fun onMoveItem(from: Int, to: Int) {} + + /** + * Attach an adapter to the model. + * + * This can be used to notify the adapter of changes in the model. + */ + fun attachAdapter(adapter: RecyclerView.Adapter<*>) {} + + /** + * Callback to notify elements (other than the adapter) of relevant changes in the model. + */ + interface ControlsModelCallback { + + /** + * Use to notify that the model has changed for the first time + */ + fun onFirstChange() + } } /** @@ -55,5 +76,29 @@ interface ControlsModel { * [ControlAdapter]. */ sealed class ElementWrapper + data class ZoneNameWrapper(val zoneName: CharSequence) : ElementWrapper() -data class ControlWrapper(val controlStatus: ControlStatus) : ElementWrapper()
\ No newline at end of file + +data class ControlStatusWrapper( + val controlStatus: ControlStatus +) : ElementWrapper(), ControlInterface by controlStatus + +data class ControlInfoWrapper( + override val component: ComponentName, + val controlInfo: ControlInfo, + override var favorite: Boolean +) : ElementWrapper(), ControlInterface { + override val controlId: String + get() = controlInfo.controlId + override val title: CharSequence + get() = controlInfo.controlTitle + override val subtitle: CharSequence + get() = controlInfo.controlSubtitle + override val deviceType: Int + get() = controlInfo.deviceType +} + +data class DividerWrapper( + var showNone: Boolean = false, + var showDivider: Boolean = false +) : ElementWrapper()
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt index 0c41f7e5df5a..3be59009f531 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt @@ -64,6 +64,7 @@ class ControlsProviderSelectorActivity @Inject constructor( override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) + setContentView(R.layout.controls_management) requireViewById<ViewStub>(R.id.stub).apply { layoutResource = R.layout.controls_management_apps diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt deleted file mode 100644 index 5c51e3dbe4ac..000000000000 --- a/packages/SystemUI/src/com/android/systemui/controls/management/FavoriteModel.kt +++ /dev/null @@ -1,145 +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.controls.management - -import android.text.TextUtils -import android.util.Log -import com.android.systemui.controls.ControlStatus -import java.util.Collections -import java.util.Comparator - -/** - * Model for keeping track of current favorites and their order. - * - * This model is to be used with two [ControlAdapter] one that shows only favorites in the current - * order and another that shows all controls, separated by zone. When the favorite state of any - * control is modified or when the favorites are reordered, the adapters are notified of the change. - * - * @param listControls list of all the [ControlStatus] to display. This includes controls currently - * marked as favorites as well as those that have been removed (not returned - * from load) - * @param listFavoritesIds list of the [Control.controlId] for all the favorites, including those - * that have been removed. - * @param favoritesAdapter [ControlAdapter] used by the [RecyclerView] that shows only favorites - * @param allAdapter [ControlAdapter] used by the [RecyclerView] that shows all controls - */ -class FavoriteModel( - private val listControls: List<ControlStatus>, - listFavoritesIds: List<String>, - private val favoritesAdapter: ControlAdapter, - private val allAdapter: ControlAdapter -) { - - companion object { - private const val TAG = "FavoriteModel" - } - - /** - * List of favorite controls ([ControlWrapper]) in order. - * - * Initially, this list will give a list of wrappers in the order specified by the constructor - * variable `listFavoriteIds`. - * - * As the favorites are added, removed or moved, this list will keep track of those changes. - */ - val favorites: List<ControlWrapper> = listFavoritesIds.map { id -> - ControlWrapper(listControls.first { it.control.controlId == id }) - }.toMutableList() - - /** - * List of all controls by zones. - * - * Lists all the controls with the zone names interleaved as a flat list. After each zone name, - * the controls in that zone are listed. Zones are listed in alphabetical order - */ - val all: List<ElementWrapper> = listControls.groupBy { it.control.zone } - .mapKeys { it.key ?: "" } // map null to empty - .toSortedMap(CharSequenceComparator()) - .flatMap { - val controls = it.value.map { ControlWrapper(it) } - if (!TextUtils.isEmpty(it.key)) { - listOf(ZoneNameWrapper(it.key)) + controls - } else { - controls - } - } - - /** - * Change the favorite status of a [Control]. - * - * This can be invoked from any of the [ControlAdapter]. It will change the status of that - * control and either add it to the list of favorites (at the end) or remove it from it. - * - * Removing the favorite status from a Removed control will make it disappear completely if - * changes are saved. - * - * @param controlId the id of the [Control] to change the status - * @param favorite `true` if and only if it's set to be a favorite. - */ - fun changeFavoriteStatus(controlId: String, favorite: Boolean) { - favorites as MutableList - val index = all.indexOfFirst { - it is ControlWrapper && it.controlStatus.control.controlId == controlId - } - val control = (all[index] as ControlWrapper).controlStatus - if (control.favorite == favorite) { - Log.d(TAG, "Changing favorite to same state for ${control.control.controlId} ") - return - } else { - control.favorite = favorite - } - allAdapter.notifyItemChanged(index) - if (favorite) { - favorites.add(all[index] as ControlWrapper) - favoritesAdapter.notifyItemInserted(favorites.size - 1) - } else { - val i = favorites.indexOfFirst { it.controlStatus.control.controlId == controlId } - favorites.removeAt(i) - favoritesAdapter.notifyItemRemoved(i) - } - } - - /** - * Move items in the model and notify the [favoritesAdapter]. - */ - fun onMoveItem(from: Int, to: Int) { - if (from < to) { - for (i in from until to) { - Collections.swap(favorites, i, i + 1) - } - } else { - for (i in from downTo to + 1) { - Collections.swap(favorites, i, i - 1) - } - } - favoritesAdapter.notifyItemMoved(from, to) - } -} - -/** - * Compares [CharSequence] as [String]. - * - * It will have empty strings as the first element - */ -class CharSequenceComparator : Comparator<CharSequence> { - override fun compare(p0: CharSequence?, p1: CharSequence?): Int { - if (p0 == null && p1 == null) return 0 - else if (p0 == null && p1 != null) return -1 - else if (p0 != null && p1 == null) return 1 - return p0.toString().compareTo(p1.toString()) - } -}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt new file mode 100644 index 000000000000..411170cb322c --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/controls/management/FavoritesModel.kt @@ -0,0 +1,221 @@ +/* + * 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.management + +import android.content.ComponentName +import androidx.recyclerview.widget.ItemTouchHelper +import androidx.recyclerview.widget.RecyclerView +import com.android.systemui.controls.ControlInterface +import com.android.systemui.controls.controller.ControlInfo +import java.util.Collections + +/** + * Model used to show and rearrange favorites. + * + * The model will show all the favorite controls and a divider that can be toggled visible/gone. + * It will place the items selected as favorites before the divider and the ones unselected after. + * + * @property componentName used by the [ControlAdapter] to retrieve resources. + * @property favorites list of current favorites + * @property favoritesModelCallback callback to notify on first change and empty favorites + */ +class FavoritesModel( + private val componentName: ComponentName, + favorites: List<ControlInfo>, + private val favoritesModelCallback: FavoritesModelCallback +) : ControlsModel { + + private var adapter: RecyclerView.Adapter<*>? = null + private var modified = false + + override fun attachAdapter(adapter: RecyclerView.Adapter<*>) { + this.adapter = adapter + } + + override val favorites: List<ControlInfo> + get() = elements.take(dividerPosition).map { + (it as ControlInfoWrapper).controlInfo + } + + override val elements: List<ElementWrapper> = favorites.map { + ControlInfoWrapper(componentName, it, true) + } + DividerWrapper() + + /** + * Indicates the position of the divider to determine + */ + private var dividerPosition = elements.size - 1 + + override fun changeFavoriteStatus(controlId: String, favorite: Boolean) { + val position = elements.indexOfFirst { it is ControlInterface && it.controlId == controlId } + if (position == -1) { + return // controlId not found + } + if (position < dividerPosition && favorite || position > dividerPosition && !favorite) { + return // Does not change favorite status + } + if (favorite) { + onMoveItemInternal(position, dividerPosition) + } else { + onMoveItemInternal(position, elements.size - 1) + } + } + + override fun onMoveItem(from: Int, to: Int) { + onMoveItemInternal(from, to) + } + + private fun updateDividerNone(oldDividerPosition: Int, show: Boolean) { + (elements[oldDividerPosition] as DividerWrapper).showNone = show + favoritesModelCallback.onNoneChanged(show) + } + + private fun updateDividerShow(oldDividerPosition: Int, show: Boolean) { + (elements[oldDividerPosition] as DividerWrapper).showDivider = show + } + + /** + * Performs the update in the model. + * + * * update the favorite field of the [ControlInterface] + * * update the fields of the [DividerWrapper] + * * move the corresponding element in [elements] + * + * It may emit the following signals: + * * [RecyclerView.Adapter.notifyItemChanged] if a [ControlInterface.favorite] has changed + * (in the new position) or if the information in [DividerWrapper] has changed (in the + * old position). + * * [RecyclerView.Adapter.notifyItemMoved] + * * [FavoritesModelCallback.onNoneChanged] whenever we go from 1 to 0 favorites and back + * * [ControlsModel.ControlsModelCallback.onFirstChange] upon the first change in the model + */ + private fun onMoveItemInternal(from: Int, to: Int) { + if (from == dividerPosition) return // divider does not move + var changed = false + if (from < dividerPosition && to >= dividerPosition || + from > dividerPosition && to <= dividerPosition) { + if (from < dividerPosition && to >= dividerPosition) { + // favorite to not favorite + (elements[from] as ControlInfoWrapper).favorite = false + } else if (from > dividerPosition && to <= dividerPosition) { + // not favorite to favorite + (elements[from] as ControlInfoWrapper).favorite = true + } + changed = true + updateDivider(from, to) + } + moveElement(from, to) + adapter?.notifyItemMoved(from, to) + if (changed) { + adapter?.notifyItemChanged(to, Any()) + } + if (!modified) { + modified = true + favoritesModelCallback.onFirstChange() + } + } + + private fun updateDivider(from: Int, to: Int) { + var dividerChanged = false + val oldDividerPosition = dividerPosition + if (from < dividerPosition && to >= dividerPosition) { // favorite to not favorite + dividerPosition-- + if (dividerPosition == 0) { + updateDividerNone(oldDividerPosition, true) + dividerChanged = true + } + if (dividerPosition == elements.size - 2) { + updateDividerShow(oldDividerPosition, true) + dividerChanged = true + } + } else if (from > dividerPosition && to <= dividerPosition) { // not favorite to favorite + dividerPosition++ + if (dividerPosition == 1) { + updateDividerNone(oldDividerPosition, false) + dividerChanged = true + } + if (dividerPosition == elements.size - 1) { + updateDividerShow(oldDividerPosition, false) + dividerChanged = true + } + } + if (dividerChanged) { + adapter?.notifyItemChanged(oldDividerPosition) + } + } + + private fun moveElement(from: Int, to: Int) { + if (from < to) { + for (i in from until to) { + Collections.swap(elements, i, i + 1) + } + } else { + for (i in from downTo to + 1) { + Collections.swap(elements, i, i - 1) + } + } + } + + /** + * Touch helper to facilitate dragging in the [RecyclerView]. + * + * Only views above the divider line (favorites) can be dragged or accept drops. + */ + val itemTouchHelperCallback = object : ItemTouchHelper.SimpleCallback(0, 0) { + + private val MOVEMENT = ItemTouchHelper.UP or + ItemTouchHelper.DOWN or + ItemTouchHelper.LEFT or + ItemTouchHelper.RIGHT + + override fun onMove( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + onMoveItem(viewHolder.adapterPosition, target.adapterPosition) + return true + } + + override fun getMovementFlags( + recyclerView: RecyclerView, + viewHolder: RecyclerView.ViewHolder + ): Int { + if (viewHolder.adapterPosition < dividerPosition) { + return ItemTouchHelper.Callback.makeMovementFlags(MOVEMENT, 0) + } else { + return ItemTouchHelper.Callback.makeMovementFlags(0, 0) + } + } + + override fun canDropOver( + recyclerView: RecyclerView, + current: RecyclerView.ViewHolder, + target: RecyclerView.ViewHolder + ): Boolean { + return target.adapterPosition < dividerPosition + } + + override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {} + + override fun isItemViewSwipeEnabled() = false + } + + interface FavoritesModelCallback : ControlsModel.ControlsModelCallback { + fun onNoneChanged(showNoFavorites: Boolean) + } +}
\ No newline at end of file diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt index 680d0066fc56..ad86eeb089c8 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlActionCoordinator.kt @@ -16,19 +16,27 @@ package com.android.systemui.controls.ui +import android.app.Dialog import android.app.PendingIntent import android.content.Intent -import android.provider.Settings +import android.service.controls.Control import android.service.controls.actions.BooleanAction import android.service.controls.actions.CommandAction import android.util.Log import android.view.HapticFeedbackConstants +import com.android.systemui.R + object ControlActionCoordinator { public const val MIN_LEVEL = 0 public const val MAX_LEVEL = 10000 - private var useDetailDialog: Boolean? = null + private var dialog: Dialog? = null + + fun closeDialog() { + dialog?.dismiss() + dialog = null + } fun toggle(cvh: ControlViewHolder, templateId: String, isChecked: Boolean) { cvh.action(BooleanAction(templateId, !isChecked)) @@ -37,31 +45,39 @@ object ControlActionCoordinator { cvh.clipLayer.setLevel(nextLevel) } - fun touch(cvh: ControlViewHolder, templateId: String) { - cvh.action(CommandAction(templateId)) + fun touch(cvh: ControlViewHolder, templateId: String, control: Control) { + if (cvh.usePanel()) { + showDialog(cvh, control.getAppIntent().getIntent()) + } else { + cvh.action(CommandAction(templateId)) + } } + /** + * Allow apps to specify whether they would like to appear in a detail panel or within + * the full activity by setting the {@link Control#EXTRA_USE_PANEL} flag. In order for + * activities to determine how they are being launched, they should inspect the + * {@link Control#EXTRA_USE_PANEL} flag for a value of true. + */ fun longPress(cvh: ControlViewHolder) { // Long press snould only be called when there is valid control state, otherwise ignore cvh.cws.control?.let { - if (useDetailDialog == null) { - useDetailDialog = Settings.Secure.getInt(cvh.context.getContentResolver(), - "systemui.controls_use_detail_panel", 0) != 0 - } - try { + it.getAppIntent().send() cvh.layout.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS) - if (useDetailDialog!!) { - DetailDialog(cvh.context, it.getAppIntent()).show() - } else { - it.getAppIntent().send() - val closeDialog = Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS) - cvh.context.sendBroadcast(closeDialog) - } + cvh.context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) } catch (e: PendingIntent.CanceledException) { Log.e(ControlsUiController.TAG, "Error sending pending intent", e) - cvh.setTransientStatus("Error opening application") + cvh.setTransientStatus( + cvh.context.resources.getString(R.string.controls_error_failed)) } } } + + private fun showDialog(cvh: ControlViewHolder, intent: Intent) { + dialog = DetailDialog(cvh, intent).also { + it.setOnDismissListener { _ -> dialog = null } + it.show() + } + } } diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt index b1cb04e10eef..0eb6cb100933 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlViewHolder.kt @@ -39,16 +39,29 @@ import com.android.systemui.R import kotlin.reflect.KClass -private const val UPDATE_DELAY_IN_MILLIS = 3000L -private const val ALPHA_ENABLED = (255.0 * 0.2).toInt() -private const val ALPHA_DISABLED = 255 - +/** + * Wraps the widgets that make up the UI representation of a {@link Control}. Updates to the view + * are signaled via calls to {@link #bindData}. Similar to the ViewHolder concept used in + * RecyclerViews. + */ class ControlViewHolder( val layout: ViewGroup, val controlsController: ControlsController, val uiExecutor: DelayableExecutor, - val bgExecutor: DelayableExecutor + val bgExecutor: DelayableExecutor, + val usePanels: Boolean ) { + + companion object { + private const val UPDATE_DELAY_IN_MILLIS = 3000L + private const val ALPHA_ENABLED = (255.0 * 0.2).toInt() + private const val ALPHA_DISABLED = 255 + private val FORCE_PANEL_DEVICES = setOf( + DeviceTypes.TYPE_THERMOSTAT, + DeviceTypes.TYPE_CAMERA + ) + } + val icon: ImageView = layout.requireViewById(R.id.icon) val status: TextView = layout.requireViewById(R.id.status) val title: TextView = layout.requireViewById(R.id.title) @@ -59,6 +72,8 @@ class ControlViewHolder( var cancelUpdate: Runnable? = null var behavior: Behavior? = null var lastAction: ControlAction? = null + val deviceType: Int + get() = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType init { val ld = layout.getBackground() as LayerDrawable @@ -76,7 +91,7 @@ class ControlViewHolder( val (controlStatus, template) = cws.control?.let { title.setText(it.getTitle()) subtitle.setText(it.getSubtitle()) - Pair(it.getStatus(), it.getControlTemplate()) + Pair(it.status, it.controlTemplate) } ?: run { title.setText(cws.ci.controlTitle) subtitle.setText(cws.ci.controlSubtitle) @@ -91,7 +106,7 @@ class ControlViewHolder( }) } - val clazz = findBehavior(controlStatus, template) + val clazz = findBehavior(controlStatus, template, deviceType) if (behavior == null || behavior!!::class != clazz) { // Behavior changes can signal a change in template from the app or // first time setup @@ -126,9 +141,17 @@ class ControlViewHolder( controlsController.action(cws.componentName, cws.ci, action) } - private fun findBehavior(status: Int, template: ControlTemplate): KClass<out Behavior> { + fun usePanel(): Boolean = + usePanels && deviceType in ControlViewHolder.FORCE_PANEL_DEVICES + + private fun findBehavior( + status: Int, + template: ControlTemplate, + deviceType: Int + ): KClass<out Behavior> { return when { status == Control.STATUS_UNKNOWN -> UnknownBehavior::class + deviceType == DeviceTypes.TYPE_CAMERA -> TouchBehavior::class template is ToggleTemplate -> ToggleBehavior::class template is StatelessTemplate -> TouchBehavior::class template is ToggleRangeTemplate -> ToggleRangeBehavior::class @@ -140,7 +163,6 @@ class ControlViewHolder( internal fun applyRenderInfo(enabled: Boolean, offset: Int = 0) { setEnabled(enabled) - val deviceType = cws.control?.let { it.getDeviceType() } ?: cws.ci.deviceType val ri = RenderInfo.lookup(context, cws.componentName, deviceType, enabled, offset) val fg = context.getResources().getColorStateList(ri.foreground, context.getTheme()) 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 7da3d70271c1..fab6fc7357dd 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/ControlsUiControllerImpl.kt @@ -30,18 +30,19 @@ import android.content.res.Configuration import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.os.Process +import android.provider.Settings import android.service.controls.Control import android.service.controls.actions.ControlAction -import android.util.TypedValue import android.util.Log -import android.view.animation.AccelerateInterpolator -import android.view.animation.DecelerateInterpolator +import android.util.TypedValue import android.view.ContextThemeWrapper import android.view.LayoutInflater import android.view.View import android.view.View.MeasureSpec import android.view.ViewGroup import android.view.WindowManager +import android.view.animation.AccelerateInterpolator +import android.view.animation.DecelerateInterpolator import android.widget.AdapterView import android.widget.ArrayAdapter import android.widget.ImageView @@ -49,23 +50,21 @@ import android.widget.LinearLayout import android.widget.ListPopupWindow import android.widget.Space import android.widget.TextView +import com.android.systemui.R import com.android.systemui.controls.ControlsServiceInfo import com.android.systemui.controls.controller.ControlInfo import com.android.systemui.controls.controller.ControlsController import com.android.systemui.controls.controller.StructureInfo +import com.android.systemui.controls.management.ControlsEditingActivity import com.android.systemui.controls.management.ControlsFavoritingActivity import com.android.systemui.controls.management.ControlsListingController import com.android.systemui.controls.management.ControlsProviderSelectorActivity import com.android.systemui.dagger.qualifiers.Background import com.android.systemui.dagger.qualifiers.Main import com.android.systemui.util.concurrency.DelayableExecutor -import com.android.systemui.R - import dagger.Lazy - import java.text.Collator import java.util.function.Consumer - import javax.inject.Inject import javax.inject.Singleton @@ -85,6 +84,7 @@ class ControlsUiControllerImpl @Inject constructor ( private const val PREF_COMPONENT = "controls_component" private const val PREF_STRUCTURE = "controls_structure" + private const val USE_PANELS = "systemui.controls_use_panel" private const val FADE_IN_MILLIS = 225L private val EMPTY_COMPONENT = ComponentName("", "") @@ -210,14 +210,28 @@ class ControlsUiControllerImpl @Inject constructor ( } private fun startFavoritingActivity(context: Context, si: StructureInfo) { - val i = Intent(context, ControlsFavoritingActivity::class.java).apply { + startTargetedActivity(context, si, ControlsFavoritingActivity::class.java) + } + + private fun startEditingActivity(context: Context, si: StructureInfo) { + startTargetedActivity(context, si, ControlsEditingActivity::class.java) + } + + private fun startTargetedActivity(context: Context, si: StructureInfo, klazz: Class<*>) { + val i = Intent(context, klazz).apply { + addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) + } + putIntentExtras(i, si) + startActivity(context, i) + } + + private fun putIntentExtras(intent: Intent, si: StructureInfo) { + intent.apply { putExtra(ControlsFavoritingActivity.EXTRA_APP, - controlsListingController.get().getAppLabel(si.componentName)) + controlsListingController.get().getAppLabel(si.componentName)) putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure) putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName) - addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK) } - startActivity(context, i) } private fun startProviderSelectorActivity(context: Context) { @@ -253,6 +267,7 @@ class ControlsUiControllerImpl @Inject constructor ( private fun createMenu() { val items = arrayOf( context.resources.getString(R.string.controls_menu_add), + context.resources.getString(R.string.controls_menu_edit), "Reset" ) var adapter = ArrayAdapter<String>(context, R.layout.controls_more_item, items) @@ -273,8 +288,10 @@ class ControlsUiControllerImpl @Inject constructor ( when (pos) { // 0: Add Control 0 -> startFavoritingActivity(view.context, selectedStructure) - // 1: TEMPORARY for reset controls - 1 -> showResetConfirmation() + // 1: Edit controls + 1 -> startEditingActivity(view.context, selectedStructure) + // 2: TEMPORARY for reset controls + 2 -> showResetConfirmation() else -> Log.w(ControlsUiController.TAG, "Unsupported index ($pos) on 'more' menu selection") } @@ -407,6 +424,9 @@ class ControlsUiControllerImpl @Inject constructor ( val maxColumns = findMaxColumns() + // use flag only temporarily for testing + val usePanels = Settings.Secure.getInt(context.contentResolver, USE_PANELS, 0) == 1 + val listView = parent.requireViewById(R.id.global_actions_controls_list) as ViewGroup var lastRow: ViewGroup = createRow(inflater, listView) selectedStructure.controls.forEach { @@ -420,7 +440,8 @@ class ControlsUiControllerImpl @Inject constructor ( baseLayout, controlsController.get(), uiExecutor, - bgExecutor + bgExecutor, + usePanels ) val key = ControlKey(selectedStructure.componentName, it.controlId) cvh.bindData(controlsById.getValue(key)) @@ -500,6 +521,7 @@ class ControlsUiControllerImpl @Inject constructor ( hidden = true popup?.dismiss() activeDialog?.dismiss() + ControlActionCoordinator.closeDialog() controlsController.get().unsubscribe() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt index d3d4287b8707..15c41a2005a6 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/DetailDialog.kt @@ -17,18 +17,16 @@ package com.android.systemui.controls.ui import android.app.ActivityView -import android.app.ActivityOptions import android.app.Dialog -import android.app.PendingIntent import android.content.ComponentName -import android.content.Context import android.content.Intent +import android.provider.Settings import android.view.View import android.view.ViewGroup -import android.view.ViewGroup.LayoutParams.MATCH_PARENT -import android.view.Window +import android.view.WindowInsets import android.view.WindowManager -import android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS +import android.widget.ImageView +import android.widget.TextView import com.android.systemui.R @@ -38,20 +36,26 @@ import com.android.systemui.R * The activity being launched is specified by {@link android.service.controls.Control#getAppIntent}. */ class DetailDialog( - val parentContext: Context, - val intent: PendingIntent -) : Dialog(parentContext) { + val cvh: ControlViewHolder, + val intent: Intent +) : Dialog(cvh.context, R.style.Theme_SystemUI_Dialog_Control_DetailPanel) { - var activityView: ActivityView + companion object { + private const val ALPHA = (0.8f * 255).toInt() + private const val PANEL_TOP_OFFSET = "systemui.controls_panel_top_offset" + } + + lateinit var activityView: ActivityView val stateCallback: ActivityView.StateCallback = object : ActivityView.StateCallback() { override fun onActivityViewReady(view: ActivityView) { - val fillInIntent = Intent() + val launchIntent = Intent(intent) // Apply flags to make behaviour match documentLaunchMode=always. - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) - fillInIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) - view.startActivity(intent, fillInIntent, ActivityOptions.makeBasic()) + launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) + launchIntent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK) + + view.startActivity(launchIntent) } override fun onActivityViewDestroyed(view: ActivityView) {} @@ -61,28 +65,8 @@ class DetailDialog( override fun onTaskRemovalStarted(taskId: Int) {} } - @Suppress("DEPRECATION") - private fun Window.setWindowParams() { - requestFeature(Window.FEATURE_NO_TITLE) - - // Inflate the decor view, so the attributes below are not overwritten by the theme. - decorView - attributes.systemUiVisibility = - (attributes.systemUiVisibility - or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN - or View.SYSTEM_UI_FLAG_LAYOUT_STABLE) - - setLayout(MATCH_PARENT, MATCH_PARENT) - clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND) - addFlags(WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN - or WindowManager.LayoutParams.FLAG_LAYOUT_INSET_DECOR - or WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) - setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) - getAttributes().setFitInsetsTypes(0 /* types */) - } - init { - getWindow()?.setWindowParams() + window.setType(WindowManager.LayoutParams.TYPE_VOLUME_OVERLAY) setContentView(R.layout.controls_detail_dialog) @@ -90,19 +74,61 @@ class DetailDialog( requireViewById<ViewGroup>(R.id.controls_activity_view).apply { addView(activityView) } + + requireViewById<ImageView>(R.id.control_detail_close).apply { + setOnClickListener { _: View -> dismiss() } + } + + requireViewById<TextView>(R.id.title).apply { + setText(cvh.title.text) + } + + requireViewById<TextView>(R.id.subtitle).apply { + setText(cvh.subtitle.text) + } + + requireViewById<ImageView>(R.id.control_detail_open_in_app).apply { + setOnClickListener { v: View -> + dismiss() + context.sendBroadcast(Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)) + v.context.startActivity(intent) + } + } + + // consume all insets to achieve slide under effect + window.getDecorView().setOnApplyWindowInsetsListener { + v: View, insets: WindowInsets -> + activityView.apply { + val l = getPaddingLeft() + val t = getPaddingTop() + val r = getPaddingRight() + setPadding(l, t, r, insets.getSystemWindowInsets().bottom) + } + + insets.consumeSystemWindowInsets() + } + + requireViewById<ViewGroup>(R.id.control_detail_root).apply { + // use flag only temporarily for testing + val resolver = cvh.context.contentResolver + val defaultOffsetInPx = cvh.context.resources + .getDimensionPixelSize(R.dimen.controls_activity_view_top_offset) + val offsetInPx = Settings.Secure.getInt(resolver, PANEL_TOP_OFFSET, defaultOffsetInPx) + + val lp = getLayoutParams() as ViewGroup.MarginLayoutParams + lp.topMargin = offsetInPx + setLayoutParams(lp) + } } override fun show() { - val attrs = getWindow()?.attributes - attrs?.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS - getWindow()?.attributes = attrs - activityView.setCallback(stateCallback) super.show() } override fun dismiss() { + if (!isShowing()) return activityView.release() super.dismiss() diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt index 15c1dabf71bd..6340db1d756d 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TemperatureControlBehavior.kt @@ -33,6 +33,10 @@ class TemperatureControlBehavior : Behavior { override fun initialize(cvh: ControlViewHolder) { this.cvh = cvh + + cvh.layout.setOnClickListener { _ -> + ControlActionCoordinator.touch(cvh, template.getTemplateId(), control) + } } override fun bind(cws: ControlWithState) { diff --git a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt index d64a5f060487..b02c9c8972fc 100644 --- a/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt +++ b/packages/SystemUI/src/com/android/systemui/controls/ui/TouchBehavior.kt @@ -20,7 +20,7 @@ import android.graphics.drawable.Drawable import android.graphics.drawable.LayerDrawable import android.view.View import android.service.controls.Control -import android.service.controls.templates.StatelessTemplate +import android.service.controls.templates.ControlTemplate import com.android.systemui.R import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL @@ -31,7 +31,7 @@ import com.android.systemui.controls.ui.ControlActionCoordinator.MIN_LEVEL */ class TouchBehavior : Behavior { lateinit var clipLayer: Drawable - lateinit var template: StatelessTemplate + lateinit var template: ControlTemplate lateinit var control: Control lateinit var cvh: ControlViewHolder @@ -40,14 +40,14 @@ class TouchBehavior : Behavior { cvh.applyRenderInfo(false) cvh.layout.setOnClickListener(View.OnClickListener() { - ControlActionCoordinator.touch(cvh, template.getTemplateId()) + ControlActionCoordinator.touch(cvh, template.getTemplateId(), control) }) } override fun bind(cws: ControlWithState) { this.control = cws.control!! cvh.status.setText(control.getStatusText()) - template = control.getControlTemplate() as StatelessTemplate + template = control.getControlTemplate() val ld = cvh.layout.getBackground() as LayerDrawable clipLayer = ld.findDrawableByLayerId(R.id.clip_layer) diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java index a4a589481b33..3f095dc0510e 100644 --- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java +++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java @@ -222,11 +222,27 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private ControlsController mControlsController; private SharedPreferences mControlsPreferences; private final RingerModeTracker mRingerModeTracker; + private int mDialogPressDelay = DIALOG_PRESS_DELAY; // ms @VisibleForTesting public enum GlobalActionsEvent implements UiEventLogger.UiEventEnum { @UiEvent(doc = "The global actions / power menu surface became visible on the screen.") - GA_POWER_MENU_OPEN(337); + GA_POWER_MENU_OPEN(337), + + @UiEvent(doc = "The global actions bugreport button was pressed.") + GA_BUGREPORT_PRESS(344), + + @UiEvent(doc = "The global actions bugreport button was long pressed.") + GA_BUGREPORT_LONG_PRESS(345), + + @UiEvent(doc = "The global actions emergency button was pressed.") + GA_EMERGENCY_DIALER_PRESS(346), + + @UiEvent(doc = "The global actions screenshot button was pressed.") + GA_SCREENSHOT_PRESS(347), + + @UiEvent(doc = "The global actions screenshot button was long pressed.") + GA_SCREENSHOT_LONG_PRESS(348); private final int mId; @@ -679,7 +695,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class EmergencyDialerAction extends EmergencyAction { + @VisibleForTesting + class EmergencyDialerAction extends EmergencyAction { private EmergencyDialerAction() { super(com.android.systemui.R.drawable.ic_emergency_star, R.string.global_action_emergency); @@ -688,6 +705,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public void onPress() { mMetricsLogger.action(MetricsEvent.ACTION_EMERGENCY_DIALER_FROM_POWER_MENU); + mUiEventLogger.log(GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); if (mTelecomManager != null) { Intent intent = mTelecomManager.createLaunchEmergencyDialerIntent( null /* number */); @@ -701,6 +719,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + @VisibleForTesting + EmergencyDialerAction makeEmergencyDialerActionForTesting() { + return new EmergencyDialerAction(); + } + private final class RestartAction extends SinglePressAction implements LongPressAction { private RestartAction() { super(R.drawable.ic_restart, R.string.global_action_restart); @@ -731,7 +754,8 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class ScreenshotAction extends SinglePressAction implements LongPressAction { + @VisibleForTesting + class ScreenshotAction extends SinglePressAction implements LongPressAction { public ScreenshotAction() { super(R.drawable.ic_screenshot, R.string.global_action_screenshot); } @@ -747,8 +771,9 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, public void run() { mScreenshotHelper.takeScreenshot(1, true, true, mHandler, null); mMetricsLogger.action(MetricsEvent.ACTION_SCREENSHOT_POWER_MENU); + mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_PRESS); } - }, 500); + }, mDialogPressDelay); } @Override @@ -764,6 +789,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, @Override public boolean onLongPress() { if (FeatureFlagUtils.isEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS)) { + mUiEventLogger.log(GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); mScreenRecordHelper.launchRecordPrompt(); } else { onPress(); @@ -772,7 +798,13 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } - private class BugReportAction extends SinglePressAction implements LongPressAction { + @VisibleForTesting + ScreenshotAction makeScreenshotActionForTesting() { + return new ScreenshotAction(); + } + + @VisibleForTesting + class BugReportAction extends SinglePressAction implements LongPressAction { public BugReportAction() { super(R.drawable.ic_lock_bugreport, R.string.bugreport_title); @@ -795,6 +827,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, // Take an "interactive" bugreport. mMetricsLogger.action( MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_INTERACTIVE); + mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_PRESS); if (!mIActivityManager.launchBugReportHandlerApp()) { Log.w(TAG, "Bugreport handler could not be launched"); mIActivityManager.requestInteractiveBugReport(); @@ -802,7 +835,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } catch (RemoteException e) { } } - }, 500); + }, mDialogPressDelay); } @Override @@ -815,6 +848,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, try { // Take a "full" bugreport. mMetricsLogger.action(MetricsEvent.ACTION_BUGREPORT_FROM_POWER_MENU_FULL); + mUiEventLogger.log(GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); mIActivityManager.requestFullBugReport(); } catch (RemoteException e) { } @@ -831,6 +865,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } } + @VisibleForTesting + BugReportAction makeBugReportActionForTesting() { + return new BugReportAction(); + } + private final class LogoutAction extends SinglePressAction { private LogoutAction() { super(R.drawable.ic_logout, R.string.global_action_logout); @@ -858,7 +897,7 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, } catch (RemoteException re) { Log.e(TAG, "Couldn't logout user " + re); } - }, 500); + }, mDialogPressDelay); } } @@ -1599,6 +1638,11 @@ public class GlobalActionsDialog implements DialogInterface.OnDismissListener, private static final int MESSAGE_REFRESH = 1; private static final int MESSAGE_SHOW = 2; private static final int DIALOG_DISMISS_DELAY = 300; // ms + private static final int DIALOG_PRESS_DELAY = 500; // ms + + @VisibleForTesting void setZeroDialogPressDelayForTesting() { + mDialogPressDelay = 0; // ms + } private Handler mHandler = new Handler() { public void handleMessage(Message msg) { diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java index 9873d240efe3..62efd8ce4cee 100644 --- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java +++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java @@ -44,9 +44,11 @@ import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; +import androidx.annotation.Nullable; import androidx.core.graphics.drawable.RoundedBitmapDrawable; import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory; +import com.android.settingslib.media.LocalMediaManager; import com.android.settingslib.media.MediaDevice; import com.android.settingslib.media.MediaOutputSliceConstants; import com.android.settingslib.widget.AdaptiveIcon; @@ -66,6 +68,7 @@ import java.util.concurrent.Executor; public class MediaControlPanel { private static final String TAG = "MediaControlPanel"; private final NotificationMediaManager mMediaManager; + @Nullable private final LocalMediaManager mLocalMediaManager; private final Executor mForegroundExecutor; private final Executor mBackgroundExecutor; @@ -77,6 +80,7 @@ public class MediaControlPanel { private int mForegroundColor; private int mBackgroundColor; protected ComponentName mRecvComponent; + private MediaDevice mDevice; private boolean mIsRegistered = false; private final int[] mActionIds; @@ -121,19 +125,44 @@ public class MediaControlPanel { } }; + private final LocalMediaManager.DeviceCallback mDeviceCallback = + new LocalMediaManager.DeviceCallback() { + @Override + public void onDeviceListUpdate(List<MediaDevice> devices) { + if (mLocalMediaManager == null) { + return; + } + MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); + // Check because this can be called several times while changing devices + if (mDevice == null || !mDevice.equals(currentDevice)) { + mDevice = currentDevice; + updateDevice(mDevice); + } + } + + @Override + public void onSelectedDeviceStateChanged(MediaDevice device, int state) { + if (mDevice == null || !mDevice.equals(device)) { + mDevice = device; + updateDevice(mDevice); + } + } + }; + /** * Initialize a new control panel * @param context * @param parent * @param manager + * @param routeManager Manager used to listen for device change events. * @param layoutId layout resource to use for this control panel * @param actionIds resource IDs for action buttons in the layout * @param foregroundExecutor foreground executor * @param backgroundExecutor background executor, used for processing artwork */ public MediaControlPanel(Context context, ViewGroup parent, NotificationMediaManager manager, - @LayoutRes int layoutId, int[] actionIds, Executor foregroundExecutor, - Executor backgroundExecutor) { + @Nullable LocalMediaManager routeManager, @LayoutRes int layoutId, int[] actionIds, + Executor foregroundExecutor, Executor backgroundExecutor) { mContext = context; LayoutInflater inflater = LayoutInflater.from(mContext); mMediaNotifView = (LinearLayout) inflater.inflate(layoutId, parent, false); @@ -144,6 +173,7 @@ public class MediaControlPanel { // mStateListener to be unregistered in detach. mMediaNotifView.addOnAttachStateChangeListener(mStateListener); mMediaManager = manager; + mLocalMediaManager = routeManager; mActionIds = actionIds; mForegroundExecutor = foregroundExecutor; mBackgroundExecutor = backgroundExecutor; @@ -176,7 +206,7 @@ public class MediaControlPanel { * @param device */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, - int bgColor, PendingIntent contentIntent, String appNameString, MediaDevice device) { + int bgColor, PendingIntent contentIntent, String appNameString) { mToken = token; mForegroundColor = iconColor; mBackgroundColor = bgColor; @@ -253,9 +283,9 @@ public class MediaControlPanel { // Transfer chip mSeamless = mMediaNotifView.findViewById(R.id.media_seamless); - if (mSeamless != null) { + if (mSeamless != null && mLocalMediaManager != null) { mSeamless.setVisibility(View.VISIBLE); - updateDevice(device); + updateDevice(mLocalMediaManager.getCurrentConnectedDevice()); ActivityStarter mActivityStarter = Dependency.get(ActivityStarter.class); mSeamless.setOnClickListener(v -> { final Intent intent = new Intent() @@ -366,7 +396,7 @@ public class MediaControlPanel { * Update the current device information * @param device device information to display */ - public void updateDevice(MediaDevice device) { + private void updateDevice(MediaDevice device) { if (mSeamless == null) { return; } @@ -456,6 +486,10 @@ public class MediaControlPanel { Assert.isMainThread(); if (!mIsRegistered) { mMediaManager.addCallback(mMediaListener); + if (mLocalMediaManager != null) { + mLocalMediaManager.registerCallback(mDeviceCallback); + mLocalMediaManager.startScan(); + } mIsRegistered = true; } } @@ -463,6 +497,10 @@ public class MediaControlPanel { private void makeInactive() { Assert.isMainThread(); if (mIsRegistered) { + if (mLocalMediaManager != null) { + mLocalMediaManager.stopScan(); + mLocalMediaManager.unregisterCallback(mDeviceCallback); + } mMediaManager.removeCallback(mMediaListener); mIsRegistered = false; } diff --git a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt index cf8f26841cf9..dd83e42cde2d 100644 --- a/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt +++ b/packages/SystemUI/src/com/android/systemui/media/SeekBarViewModel.kt @@ -34,8 +34,13 @@ private const val POSITION_UPDATE_INTERVAL_MILLIS = 100L /** ViewModel for seek bar in QS media player. */ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { + private var _data = Progress(false, false, null, null, null) + set(value) { + field = value + _progress.postValue(value) + } private val _progress = MutableLiveData<Progress>().apply { - postValue(Progress(false, false, null, null, null)) + postValue(_data) } val progress: LiveData<Progress> get() = _progress @@ -73,7 +78,7 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { val position = playbackState?.position?.toInt() val duration = mediaMetadata?.getLong(MediaMetadata.METADATA_KEY_DURATION)?.toInt() val enabled = if (duration != null && duration <= 0) false else true - _progress.postValue(Progress(enabled, seekAvailable, position, duration, color)) + _data = Progress(enabled, seekAvailable, position, duration, color) if (shouldPollPlaybackPosition()) { checkPlaybackPosition() } @@ -82,8 +87,8 @@ class SeekBarViewModel(val bgExecutor: DelayableExecutor) { @AnyThread private fun checkPlaybackPosition(): Runnable = bgExecutor.executeDelayed({ val currentPosition = controller?.playbackState?.position?.toInt() - if (currentPosition != null && _progress.value!!.elapsedTime != currentPosition) { - _progress.postValue(_progress.value!!.copy(elapsedTime = currentPosition)) + if (currentPosition != null && _data.elapsedTime != currentPosition) { + _data = _data.copy(elapsedTime = currentPosition) } if (shouldPollPlaybackPosition()) { checkPlaybackPosition() diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java index d2994aebeb33..a95d6b7a73cd 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java +++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java @@ -317,17 +317,22 @@ public class PipTaskOrganizer extends TaskOrganizer { /** * TODO(b/152809058): consolidate the display info handling logic in SysUI + * + * @param destinationBoundsOut the current destination bounds will be populated to this param */ @SuppressWarnings("unchecked") - public void onMovementBoundsChanged(boolean fromImeAdjustment, boolean fromShelfAdjustment) { + public void onMovementBoundsChanged(Rect destinationBoundsOut, + boolean fromImeAdjustment, boolean fromShelfAdjustment) { final PipAnimationController.PipTransitionAnimator animator = mPipAnimationController.getCurrentAnimator(); + destinationBoundsOut.set(mLastReportedBounds); if (animator == null || !animator.isRunning() || animator.getTransitionDirection() != TRANSITION_DIRECTION_TO_PIP) { return; } final Rect currentDestinationBounds = animator.getDestinationBounds(); + destinationBoundsOut.set(currentDestinationBounds); if (!fromImeAdjustment && !fromShelfAdjustment && mPipBoundsHandler.getDisplayBounds().contains(currentDestinationBounds)) { // no need to update the destination bounds, bail early @@ -342,6 +347,7 @@ public class PipTaskOrganizer extends TaskOrganizer { animator.updateEndValue(newDestinationBounds); } animator.setDestinationBounds(newDestinationBounds); + destinationBoundsOut.set(newDestinationBounds); } /** 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 918c45b52d61..a2667d9a4c74 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java @@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED; import static com.android.systemui.pip.PipAnimationController.TRANSITION_DIRECTION_TO_FULLSCREEN; +import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityTaskManager; import android.app.IActivityManager; @@ -160,9 +161,9 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { - mHandler.post(() -> updateMovementBounds(animatingBounds, fromImeAdjustment, - false /* fromShelfAdjustment */)); + public void onMovementBoundsChanged(boolean fromImeAdjustment) { + mHandler.post(() -> updateMovementBounds(null /* toBounds */, + fromImeAdjustment, false /* fromShelfAdjustment */)); } @Override @@ -352,17 +353,19 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mMenuController.onPinnedStackAnimationEnded(); } - private void updateMovementBounds(Rect animatingBounds, boolean fromImeAdjustment, - boolean fromShelfAdjustment) { + private void updateMovementBounds(@Nullable Rect toBounds, + boolean fromImeAdjustment, boolean fromShelfAdjustment) { // Populate inset / normal bounds and DisplayInfo from mPipBoundsHandler before - // passing to mTouchHandler, mTouchHandler would rely on the bounds calculated by - // mPipBoundsHandler with up-to-dated information + // passing to mTouchHandler/mPipTaskOrganizer + final Rect outBounds = new Rect(toBounds); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, mTmpDisplayInfo); + outBounds, mTmpDisplayInfo); + // mTouchHandler would rely on the bounds populated from mPipTaskOrganizer + mPipTaskOrganizer.onMovementBoundsChanged(outBounds, + fromImeAdjustment, fromShelfAdjustment); mTouchHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, fromImeAdjustment, fromShelfAdjustment, + outBounds, fromImeAdjustment, fromShelfAdjustment, mTmpDisplayInfo.rotation); - mPipTaskOrganizer.onMovementBoundsChanged(fromImeAdjustment, fromShelfAdjustment); } public void dump(PrintWriter pw) { 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 1e9daab4a0b6..ddba9eab7766 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipTouchHandler.java @@ -380,11 +380,18 @@ public class PipTouchHandler { } // Re-calculate the expanded bounds - mNormalBounds = normalBounds; + mNormalBounds.set(normalBounds); Rect normalMovementBounds = new Rect(); mSnapAlgorithm.getMovementBounds(mNormalBounds, insetBounds, normalMovementBounds, bottomOffset); + if (mMovementBounds.isEmpty()) { + // mMovementBounds is not initialized yet and a clean movement bounds without + // bottom offset shall be used later in this function. + mSnapAlgorithm.getMovementBounds(curBounds, insetBounds, mMovementBounds, + 0 /* bottomOffset */); + } + // Calculate the expanded size float aspectRatio = (float) normalBounds.width() / normalBounds.height(); Point displaySize = new Point(); @@ -430,8 +437,8 @@ public class PipTouchHandler { // Update the movement bounds after doing the calculations based on the old movement bounds // above - mNormalMovementBounds = normalMovementBounds; - mExpandedMovementBounds = expandedMovementBounds; + mNormalMovementBounds.set(normalMovementBounds); + mExpandedMovementBounds.set(expandedMovementBounds); mDisplayRotation = displayRotation; mInsetBounds.set(insetBounds); updateMovementBounds(); diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java index 99a01d3f6a7f..3a2d786cebe4 100644 --- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java +++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java @@ -208,12 +208,13 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio } @Override - public void onMovementBoundsChanged(Rect animatingBounds, boolean fromImeAdjustment) { + public void onMovementBoundsChanged(boolean fromImeAdjustment) { mHandler.post(() -> { // Populate the inset / normal bounds and DisplayInfo from mPipBoundsHandler first. + final Rect destinationBounds = new Rect(); mPipBoundsHandler.onMovementBoundsChanged(mTmpInsetBounds, mTmpNormalBounds, - animatingBounds, mTmpDisplayInfo); - mDefaultPipBounds.set(animatingBounds); + destinationBounds, mTmpDisplayInfo); + mDefaultPipBounds.set(destinationBounds); }); } @@ -239,6 +240,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mInitialized = true; mContext = context; mPipBoundsHandler = pipBoundsHandler; + // Ensure that we have the display info in case we get calls to update the bounds before the + // listener calls back + final DisplayInfo displayInfo = new DisplayInfo(); + context.getDisplay().getDisplayInfo(displayInfo); + mPipBoundsHandler.onDisplayInfoChanged(displayInfo); + mResizeAnimationDuration = context.getResources() .getInteger(R.integer.config_pipResizeAnimationDuration); mPipTaskOrganizer = new PipTaskOrganizer(mContext, mPipBoundsHandler, @@ -455,8 +462,12 @@ public class PipManager implements BasePipManager, PipTaskOrganizer.PipTransitio mCurrentPipBounds = mPipBounds; break; } - mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration, - null); + if (mCurrentPipBounds != null) { + mPipTaskOrganizer.scheduleAnimateResizePip(mCurrentPipBounds, mResizeAnimationDuration, + null); + } else { + mPipTaskOrganizer.dismissPip(mResizeAnimationDuration); + } } /** diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java index 339a408d501a..e636707a9722 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSMediaPlayer.java @@ -34,7 +34,7 @@ import android.widget.LinearLayout; import android.widget.SeekBar; import android.widget.TextView; -import com.android.settingslib.media.MediaDevice; +import com.android.settingslib.media.LocalMediaManager; import com.android.systemui.R; import com.android.systemui.media.MediaControlPanel; import com.android.systemui.media.SeekBarObserver; @@ -74,9 +74,10 @@ public class QSMediaPlayer extends MediaControlPanel { * @param backgroundExecutor */ public QSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, - Executor foregroundExecutor, DelayableExecutor backgroundExecutor) { - super(context, parent, manager, R.layout.qs_media_panel, QS_ACTION_IDS, foregroundExecutor, - backgroundExecutor); + LocalMediaManager routeManager, Executor foregroundExecutor, + DelayableExecutor backgroundExecutor) { + super(context, parent, manager, routeManager, R.layout.qs_media_panel, QS_ACTION_IDS, + foregroundExecutor, backgroundExecutor); mParent = (QSPanel) parent; mBackgroundExecutor = backgroundExecutor; mSeekBarViewModel = new SeekBarViewModel(backgroundExecutor); @@ -101,12 +102,12 @@ public class QSMediaPlayer extends MediaControlPanel { * @param device current playback device */ public void setMediaSession(MediaSession.Token token, Icon icon, int iconColor, - int bgColor, View actionsContainer, Notification notif, MediaDevice device) { + int bgColor, View actionsContainer, Notification notif) { String appName = Notification.Builder.recoverBuilder(getContext(), notif) .loadHeaderAppName(); super.setMediaSession(token, icon, iconColor, bgColor, notif.contentIntent, - appName, device); + appName); // Media controls LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java index c8412fffd143..0566b2e621db 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QSPanel.java @@ -47,7 +47,6 @@ import com.android.settingslib.Utils; import com.android.settingslib.bluetooth.LocalBluetoothManager; import com.android.settingslib.media.InfoMediaManager; import com.android.settingslib.media.LocalMediaManager; -import com.android.settingslib.media.MediaDevice; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.R; @@ -75,7 +74,6 @@ import java.io.FileDescriptor; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.concurrent.Executor; import java.util.stream.Collectors; @@ -105,8 +103,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private final LocalBluetoothManager mLocalBluetoothManager; private final Executor mForegroundExecutor; private final DelayableExecutor mBackgroundExecutor; - private LocalMediaManager mLocalMediaManager; - private MediaDevice mDevice; private boolean mUpdateCarousel = false; protected boolean mExpanded; @@ -130,34 +126,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne private BrightnessMirrorController mBrightnessMirrorController; private View mDivider; - private final LocalMediaManager.DeviceCallback mDeviceCallback = - new LocalMediaManager.DeviceCallback() { - @Override - public void onDeviceListUpdate(List<MediaDevice> devices) { - if (mLocalMediaManager == null) { - return; - } - MediaDevice currentDevice = mLocalMediaManager.getCurrentConnectedDevice(); - // Check because this can be called several times while changing devices - if (mDevice == null || !mDevice.equals(currentDevice)) { - mDevice = currentDevice; - for (QSMediaPlayer p : mMediaPlayers) { - p.updateDevice(mDevice); - } - } - } - - @Override - public void onSelectedDeviceStateChanged(MediaDevice device, int state) { - if (mDevice == null || !mDevice.equals(device)) { - mDevice = device; - for (QSMediaPlayer p : mMediaPlayers) { - p.updateDevice(mDevice); - } - } - } - }; - @Inject public QSPanel( @Named(VIEW_CONTEXT) Context context, @@ -277,7 +245,14 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne if (player == null) { Log.d(TAG, "creating new player"); - player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, + // Set up listener for device changes + // TODO: integrate with MediaTransferManager? + InfoMediaManager imm = new InfoMediaManager(mContext, notif.getPackageName(), + notif.getNotification(), mLocalBluetoothManager); + LocalMediaManager routeManager = new LocalMediaManager(mContext, mLocalBluetoothManager, + imm, notif.getPackageName()); + + player = new QSMediaPlayer(mContext, this, mNotificationMediaManager, routeManager, mForegroundExecutor, mBackgroundExecutor); player.setListening(mListening); if (player.isPlaying()) { @@ -292,22 +267,10 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne Log.d(TAG, "setting player session"); player.setMediaSession(token, icon, iconColor, bgColor, actionsContainer, - notif.getNotification(), mDevice); + notif.getNotification()); if (mMediaPlayers.size() > 0) { ((View) mMediaCarousel.getParent()).setVisibility(View.VISIBLE); - - if (mLocalMediaManager == null) { - // Set up listener for device changes - // TODO: integrate with MediaTransferManager? - InfoMediaManager imm = - new InfoMediaManager(mContext, null, null, mLocalBluetoothManager); - mLocalMediaManager = new LocalMediaManager(mContext, mLocalBluetoothManager, imm, - null); - mLocalMediaManager.startScan(); - mDevice = mLocalMediaManager.getCurrentConnectedDevice(); - mLocalMediaManager.registerCallback(mDeviceCallback); - } } } @@ -330,11 +293,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mMediaCarousel.removeView(player.getView()); if (mMediaPlayers.size() == 0) { ((View) mMediaCarousel.getParent()).setVisibility(View.GONE); - if (mLocalMediaManager != null) { - mLocalMediaManager.stopScan(); - mLocalMediaManager.unregisterCallback(mDeviceCallback); - mLocalMediaManager = null; - } } return true; } @@ -404,11 +362,6 @@ public class QSPanel extends LinearLayout implements Tunable, Callback, Brightne mBrightnessMirrorController.removeCallback(this); } mDumpManager.unregisterDumpable(getDumpableTag()); - if (mLocalMediaManager != null) { - mLocalMediaManager.stopScan(); - mLocalMediaManager.unregisterCallback(mDeviceCallback); - mLocalMediaManager = null; - } super.onDetachedFromWindow(); } diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java index 0c5019491a59..0ba4cb159024 100644 --- a/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java +++ b/packages/SystemUI/src/com/android/systemui/qs/QuickQSMediaPlayer.java @@ -53,7 +53,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel { */ public QuickQSMediaPlayer(Context context, ViewGroup parent, NotificationMediaManager manager, Executor foregroundExecutor, Executor backgroundExecutor) { - super(context, parent, manager, R.layout.qqs_media_panel, QQS_ACTION_IDS, + super(context, parent, manager, null, R.layout.qqs_media_panel, QQS_ACTION_IDS, foregroundExecutor, backgroundExecutor); } @@ -84,7 +84,7 @@ public class QuickQSMediaPlayer extends MediaControlPanel { return; } - super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null, null); + super.setMediaSession(token, icon, iconColor, bgColor, contentIntent, null); LinearLayout parentActionsLayout = (LinearLayout) actionsContainer; int i = 0; diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java index c8b34f1f5b27..4e6df0ad1ba4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java @@ -75,6 +75,9 @@ public final class NotificationClicker implements View.OnClickListener { // We never want to open the app directly if the user clicks in between // the notifications. return; + } else if (row.areGutsExposed()) { + // ignore click if guts are exposed + return; } // Mark notification for one frame. diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java index fb88ea534a91..8c9bb6c75828 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/BiometricUnlockController.java @@ -34,6 +34,7 @@ import com.android.internal.util.LatencyTracker; import com.android.keyguard.KeyguardConstants; import com.android.keyguard.KeyguardUpdateMonitor; import com.android.keyguard.KeyguardUpdateMonitorCallback; +import com.android.keyguard.KeyguardViewController; import com.android.systemui.Dependency; import com.android.systemui.Dumpable; import com.android.systemui.dagger.qualifiers.Main; @@ -145,7 +146,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private final Context mContext; private final int mWakeUpDelay; private int mMode; - private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager; + private KeyguardViewController mKeyguardViewController; private DozeScrimController mDozeScrimController; private KeyguardViewMediator mKeyguardViewMediator; private ScrimController mScrimController; @@ -204,9 +205,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp dumpManager.registerDumpable(getClass().getName(), this); } - public void setStatusBarKeyguardViewManager( - StatusBarKeyguardViewManager statusBarKeyguardViewManager) { - mStatusBarKeyguardViewManager = statusBarKeyguardViewManager; + public void setKeyguardViewController(KeyguardViewController keyguardViewController) { + mKeyguardViewController = keyguardViewController; } private final Runnable mReleaseBiometricWakeLockRunnable = new Runnable() { @@ -328,7 +328,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp case MODE_DISMISS_BOUNCER: case MODE_UNLOCK_FADING: Trace.beginSection("MODE_DISMISS_BOUNCER or MODE_UNLOCK_FADING"); - mStatusBarKeyguardViewManager.notifyKeyguardAuthenticated( + mKeyguardViewController.notifyKeyguardAuthenticated( false /* strongAuth */); Trace.endSection(); break; @@ -376,7 +376,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp private void showBouncer() { if (mMode == MODE_SHOW_BOUNCER) { - mStatusBarKeyguardViewManager.showBouncer(false); + mKeyguardViewController.showBouncer(false); } mShadeController.animateCollapsePanels(CommandQueue.FLAG_EXCLUDE_NONE, true /* force */, false /* delayed */, BIOMETRIC_COLLAPSE_SPEEDUP_FACTOR); @@ -431,7 +431,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean deviceDreaming = mUpdateMonitor.isDreaming(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardViewController.isShowing()) { return MODE_ONLY_WAKE; } else if (mDozeScrimController.isPulsing() && unlockingAllowed) { return MODE_WAKE_AND_UNLOCK_PULSING; @@ -444,12 +444,12 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return MODE_WAKE_AND_UNLOCK_FROM_DREAM; } - if (mStatusBarKeyguardViewManager.isShowing()) { - if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if (mKeyguardViewController.isShowing()) { + if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { return MODE_DISMISS_BOUNCER; } else if (unlockingAllowed) { return MODE_UNLOCK_COLLAPSING; - } else if (!mStatusBarKeyguardViewManager.isBouncerShowing()) { + } else if (!mKeyguardViewController.isBouncerShowing()) { return MODE_SHOW_BOUNCER; } } @@ -463,7 +463,7 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp boolean bypass = mKeyguardBypassController.getBypassEnabled(); if (!mUpdateMonitor.isDeviceInteractive()) { - if (!mStatusBarKeyguardViewManager.isShowing()) { + if (!mKeyguardViewController.isShowing()) { return bypass ? MODE_WAKE_AND_UNLOCK : MODE_ONLY_WAKE; } else if (!unlockingAllowed) { return bypass ? MODE_SHOW_BOUNCER : MODE_NONE; @@ -484,8 +484,8 @@ public class BiometricUnlockController extends KeyguardUpdateMonitorCallback imp if (unlockingAllowed && deviceDreaming) { return bypass ? MODE_WAKE_AND_UNLOCK_FROM_DREAM : MODE_ONLY_WAKE; } - if (mStatusBarKeyguardViewManager.isShowing()) { - if (mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing() && unlockingAllowed) { + if (mKeyguardViewController.isShowing()) { + if (mKeyguardViewController.bouncerIsOrWillBeShowing() && unlockingAllowed) { if (bypass && mKeyguardBypassController.canPlaySubtleWindowAnimations()) { return MODE_UNLOCK_FADING; } else { 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 fa55b74606c2..900b3ea97010 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java @@ -488,11 +488,9 @@ public class StatusBar extends SystemUI implements DemoMode, WallpaperInfo info = wallpaperManager.getWallpaperInfo(UserHandle.USER_CURRENT); final boolean deviceSupportsAodWallpaper = mContext.getResources().getBoolean( com.android.internal.R.bool.config_dozeSupportsAodWallpaper); - final boolean imageWallpaperInAmbient = !mDozeParameters.getDisplayNeedsBlanking(); // If WallpaperInfo is null, it must be ImageWallpaper. final boolean supportsAmbientMode = deviceSupportsAodWallpaper - && ((info == null && imageWallpaperInAmbient) - || (info != null && info.supportsAmbientMode())); + && (info != null && info.supportsAmbientMode()); mNotificationShadeWindowController.setWallpaperSupportsAmbientMode(supportsAmbientMode); mScrimController.setWallpaperSupportsAmbientMode(supportsAmbientMode); @@ -1399,7 +1397,7 @@ public class StatusBar extends SystemUI implements DemoMode, mStackScroller, mKeyguardBypassController, mFalsingManager); mKeyguardIndicationController .setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); mRemoteInputManager.getController().addCallback(mStatusBarKeyguardViewManager); mDynamicPrivacyController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java index 45719c7f3936..03021c2744f4 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java +++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java @@ -744,14 +744,12 @@ public class StatusBarKeyguardViewManager implements RemoteInputController.Callb return false; } + @Override public boolean isBouncerShowing() { return mBouncer.isShowing(); } - /** - * When bouncer is fully visible or {@link KeyguardBouncer#show(boolean)} was called but - * animation didn't finish yet. - */ + @Override public boolean bouncerIsOrWillBeShowing() { return mBouncer.isShowing() || mBouncer.inTransit(); } diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java index a94af24fc843..1c7a9b5e8681 100644 --- a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingActivity.java @@ -175,6 +175,9 @@ public class WifiDebuggingActivity extends AlertActivity IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); registerReceiver(mWifiChangeReceiver, filter); + // Close quick shade + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); + } @Override diff --git a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java index 0266a84503a1..7a31fa54b1cd 100644 --- a/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java +++ b/packages/SystemUI/src/com/android/systemui/wifi/WifiDebuggingSecondaryUserActivity.java @@ -96,6 +96,8 @@ public class WifiDebuggingSecondaryUserActivity extends AlertActivity IntentFilter filter = new IntentFilter(WifiManager.WIFI_STATE_CHANGED_ACTION); filter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION); registerReceiver(mWifiChangeReceiver, filter); + // Close quick shade + sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)); } @Override diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt index 8630570c4e70..f6ee46b0303a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsControllerImplTest.kt @@ -87,9 +87,6 @@ class ControlsControllerImplTest : SysuiTestCase() { private lateinit var structureInfoCaptor: ArgumentCaptor<StructureInfo> @Captor - private lateinit var booleanConsumer: ArgumentCaptor<Consumer<Boolean>> - - @Captor private lateinit var controlLoadCallbackCaptor: ArgumentCaptor<ControlsBindingController.LoadCallback> @Captor @@ -936,4 +933,33 @@ class ControlsControllerImplTest : SysuiTestCase() { verifyNoMoreInteractions(persistenceWrapper) verifyNoMoreInteractions(auxiliaryPersistenceWrapper) } + + @Test + fun testGetFavoritesForStructure() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + controller.replaceFavoritesForStructure( + TEST_STRUCTURE_INFO_2.copy(componentName = TEST_COMPONENT)) + delayableExecutor.runAllReady() + + assertEquals(TEST_STRUCTURE_INFO.controls, + controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE)) + assertEquals(TEST_STRUCTURE_INFO_2.controls, + controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE_2)) + } + + @Test + fun testGetFavoritesForStructure_wrongStructure() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + delayableExecutor.runAllReady() + + assertTrue(controller.getFavoritesForStructure(TEST_COMPONENT, TEST_STRUCTURE_2).isEmpty()) + } + + @Test + fun testGetFavoritesForStructure_wrongComponent() { + controller.replaceFavoritesForStructure(TEST_STRUCTURE_INFO) + delayableExecutor.runAllReady() + + assertTrue(controller.getFavoritesForStructure(TEST_COMPONENT_2, TEST_STRUCTURE).isEmpty()) + } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt index 5e0d28f6f795..236384b09514 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/AllModelTest.kt @@ -31,6 +31,8 @@ import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.Mock +import org.mockito.Mockito.never +import org.mockito.Mockito.verify import org.mockito.MockitoAnnotations @SmallTest @@ -43,6 +45,8 @@ class AllModelTest : SysuiTestCase() { @Mock lateinit var pendingIntent: PendingIntent + @Mock + lateinit var controlsModelCallback: ControlsModel.ControlsModelCallback val idPrefix = "controlId" val favoritesIndices = listOf(7, 3, 1, 9) @@ -84,7 +88,7 @@ class AllModelTest : SysuiTestCase() { it in favoritesIndices ) } - model = AllModel(controls, favoritesList, EMPTY_STRING) + model = AllModel(controls, favoritesList, EMPTY_STRING, controlsModelCallback) } @Test @@ -93,28 +97,28 @@ class AllModelTest : SysuiTestCase() { // Zones are sorted by order of appearance, with empty at the end with special header. val expected = listOf( ZoneNameWrapper("1"), - ControlWrapper(controls[0]), - ControlWrapper(controls[3]), - ControlWrapper(controls[6]), - ControlWrapper(controls[9]), + ControlStatusWrapper(controls[0]), + ControlStatusWrapper(controls[3]), + ControlStatusWrapper(controls[6]), + ControlStatusWrapper(controls[9]), ZoneNameWrapper("2"), - ControlWrapper(controls[1]), - ControlWrapper(controls[4]), - ControlWrapper(controls[7]), + ControlStatusWrapper(controls[1]), + ControlStatusWrapper(controls[4]), + ControlStatusWrapper(controls[7]), ZoneNameWrapper("0"), - ControlWrapper(controls[2]), - ControlWrapper(controls[5]), - ControlWrapper(controls[8]), + ControlStatusWrapper(controls[2]), + ControlStatusWrapper(controls[5]), + ControlStatusWrapper(controls[8]), ZoneNameWrapper(EMPTY_STRING), - ControlWrapper(controls[10]), - ControlWrapper(controls[11]) + ControlStatusWrapper(controls[10]), + ControlStatusWrapper(controls[11]) ) expected.zip(model.elements).forEachIndexed { index, it -> assertEquals("Error in item at index $index", it.first, it.second) } } - private fun sameControl(controlInfo: ControlInfo.Builder, control: Control): Boolean { + private fun sameControl(controlInfo: ControlInfo, control: Control): Boolean { return controlInfo.controlId == control.controlId && controlInfo.controlTitle == control.title && controlInfo.controlSubtitle == control.subtitle && @@ -124,10 +128,11 @@ class AllModelTest : SysuiTestCase() { @Test fun testAllEmpty_noHeader() { val selected_controls = listOf(controls[10], controls[11]) - val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING) + val new_model = AllModel(selected_controls, emptyList(), EMPTY_STRING, + controlsModelCallback) val expected = listOf( - ControlWrapper(controls[10]), - ControlWrapper(controls[11]) + ControlStatusWrapper(controls[10]), + ControlStatusWrapper(controls[11]) ) expected.zip(new_model.elements).forEachIndexed { index, it -> @@ -154,6 +159,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback).onFirstChange() } @Test @@ -163,10 +170,12 @@ class AllModelTest : SysuiTestCase() { model.changeFavoriteStatus(id, true) assertTrue( (model.elements.first { - it is ControlWrapper && it.controlStatus.control.controlId == id - } as ControlWrapper) + it is ControlStatusWrapper && it.controlStatus.control.controlId == id + } as ControlStatusWrapper) .controlStatus.favorite ) + + verify(controlsModelCallback).onFirstChange() } @Test @@ -180,6 +189,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback, never()).onFirstChange() } @Test @@ -194,6 +205,8 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback).onFirstChange() } @Test @@ -203,10 +216,12 @@ class AllModelTest : SysuiTestCase() { model.changeFavoriteStatus(id, false) assertFalse( (model.elements.first { - it is ControlWrapper && it.controlStatus.control.controlId == id - } as ControlWrapper) + it is ControlStatusWrapper && it.controlStatus.control.controlId == id + } as ControlStatusWrapper) .controlStatus.favorite ) + + verify(controlsModelCallback).onFirstChange() } @Test @@ -219,5 +234,7 @@ class AllModelTest : SysuiTestCase() { model.favorites.zip(expectedFavorites).forEach { assertTrue(sameControl(it.first, it.second)) } + + verify(controlsModelCallback, never()).onFirstChange() } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt deleted file mode 100644 index c330b38fed42..000000000000 --- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoriteModelTest.kt +++ /dev/null @@ -1,200 +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.controls.management - -import android.app.PendingIntent -import android.content.ComponentName -import android.service.controls.Control -import android.testing.AndroidTestingRunner -import androidx.test.filters.SmallTest -import com.android.systemui.SysuiTestCase -import com.android.systemui.controls.ControlStatus -import org.junit.Assert.assertEquals -import org.junit.Assert.assertFalse -import org.junit.Assert.assertTrue -import org.junit.Assert.fail -import org.junit.Before -import org.junit.Test -import org.junit.runner.RunWith -import org.junit.runners.Parameterized -import org.mockito.Mock -import org.mockito.Mockito.verify -import org.mockito.Mockito.verifyNoMoreInteractions -import org.mockito.MockitoAnnotations - -open class FavoriteModelTest : SysuiTestCase() { - - @Mock - lateinit var pendingIntent: PendingIntent - @Mock - lateinit var allAdapter: ControlAdapter - @Mock - lateinit var favoritesAdapter: ControlAdapter - - val idPrefix = "controlId" - val favoritesIndices = listOf(7, 3, 1, 9) - val favoritesList = favoritesIndices.map { "controlId$it" } - lateinit var controls: List<ControlStatus> - - lateinit var model: FavoriteModel - - @Before - fun setUp() { - MockitoAnnotations.initMocks(this) - - // controlId0 --> zone = 0 - // controlId1 --> zone = 1, favorite - // controlId2 --> zone = 2 - // controlId3 --> zone = 0, favorite - // controlId4 --> zone = 1 - // controlId5 --> zone = 2 - // controlId6 --> zone = 0 - // controlId7 --> zone = 1, favorite - // controlId8 --> zone = 2 - // controlId9 --> zone = 0, favorite - controls = (0..9).map { - ControlStatus( - Control.StatelessBuilder("$idPrefix$it", pendingIntent) - .setZone((it % 3).toString()) - .build(), - ComponentName("", ""), - it in favoritesIndices - ) - } - - model = FavoriteModel(controls, favoritesList, favoritesAdapter, allAdapter) - } -} - -@SmallTest -@RunWith(AndroidTestingRunner::class) -class FavoriteModelNonParametrizedTests : FavoriteModelTest() { - @Test - fun testAll() { - // Zones are sorted alphabetically - val expected = listOf( - ZoneNameWrapper("0"), - ControlWrapper(controls[0]), - ControlWrapper(controls[3]), - ControlWrapper(controls[6]), - ControlWrapper(controls[9]), - ZoneNameWrapper("1"), - ControlWrapper(controls[1]), - ControlWrapper(controls[4]), - ControlWrapper(controls[7]), - ZoneNameWrapper("2"), - ControlWrapper(controls[2]), - ControlWrapper(controls[5]), - ControlWrapper(controls[8]) - ) - assertEquals(expected, model.all) - } - - @Test - fun testFavoritesInOrder() { - val expected = favoritesIndices.map { ControlWrapper(controls[it]) } - assertEquals(expected, model.favorites) - } - - @Test - fun testChangeFavoriteStatus_addFavorite() { - val controlToAdd = 6 - model.changeFavoriteStatus("$idPrefix$controlToAdd", true) - - val pair = model.all.findControl(controlToAdd) - pair?.let { - assertTrue(it.second.favorite) - assertEquals(it.second, model.favorites.last().controlStatus) - verify(favoritesAdapter).notifyItemInserted(model.favorites.size - 1) - verify(allAdapter).notifyItemChanged(it.first) - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } ?: run { - fail("control not found") - } - } - - @Test - fun testChangeFavoriteStatus_removeFavorite() { - val controlToRemove = 3 - model.changeFavoriteStatus("$idPrefix$controlToRemove", false) - - val pair = model.all.findControl(controlToRemove) - pair?.let { - assertFalse(it.second.favorite) - assertTrue(model.favorites.none { - it.controlStatus.control.controlId == "$idPrefix$controlToRemove" - }) - verify(favoritesAdapter).notifyItemRemoved(favoritesIndices.indexOf(controlToRemove)) - verify(allAdapter).notifyItemChanged(it.first) - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } ?: run { - fail("control not found") - } - } - - @Test - fun testChangeFavoriteStatus_sameStatus() { - model.changeFavoriteStatus("${idPrefix}7", true) - model.changeFavoriteStatus("${idPrefix}6", false) - - val expected = favoritesIndices.map { ControlWrapper(controls[it]) } - assertEquals(expected, model.favorites) - - verifyNoMoreInteractions(favoritesAdapter, allAdapter) - } - - private fun List<ElementWrapper>.findControl(controlIndex: Int): Pair<Int, ControlStatus>? { - val index = indexOfFirst { - it is ControlWrapper && - it.controlStatus.control.controlId == "$idPrefix$controlIndex" - } - return if (index == -1) null else index to (get(index) as ControlWrapper).controlStatus - } -} - -@SmallTest -@RunWith(Parameterized::class) -class FavoriteModelParameterizedTest(val from: Int, val to: Int) : FavoriteModelTest() { - - companion object { - @JvmStatic - @Parameterized.Parameters(name = "{0} -> {1}") - fun data(): Collection<Array<Int>> { - return (0..3).flatMap { from -> - (0..3).map { to -> - arrayOf(from, to) - } - }.filterNot { it[0] == it[1] } - } - } - - @Test - fun testMoveItem() { - val originalFavorites = model.favorites.toList() - val originalFavoritesIds = - model.favorites.map { it.controlStatus.control.controlId }.toSet() - model.onMoveItem(from, to) - assertEquals(originalFavorites[from], model.favorites[to]) - // Check that we still have the same favorites - assertEquals(originalFavoritesIds, - model.favorites.map { it.controlStatus.control.controlId }.toSet()) - - verify(favoritesAdapter).notifyItemMoved(from, to) - - verifyNoMoreInteractions(allAdapter, favoritesAdapter) - } -} diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt new file mode 100644 index 000000000000..ce33a8d49fac --- /dev/null +++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/FavoritesModelTest.kt @@ -0,0 +1,291 @@ +/* + * 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.management + +import android.content.ComponentName +import android.testing.AndroidTestingRunner +import androidx.recyclerview.widget.RecyclerView +import androidx.test.filters.SmallTest +import com.android.systemui.SysuiTestCase +import com.android.systemui.controls.ControlInterface +import com.android.systemui.controls.controller.ControlInfo +import com.android.systemui.util.mockito.any +import com.android.systemui.util.mockito.eq +import org.junit.After +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.ArgumentMatchers.anyInt +import org.mockito.Mock +import org.mockito.Mockito.inOrder +import org.mockito.Mockito.never +import org.mockito.Mockito.times +import org.mockito.Mockito.verify +import org.mockito.Mockito.verifyNoMoreInteractions +import org.mockito.MockitoAnnotations + +@SmallTest +@RunWith(AndroidTestingRunner::class) +class FavoritesModelTest : SysuiTestCase() { + + companion object { + private val TEST_COMPONENT = ComponentName.unflattenFromString("test_pkg/.test_cls")!! + private val ID_PREFIX = "control" + private val INITIAL_FAVORITES = (0..5).map { + ControlInfo("$ID_PREFIX$it", "title$it", "subtitle$it", it) + } + } + + @Mock + private lateinit var callback: FavoritesModel.FavoritesModelCallback + @Mock + private lateinit var adapter: RecyclerView.Adapter<*> + private lateinit var model: FavoritesModel + private lateinit var dividerWrapper: DividerWrapper + + @Before + fun setUp() { + MockitoAnnotations.initMocks(this) + + model = FavoritesModel(TEST_COMPONENT, INITIAL_FAVORITES, callback) + model.attachAdapter(adapter) + dividerWrapper = model.elements.first { it is DividerWrapper } as DividerWrapper + } + + @After + fun testListConsistency() { + assertEquals(INITIAL_FAVORITES.size + 1, model.elements.toSet().size) + val dividerIndex = getDividerPosition() + model.elements.forEachIndexed { index, element -> + if (index == dividerIndex) { + assertEquals(dividerWrapper, element) + } else { + element as ControlInterface + assertEquals(index < dividerIndex, element.favorite) + } + } + assertEquals(model.favorites, model.elements.take(dividerIndex).map { + (it as ControlInfoWrapper).controlInfo + }) + } + + @Test + fun testInitialElements() { + val expected = INITIAL_FAVORITES.map { + ControlInfoWrapper(TEST_COMPONENT, it, true) + } + DividerWrapper() + assertEquals(expected, model.elements) + } + + @Test + fun testFavorites() { + assertEquals(INITIAL_FAVORITES, model.favorites) + } + + @Test + fun testRemoveFavorite_notInFavorites() { + val removed = 4 + val id = "$ID_PREFIX$removed" + + model.changeFavoriteStatus(id, false) + + assertTrue(model.favorites.none { it.controlId == id }) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_endOfElements() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertEquals(ControlInfoWrapper( + TEST_COMPONENT, INITIAL_FAVORITES[4], false), model.elements.last()) + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_adapterNotified() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + val lastPos = model.elements.size - 1 + verify(adapter).notifyItemChanged(eq(lastPos), any(Any::class.java)) + verify(adapter).notifyItemMoved(removed, lastPos) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_dividerMovedBack() { + val oldDividerPosition = getDividerPosition() + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertEquals(oldDividerPosition - 1, getDividerPosition()) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveFavorite_ShowDivider() { + val oldDividerPosition = getDividerPosition() + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + + assertTrue(dividerWrapper.showDivider) + verify(adapter).notifyItemChanged(oldDividerPosition) + + verify(callback).onFirstChange() + } + + @Test + fun testDoubleRemove_onlyOnce() { + val removed = 4 + val id = "$ID_PREFIX$removed" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, false) + + verify(adapter /* only once */).notifyItemChanged(anyInt(), any(Any::class.java)) + verify(adapter /* only once */).notifyItemMoved(anyInt(), anyInt()) + verify(adapter /* only once (divider) */).notifyItemChanged(anyInt()) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveTwo_InSameOrder() { + val removedFirst = 3 + val removedSecond = 0 + model.changeFavoriteStatus("$ID_PREFIX$removedFirst", false) + model.changeFavoriteStatus("$ID_PREFIX$removedSecond", false) + + assertEquals(listOf( + ControlInfoWrapper(TEST_COMPONENT, INITIAL_FAVORITES[removedFirst], false), + ControlInfoWrapper(TEST_COMPONENT, INITIAL_FAVORITES[removedSecond], false) + ), model.elements.takeLast(2)) + + verify(callback).onFirstChange() + } + + @Test + fun testRemoveAll_showNone() { + INITIAL_FAVORITES.forEach { + model.changeFavoriteStatus(it.controlId, false) + } + assertEquals(dividerWrapper, model.elements.first()) + assertTrue(dividerWrapper.showNone) + verify(adapter, times(2)).notifyItemChanged(anyInt()) // divider + verify(callback).onNoneChanged(true) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_movedToEnd() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + + assertEquals(id, model.favorites.last().controlId) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_onlyOnce() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + model.changeFavoriteStatus(id, true) + + // Once for remove and once for add + verify(adapter, times(2)).notifyItemChanged(anyInt(), any(Any::class.java)) + verify(adapter, times(2)).notifyItemMoved(anyInt(), anyInt()) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFavorite_notRemoved() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, true) + + verifyNoMoreInteractions(adapter) + + verify(callback, never()).onFirstChange() + } + + @Test + fun testAddOnlyRemovedFavorite_dividerStopsShowing() { + val added = 2 + val id = "$ID_PREFIX$added" + model.changeFavoriteStatus(id, false) + model.changeFavoriteStatus(id, true) + + assertFalse(dividerWrapper.showDivider) + val inOrder = inOrder(adapter) + inOrder.verify(adapter).notifyItemChanged(model.elements.size - 1) + inOrder.verify(adapter).notifyItemChanged(model.elements.size - 2) + + verify(callback).onFirstChange() + } + + @Test + fun testAddFirstFavorite_dividerNotShowsNone() { + INITIAL_FAVORITES.forEach { + model.changeFavoriteStatus(it.controlId, false) + } + + verify(callback).onNoneChanged(true) + + model.changeFavoriteStatus("${ID_PREFIX}3", true) + assertEquals(1, getDividerPosition()) + + verify(callback).onNoneChanged(false) + + verify(callback).onFirstChange() + } + + @Test + fun testMoveBetweenFavorites() { + val from = 2 + val to = 4 + + model.onMoveItem(from, to) + assertEquals( + listOf(0, 1, 3, 4, 2, 5).map { "$ID_PREFIX$it" }, + model.favorites.map(ControlInfo::controlId) + ) + verify(adapter).notifyItemMoved(from, to) + verify(adapter, never()).notifyItemChanged(anyInt(), any(Any::class.java)) + + verify(callback).onFirstChange() + } + + private fun getDividerPosition(): Int = model.elements.indexOf(dividerWrapper) +}
\ No newline at end of file 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 300cb212ffb1..3af164db4b80 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/globalactions/GlobalActionsDialogTest.java @@ -32,6 +32,7 @@ import android.service.dreams.IDreamManager; import android.telephony.TelephonyManager; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.util.FeatureFlagUtils; import android.view.IWindowManager; import androidx.test.filters.SmallTest; @@ -66,7 +67,7 @@ import java.util.concurrent.Executor; @SmallTest @RunWith(AndroidTestingRunner.class) -@TestableLooper.RunWithLooper +@TestableLooper.RunWithLooper() public class GlobalActionsDialogTest extends SysuiTestCase { private GlobalActionsDialog mGlobalActionsDialog; @@ -143,11 +144,60 @@ public class GlobalActionsDialogTest extends SysuiTestCase { mUiEventLogger, mRingerModeTracker ); + mGlobalActionsDialog.setZeroDialogPressDelayForTesting(); } + @Test public void testShouldLogVisibility() { mGlobalActionsDialog.onShow(null); + mTestableLooper.processAllMessages(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); + } + + @Test + public void testShouldLogBugreportPress() throws InterruptedException { + GlobalActionsDialog.BugReportAction bugReportAction = + mGlobalActionsDialog.makeBugReportActionForTesting(); + bugReportAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_PRESS); + } + + @Test + public void testShouldLogBugreportLongPress() { + GlobalActionsDialog.BugReportAction bugReportAction = + mGlobalActionsDialog.makeBugReportActionForTesting(); + bugReportAction.onLongPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_BUGREPORT_LONG_PRESS); + } + + @Test + public void testShouldLogEmergencyDialerPress() { + GlobalActionsDialog.EmergencyDialerAction emergencyDialerAction = + mGlobalActionsDialog.makeEmergencyDialerActionForTesting(); + emergencyDialerAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_EMERGENCY_DIALER_PRESS); + } + + @Test + public void testShouldLogScreenshotPress() { + GlobalActionsDialog.ScreenshotAction screenshotAction = + mGlobalActionsDialog.makeScreenshotActionForTesting(); + screenshotAction.onPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_PRESS); + } + + @Test + public void testShouldLogScreenshotLongPress() { + FeatureFlagUtils.setEnabled(mContext, FeatureFlagUtils.SCREENRECORD_LONG_PRESS, true); + GlobalActionsDialog.ScreenshotAction screenshotAction = + mGlobalActionsDialog.makeScreenshotActionForTesting(); + screenshotAction.onLongPress(); + verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent.GA_SCREENSHOT_LONG_PRESS); + } + + private void verifyLogPosted(GlobalActionsDialog.GlobalActionsEvent event) { + mTestableLooper.processAllMessages(); verify(mUiEventLogger, times(1)) - .log(GlobalActionsDialog.GlobalActionsEvent.GA_POWER_MENU_OPEN); + .log(event); } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java index 4d7e6aec8aa9..721125409c5a 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/pip/phone/PipTouchHandlerTest.java @@ -29,7 +29,6 @@ import android.graphics.Rect; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.util.Size; -import android.view.DisplayInfo; import androidx.test.filters.SmallTest; @@ -59,12 +58,8 @@ import org.mockito.MockitoAnnotations; @SmallTest @TestableLooper.RunWithLooper(setAsMainLooper = true) public class PipTouchHandlerTest extends SysuiTestCase { - private static final int ROUNDING_ERROR_MARGIN = 10; - private static final float DEFAULT_ASPECT_RATIO = 1f; - private static final Rect EMPTY_CURRENT_BOUNDS = null; private PipTouchHandler mPipTouchHandler; - private DisplayInfo mDefaultDisplayInfo; @Mock private IActivityManager mActivityManager; @@ -90,18 +85,17 @@ public class PipTouchHandlerTest extends SysuiTestCase { @Mock private DeviceConfigProxy mDeviceConfigProxy; - private PipSnapAlgorithm mPipSnapAlgorithm; private PipMotionHelper mMotionHelper; private PipResizeGestureHandler mPipResizeGestureHandler; - Rect mInsetBounds; - Rect mMinBounds; - Rect mCurBounds; - boolean mFromImeAdjustment; - boolean mFromShelfAdjustment; - int mDisplayRotation; - + private Rect mInsetBounds; + private Rect mMinBounds; + private Rect mCurBounds; + private boolean mFromImeAdjustment; + private boolean mFromShelfAdjustment; + private int mDisplayRotation; + private int mImeHeight; @Before public void setUp() throws Exception { @@ -121,10 +115,11 @@ public class PipTouchHandlerTest extends SysuiTestCase { mInsetBounds = new Rect(10, 10, 990, 990); // minBounds of 100x100 bottom right corner mMinBounds = new Rect(890, 890, 990, 990); - mCurBounds = new Rect(); + mCurBounds = new Rect(mMinBounds); mFromImeAdjustment = false; mFromShelfAdjustment = false; mDisplayRotation = 0; + mImeHeight = 100; } @Test @@ -162,6 +157,8 @@ public class PipTouchHandlerTest extends SysuiTestCase { @Test public void updateMovementBounds_withImeAdjustment_movesPip() { mFromImeAdjustment = true; + mPipTouchHandler.onImeVisibilityChanged(true /* imeVisible */, mImeHeight); + mPipTouchHandler.onMovementBoundsChanged(mInsetBounds, mMinBounds, mCurBounds, mFromImeAdjustment, mFromShelfAdjustment, mDisplayRotation); diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java index bfcf41db5287..a927c8011b8f 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/BiometricsUnlockControllerTest.java @@ -109,7 +109,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { mNotificationShadeWindowController, mKeyguardStateController, mHandler, mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters, mMetricsLogger, mDumpManager); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); } @Test @@ -202,7 +202,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFace_andBypass_dismissKeyguard() { when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(true); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -221,7 +221,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { public void onBiometricAuthenticated_whenFace_andBypass_encrypted_showBouncer() { reset(mUpdateMonitor); when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); // the value of isStrongBiometric doesn't matter here since we only care about the returned @@ -241,7 +241,7 @@ public class BiometricsUnlockControllerTest extends SysuiTestCase { @Test public void onBiometricAuthenticated_whenFace_noBypass_encrypted_doNothing() { reset(mUpdateMonitor); - mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager); + mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager); when(mUpdateMonitor.isUnlockingWithBiometricAllowed(anyBoolean())).thenReturn(false); // the value of isStrongBiometric doesn't matter here since we only care about the returned diff --git a/packages/Tethering/Android.bp b/packages/Tethering/Android.bp index 190b443227ce..5b052df75ede 100644 --- a/packages/Tethering/Android.bp +++ b/packages/Tethering/Android.bp @@ -25,7 +25,7 @@ java_defaults { ], static_libs: [ "androidx.annotation_annotation", - "netd_aidl_interface-unstable-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-aidl-interfaces-unstable-java", "android.hardware.tetheroffload.config-V1.0-java", diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java index 350980137f3e..cc095a0bb4a7 100644 --- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java +++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java @@ -571,9 +571,8 @@ public class TetheringManager { /** * Configure tethering with static IPv4 assignment. * - * The clientAddress must be in the localIPv4Address prefix. A DHCP server will be - * started, but will only be able to offer the client address. The two addresses must - * be in the same prefix. + * A DHCP server will be started, but will only be able to offer the client address. + * The two addresses must be in the same prefix. * * @param localIPv4Address The preferred local IPv4 link address to use. * @param clientAddress The static client address. @@ -584,10 +583,7 @@ public class TetheringManager { @NonNull final LinkAddress clientAddress) { Objects.requireNonNull(localIPv4Address); Objects.requireNonNull(clientAddress); - if (localIPv4Address.getPrefixLength() != clientAddress.getPrefixLength() - || !localIPv4Address.isIpv4() || !clientAddress.isIpv4() - || !new IpPrefix(localIPv4Address.toString()).equals( - new IpPrefix(clientAddress.toString()))) { + if (!checkStaticAddressConfiguration(localIPv4Address, clientAddress)) { throw new IllegalArgumentException("Invalid server or client addresses"); } @@ -657,6 +653,19 @@ public class TetheringManager { } /** + * Check whether the two addresses are ipv4 and in the same prefix. + * @hide + */ + public static boolean checkStaticAddressConfiguration( + @NonNull final LinkAddress localIPv4Address, + @NonNull final LinkAddress clientAddress) { + return localIPv4Address.getPrefixLength() == clientAddress.getPrefixLength() + && localIPv4Address.isIpv4() && clientAddress.isIpv4() + && new IpPrefix(localIPv4Address.toString()).equals( + new IpPrefix(clientAddress.toString())); + } + + /** * Get a TetheringRequestParcel from the configuration * @hide */ diff --git a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java index d6bc063210b3..82a26beadacf 100644 --- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java +++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java @@ -18,10 +18,12 @@ package android.net.dhcp; import static android.net.shared.Inet4AddressUtils.inet4AddressToIntHTH; -import android.annotation.NonNull; import android.net.LinkAddress; import android.util.ArraySet; +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + import java.net.Inet4Address; import java.util.Collection; import java.util.Collections; @@ -160,6 +162,17 @@ public class DhcpServingParamsParcelExt extends DhcpServingParamsParcel { return this; } + /** + * Set the client address to tell DHCP server only offer this address. + * The client's prefix length is the same as server's. + * + * <p>If not set, the default value is null. + */ + public DhcpServingParamsParcelExt setSingleClientAddr(@Nullable Inet4Address clientAddr) { + this.clientAddr = clientAddr == null ? 0 : inet4AddressToIntHTH(clientAddr); + return this; + } + private static int[] toIntArray(@NonNull Collection<Inet4Address> addrs) { int[] res = new int[addrs.size()]; int i = 0; diff --git a/packages/Tethering/src/android/net/ip/IpServer.java b/packages/Tethering/src/android/net/ip/IpServer.java index 5b6fe91b9c1a..1dac5b784649 100644 --- a/packages/Tethering/src/android/net/ip/IpServer.java +++ b/packages/Tethering/src/android/net/ip/IpServer.java @@ -18,6 +18,7 @@ package android.net.ip; import static android.net.InetAddresses.parseNumericAddress; import static android.net.RouteInfo.RTN_UNICAST; +import static android.net.TetheringManager.TetheringRequest.checkStaticAddressConfiguration; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.util.NetworkConstants.FF; @@ -511,17 +512,24 @@ public class IpServer extends StateMachine { } } - private boolean startDhcp(Inet4Address addr, int prefixLen) { + private boolean startDhcp(final LinkAddress serverLinkAddr, final LinkAddress clientLinkAddr) { if (mUsingLegacyDhcp) { return true; } + + final Inet4Address addr = (Inet4Address) serverLinkAddr.getAddress(); + final int prefixLen = serverLinkAddr.getPrefixLength(); + final Inet4Address clientAddr = clientLinkAddr == null ? null : + (Inet4Address) clientLinkAddr.getAddress(); + final DhcpServingParamsParcel params; params = new DhcpServingParamsParcelExt() .setDefaultRouters(addr) .setDhcpLeaseTimeSecs(DHCP_LEASE_TIME_SECS) .setDnsServers(addr) - .setServerAddr(new LinkAddress(addr, prefixLen)) - .setMetered(true); + .setServerAddr(serverLinkAddr) + .setMetered(true) + .setSingleClientAddr(clientAddr); // TODO: also advertise link MTU mDhcpServerStartIndex++; @@ -556,9 +564,10 @@ public class IpServer extends StateMachine { } } - private boolean configureDhcp(boolean enable, Inet4Address addr, int prefixLen) { + private boolean configureDhcp(boolean enable, final LinkAddress serverAddr, + final LinkAddress clientAddr) { if (enable) { - return startDhcp(addr, prefixLen); + return startDhcp(serverAddr, clientAddr); } else { stopDhcp(); return true; @@ -606,7 +615,7 @@ public class IpServer extends StateMachine { // code that calls into NetworkManagementService directly. srvAddr = (Inet4Address) parseNumericAddress(BLUETOOTH_IFACE_ADDR); mIpv4Address = new LinkAddress(srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); - return configureDhcp(enabled, srvAddr, BLUETOOTH_DHCP_PREFIX_LENGTH); + return configureDhcp(enabled, mIpv4Address, null /* clientAddress */); } mIpv4Address = new LinkAddress(srvAddr, prefixLen); } catch (IllegalArgumentException e) { @@ -643,7 +652,7 @@ public class IpServer extends StateMachine { mLinkProperties.removeRoute(route); } - return configureDhcp(enabled, srvAddr, prefixLen); + return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr); } private String getRandomWifiIPv4Address() { @@ -962,7 +971,14 @@ public class IpServer extends StateMachine { } private void maybeConfigureStaticIp(final TetheringRequestParcel request) { - if (request == null) return; + // Ignore static address configuration if they are invalid or null. In theory, static + // addresses should not be invalid here because TetheringManager do not allow caller to + // specify invalid static address configuration. + if (request == null || request.localIPv4Address == null + || request.staticClientAddress == null || !checkStaticAddressConfiguration( + request.localIPv4Address, request.staticClientAddress)) { + return; + } mStaticIpv4ServerAddr = request.localIPv4Address; mStaticIpv4ClientAddr = request.staticClientAddress; diff --git a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java index e8add9830b5f..f8eb1476bad0 100644 --- a/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java +++ b/packages/Tethering/tests/unit/src/android/net/dhcp/DhcpServingParamsParcelExtTest.java @@ -42,7 +42,9 @@ import java.util.stream.IntStream; @SmallTest public class DhcpServingParamsParcelExtTest { private static final Inet4Address TEST_ADDRESS = inet4Addr("192.168.0.123"); + private static final Inet4Address TEST_CLIENT_ADDRESS = inet4Addr("192.168.0.42"); private static final int TEST_ADDRESS_PARCELED = 0xc0a8007b; + private static final int TEST_CLIENT_ADDRESS_PARCELED = 0xc0a8002a; private static final int TEST_PREFIX_LENGTH = 17; private static final int TEST_LEASE_TIME_SECS = 120; private static final int TEST_MTU = 1000; @@ -105,6 +107,12 @@ public class DhcpServingParamsParcelExtTest { assertFalse(mParcel.metered); } + @Test + public void testSetClientAddr() { + mParcel.setSingleClientAddr(TEST_CLIENT_ADDRESS); + assertEquals(TEST_CLIENT_ADDRESS_PARCELED, mParcel.clientAddr); + } + private static Inet4Address inet4Addr(String addr) { return (Inet4Address) parseNumericAddress(addr); } diff --git a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java index 3a580dd8e5bd..2955903c84f5 100644 --- a/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java +++ b/packages/Tethering/tests/unit/src/com/android/server/connectivity/tethering/TetheringTest.java @@ -38,6 +38,7 @@ import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_FAILED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STARTED; import static android.net.TetheringManager.TETHER_HARDWARE_OFFLOAD_STOPPED; import static android.net.dhcp.IDhcpServer.STATUS_SUCCESS; +import static android.net.shared.Inet4AddressUtils.intToInet4AddressHTH; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_INTERFACE_NAME; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_MODE; import static android.net.wifi.WifiManager.EXTRA_WIFI_AP_STATE; @@ -1668,10 +1669,13 @@ public class TetheringTest { } @Test - public void testRequestStaticServerIp() throws Exception { - final LinkAddress serverLinkAddr = new LinkAddress("192.168.20.1/24"); - final LinkAddress clientLinkAddr = new LinkAddress("192.168.20.42/24"); - final String serverAddr = "192.168.20.1"; + public void testRequestStaticIp() throws Exception { + final LinkAddress serverLinkAddr = new LinkAddress("192.168.0.123/24"); + final LinkAddress clientLinkAddr = new LinkAddress("192.168.0.42/24"); + final String serverAddr = "192.168.0.123"; + final int clientAddrParceled = 0xc0a8002a; + final ArgumentCaptor<DhcpServingParamsParcel> dhcpParamsCaptor = + ArgumentCaptor.forClass(DhcpServingParamsParcel.class); mTethering.startTethering(createTetheringRequestParcel(TETHERING_USB, serverLinkAddr, clientLinkAddr), null); mLooper.dispatchAll(); @@ -1680,8 +1684,12 @@ public class TetheringTest { sendUsbBroadcast(true, true, true, TETHERING_USB); mLooper.dispatchAll(); verify(mNetd).interfaceSetCfg(argThat(cfg -> serverAddr.equals(cfg.ipv4Addr))); - - // TODO: test static client address. + verify(mIpServerDependencies, times(1)).makeDhcpServer(any(), dhcpParamsCaptor.capture(), + any()); + final DhcpServingParamsParcel params = dhcpParamsCaptor.getValue(); + assertEquals(serverAddr, intToInet4AddressHTH(params.serverAddr).getHostAddress()); + assertEquals(24, params.serverAddrPrefixLength); + assertEquals(clientAddrParceled, params.clientAddr); } // TODO: Test that a request for hotspot mode doesn't interfere with an diff --git a/proto/src/typed_features.proto b/proto/src/typed_features.proto new file mode 100644 index 000000000000..c2b3b18ea7c8 --- /dev/null +++ b/proto/src/typed_features.proto @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +syntax = "proto2"; + +package com.android.service; +option java_multiple_files = true; + +// This message is to specify feature params that are a list of strings. +message StringListParamProto { + repeated string element = 1; +}
\ No newline at end of file diff --git a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java index ca230b6936ff..ea4aaa43ea65 100644 --- a/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java +++ b/services/autofill/java/com/android/server/autofill/AutofillInlineSuggestionsRequestSession.java @@ -39,6 +39,7 @@ import com.android.internal.view.InlineSuggestionsRequestInfo; import com.android.server.inputmethod.InputMethodManagerInternal; import java.lang.ref.WeakReference; +import java.util.Collections; import java.util.Optional; import java.util.function.Consumer; @@ -205,12 +206,9 @@ final class AutofillInlineSuggestionsRequestSession { // Although the inline suggestions should disappear when IME hides which removes them // from the view hierarchy, but we still send an empty response to be extra safe. - // TODO(b/149945531): clear the existing suggestions when IME is hide, once the bug is - // fixed. - //if (sDebug) Log.d(TAG, "Send empty inline response"); - //updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections - // .EMPTY_LIST)); - //mPreviousResponseIsNotEmpty = false; + if (sDebug) Log.d(TAG, "Send empty inline response"); + updateResponseToImeUncheckLocked(new InlineSuggestionsResponse(Collections.EMPTY_LIST)); + mPreviousResponseIsNotEmpty = false; } else if (mImeInputViewStarted && mInlineSuggestionsResponse != null && match(mAutofillId, mImeCurrentFieldId)) { // 2. if IME is visible, and response is not null, send the response @@ -224,9 +222,6 @@ final class AutofillInlineSuggestionsRequestSession { + mInlineSuggestionsResponse.getInlineSuggestions().size()); } updateResponseToImeUncheckLocked(mInlineSuggestionsResponse); - // TODO(b/149945531): don't set the response to null so it's cached, once the bug is - // fixed. - mInlineSuggestionsResponse = null; mPreviousResponseIsNotEmpty = !isEmptyResponse; } } diff --git a/services/core/Android.bp b/services/core/Android.bp index a8bc2b4bc6ce..77773edc28ca 100644 --- a/services/core/Android.bp +++ b/services/core/Android.bp @@ -127,7 +127,7 @@ java_library_static { "android.hardware.soundtrigger-V2.3-java", "android.hidl.manager-V1.2-java", "capture_state_listener-aidl-java", - "dnsresolver_aidl_interface-V2-java", + "dnsresolver_aidl_interface-V4-java", "netd_event_listener_interface-java", "overlayable_policy_aidl-java", ], diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java index 8a1de1f0763e..51427c191aa7 100644 --- a/services/core/java/com/android/server/ConnectivityService.java +++ b/services/core/java/com/android/server/ConnectivityService.java @@ -3339,6 +3339,8 @@ public class ConnectivityService extends IConnectivityManager.Stub getNetworkPermission(networkAgent.networkCapabilities)); } mDnsResolver.createNetworkCache(networkAgent.network.netId); + mDnsManager.updateTransportsForNetwork(networkAgent.network.netId, + networkAgent.networkCapabilities.getTransportTypes()); return true; } catch (RemoteException | ServiceSpecificException e) { loge("Error creating network " + networkAgent.network.netId + ": " @@ -6088,7 +6090,13 @@ public class ConnectivityService extends IConnectivityManager.Stub log("Setting DNS servers for network " + netId + " to " + dnses); } try { - mDnsManager.setDnsConfigurationForNetwork(netId, newLp, isDefaultNetwork); + mDnsManager.noteDnsServersForNetwork(netId, newLp); + // TODO: netd should listen on [::1]:53 and proxy queries to the current + // default network, and we should just set net.dns1 to ::1, not least + // because applications attempting to use net.dns resolvers will bypass + // the privacy protections of things like DNS-over-TLS. + if (isDefaultNetwork) mDnsManager.setDefaultDnsSystemProperties(newLp.getDnsServers()); + mDnsManager.flushVmDnsCache(); } catch (Exception e) { loge("Exception in setDnsConfigurationForNetwork: " + e); } @@ -6286,6 +6294,10 @@ public class ConnectivityService extends IConnectivityManager.Stub // bubble those changes through. updateAllVpnsCapabilities(); } + + if (!newNc.equalsTransportTypes(prevNc)) { + mDnsManager.updateTransportsForNetwork(nai.network.netId, newNc.getTransportTypes()); + } } /** diff --git a/services/core/java/com/android/server/am/BugReportHandlerUtil.java b/services/core/java/com/android/server/am/BugReportHandlerUtil.java index ba89fce0b3f8..0a0d8d85f5c3 100644 --- a/services/core/java/com/android/server/am/BugReportHandlerUtil.java +++ b/services/core/java/com/android/server/am/BugReportHandlerUtil.java @@ -16,15 +16,20 @@ package com.android.server.am; +import static android.app.AppOpsManager.OP_NONE; import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM; import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME; +import android.app.Activity; import android.app.BroadcastOptions; +import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.os.Binder; +import android.os.BugreportManager; +import android.os.BugreportParams; import android.os.UserHandle; import android.provider.Settings; import android.text.TextUtils; @@ -43,6 +48,8 @@ public final class BugReportHandlerUtil { private static final String SHELL_APP_PACKAGE = "com.android.shell"; private static final String INTENT_BUGREPORT_REQUESTED = "com.android.internal.intent.action.BUGREPORT_REQUESTED"; + private static final String INTENT_GET_BUGREPORT_HANDLER_RESPONSE = + "com.android.internal.intent.action.GET_BUGREPORT_HANDLER_RESPONSE"; /** * Check is BugReportHandler enabled on the device. @@ -100,6 +107,43 @@ public final class BugReportHandlerUtil { return false; } + if (getBugReportHandlerAppResponseReceivers(context, handlerApp, handlerUser).isEmpty()) { + // Just try to launch bugreport handler app to handle bugreport request + // because the bugreport handler app is old and not support to provide response to + // let BugReportHandlerUtil know it is available or not. + launchBugReportHandlerApp(context, handlerApp, handlerUser); + return true; + } + + Slog.i(TAG, "Getting response from bug report handler app: " + handlerApp); + Intent intent = new Intent(INTENT_GET_BUGREPORT_HANDLER_RESPONSE); + intent.setPackage(handlerApp); + intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND); + intent.addFlags(Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND); + final long identity = Binder.clearCallingIdentity(); + try { + // Handler app's BroadcastReceiver should call setResultCode(Activity.RESULT_OK) to + // let BugreportHandlerResponseBroadcastReceiver know the handler app is available. + context.sendOrderedBroadcastAsUser(intent, + UserHandle.of(handlerUser), + android.Manifest.permission.DUMP, + OP_NONE, /* options= */ null, + new BugreportHandlerResponseBroadcastReceiver(handlerApp, handlerUser), + /* scheduler= */ null, + Activity.RESULT_CANCELED, + /* initialData= */ null, + /* initialExtras= */ null); + } catch (RuntimeException e) { + Slog.e(TAG, "Error while trying to get response from bug report handler app.", e); + return false; + } finally { + Binder.restoreCallingIdentity(identity); + } + return true; + } + + private static void launchBugReportHandlerApp(Context context, String handlerApp, + int handlerUser) { Slog.i(TAG, "Launching bug report handler app: " + handlerApp); Intent intent = new Intent(INTENT_BUGREPORT_REQUESTED); intent.setPackage(handlerApp); @@ -115,11 +159,9 @@ public final class BugReportHandlerUtil { options.toBundle()); } catch (RuntimeException e) { Slog.e(TAG, "Error while trying to launch bugreport handler app.", e); - return false; } finally { Binder.restoreCallingIdentity(identity); } - return true; } private static String getCustomBugReportHandlerApp(Context context) { @@ -159,6 +201,16 @@ public final class BugReportHandlerUtil { handlerUser); } + private static List<ResolveInfo> getBugReportHandlerAppResponseReceivers(Context context, + String handlerApp, int handlerUser) { + // Use the app package and the user id to retrieve the receiver that can provide response + Intent intent = new Intent(INTENT_GET_BUGREPORT_HANDLER_RESPONSE); + intent.setPackage(handlerApp); + return context.getPackageManager() + .queryBroadcastReceiversAsUser(intent, PackageManager.MATCH_SYSTEM_ONLY, + handlerUser); + } + private static String getDefaultBugReportHandlerApp(Context context) { return context.getResources().getString( com.android.internal.R.string.config_defaultBugReportHandlerApp); @@ -176,4 +228,30 @@ public final class BugReportHandlerUtil { Binder.restoreCallingIdentity(identity); } } + + private static class BugreportHandlerResponseBroadcastReceiver extends BroadcastReceiver { + private final String handlerApp; + private final int handlerUser; + + BugreportHandlerResponseBroadcastReceiver(String handlerApp, int handlerUser) { + this.handlerApp = handlerApp; + this.handlerUser = handlerUser; + } + + @Override + public void onReceive(Context context, Intent intent) { + if (getResultCode() == Activity.RESULT_OK) { + // Try to launch bugreport handler app to handle bugreport request because the + // bugreport handler app is available. + launchBugReportHandlerApp(context, handlerApp, handlerUser); + return; + } + + Slog.w(TAG, "Request bug report because no response from handler app."); + BugreportManager bugreportManager = context.getSystemService(BugreportManager.class); + bugreportManager.requestBugreport( + new BugreportParams(BugreportParams.BUGREPORT_MODE_INTERACTIVE), + /* shareTitle= */null, /* shareDescription= */ null); + } + } } diff --git a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java index ea607cb750de..0e3480131952 100644 --- a/services/core/java/com/android/server/am/CarUserSwitchingDialog.java +++ b/services/core/java/com/android/server/am/CarUserSwitchingDialog.java @@ -36,7 +36,6 @@ import android.provider.Settings; import android.view.LayoutInflater; import android.view.View; import android.view.WindowInsets; -import android.view.WindowManager; import android.widget.ImageView; import android.widget.TextView; @@ -59,12 +58,6 @@ final class CarUserSwitchingDialog extends UserSwitchingDialog { String switchingToSystemUserMessage) { super(service, context, oldUser, newUser, aboveSystem, switchingFromSystemUserMessage, switchingToSystemUserMessage); - - // {@link UserSwitchingDialog} uses {@link WindowManager.LayoutParams.TYPE_SYSTEM_ERROR} - // when trying to show dialog above system. That window type has been deprecated and since - // this is a system dialog, hence, it makes sense to put this in System Dialog Window. - // This window also automatically shows status bar. - getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG); } @Override diff --git a/services/core/java/com/android/server/connectivity/DnsManager.java b/services/core/java/com/android/server/connectivity/DnsManager.java index 5250a771d73c..506c8e39194b 100644 --- a/services/core/java/com/android/server/connectivity/DnsManager.java +++ b/services/core/java/com/android/server/connectivity/DnsManager.java @@ -27,6 +27,7 @@ import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; +import android.annotation.NonNull; import android.content.ContentResolver; import android.content.Context; import android.content.Intent; @@ -34,6 +35,7 @@ import android.net.IDnsResolver; import android.net.LinkProperties; import android.net.Network; import android.net.NetworkUtils; +import android.net.ResolverOptionsParcel; import android.net.ResolverParamsParcel; import android.net.Uri; import android.net.shared.PrivateDnsConfig; @@ -237,6 +239,8 @@ public class DnsManager { // TODO: Replace these Maps with SparseArrays. private final Map<Integer, PrivateDnsConfig> mPrivateDnsMap; private final Map<Integer, PrivateDnsValidationStatuses> mPrivateDnsValidationMap; + private final Map<Integer, LinkProperties> mLinkPropertiesMap; + private final Map<Integer, int[]> mTransportsMap; private int mNumDnsEntries; private int mSampleValidity; @@ -253,6 +257,8 @@ public class DnsManager { mSystemProperties = sp; mPrivateDnsMap = new HashMap<>(); mPrivateDnsValidationMap = new HashMap<>(); + mLinkPropertiesMap = new HashMap<>(); + mTransportsMap = new HashMap<>(); // TODO: Create and register ContentObservers to track every setting // used herein, posting messages to respond to changes. @@ -265,6 +271,8 @@ public class DnsManager { public void removeNetwork(Network network) { mPrivateDnsMap.remove(network.netId); mPrivateDnsValidationMap.remove(network.netId); + mTransportsMap.remove(network.netId); + mLinkPropertiesMap.remove(network.netId); } public PrivateDnsConfig updatePrivateDns(Network network, PrivateDnsConfig cfg) { @@ -304,9 +312,35 @@ public class DnsManager { statuses.updateStatus(update); } - public void setDnsConfigurationForNetwork( - int netId, LinkProperties lp, boolean isDefaultNetwork) { + /** + * When creating a new network or transport types are changed in a specific network, + * transport types are always saved to a hashMap before update dns config. + * When destroying network, the specific network will be removed from the hashMap. + * The hashMap is always accessed on the same thread. + */ + public void updateTransportsForNetwork(int netId, @NonNull int[] transportTypes) { + mTransportsMap.put(netId, transportTypes); + sendDnsConfigurationForNetwork(netId); + } + + /** + * When {@link LinkProperties} are changed in a specific network, they are + * always saved to a hashMap before update dns config. + * When destroying network, the specific network will be removed from the hashMap. + * The hashMap is always accessed on the same thread. + */ + public void noteDnsServersForNetwork(int netId, @NonNull LinkProperties lp) { + mLinkPropertiesMap.put(netId, lp); + sendDnsConfigurationForNetwork(netId); + } + /** + * Send dns configuration parameters to resolver for a given network. + */ + public void sendDnsConfigurationForNetwork(int netId) { + final LinkProperties lp = mLinkPropertiesMap.get(netId); + final int[] transportTypes = mTransportsMap.get(netId); + if (lp == null || transportTypes == null) return; updateParametersSettings(); final ResolverParamsParcel paramsParcel = new ResolverParamsParcel(); @@ -319,15 +353,16 @@ public class DnsManager { // networks like IMS. final PrivateDnsConfig privateDnsCfg = mPrivateDnsMap.getOrDefault(netId, PRIVATE_DNS_OFF); - final boolean useTls = privateDnsCfg.useTls; final boolean strictMode = privateDnsCfg.inStrictMode(); + paramsParcel.netId = netId; paramsParcel.sampleValiditySeconds = mSampleValidity; paramsParcel.successThreshold = mSuccessThreshold; paramsParcel.minSamples = mMinSamples; paramsParcel.maxSamples = mMaxSamples; - paramsParcel.servers = NetworkUtils.makeStrings(lp.getDnsServers()); + paramsParcel.servers = + NetworkUtils.makeStrings(lp.getDnsServers()); paramsParcel.domains = getDomainStrings(lp.getDomains()); paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : ""; paramsParcel.tlsServers = @@ -337,6 +372,8 @@ public class DnsManager { .collect(Collectors.toList())) : useTls ? paramsParcel.servers // Opportunistic : new String[0]; // Off + paramsParcel.resolverOptions = new ResolverOptionsParcel(); + paramsParcel.transportTypes = transportTypes; // Prepare to track the validation status of the DNS servers in the // resolver config when private DNS is in opportunistic or strict mode. if (useTls) { @@ -349,7 +386,7 @@ public class DnsManager { mPrivateDnsValidationMap.remove(netId); } - Slog.d(TAG, String.format("setDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + Slog.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, " + "%d, %d, %s, %s)", paramsParcel.netId, Arrays.toString(paramsParcel.servers), Arrays.toString(paramsParcel.domains), paramsParcel.sampleValiditySeconds, paramsParcel.successThreshold, paramsParcel.minSamples, @@ -363,13 +400,6 @@ public class DnsManager { Slog.e(TAG, "Error setting DNS configuration: " + e); return; } - - // TODO: netd should listen on [::1]:53 and proxy queries to the current - // default network, and we should just set net.dns1 to ::1, not least - // because applications attempting to use net.dns resolvers will bypass - // the privacy protections of things like DNS-over-TLS. - if (isDefaultNetwork) setDefaultDnsSystemProperties(lp.getDnsServers()); - flushVmDnsCache(); } public void setDefaultDnsSystemProperties(Collection<InetAddress> dnses) { @@ -384,7 +414,10 @@ public class DnsManager { mNumDnsEntries = last; } - private void flushVmDnsCache() { + /** + * Flush DNS caches and events work before boot has completed. + */ + public void flushVmDnsCache() { /* * Tell the VMs to toss their DNS caches */ diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java index 2aa53cc3882e..a5de90c93aab 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java @@ -169,6 +169,8 @@ final class MediaRoute2ProviderServiceProxy extends MediaRoute2Provider } public void rebindIfDisconnected() { + //TODO: When we are connecting to the service, calling this will unbind and bind again. + // We'd better not unbind if we are connecting. if (mActiveConnection == null && shouldBind()) { unbind(); bind(); diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java index fe118e51cdce..b688e0922d49 100644 --- a/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java +++ b/services/core/java/com/android/server/media/MediaRoute2ProviderWatcher.java @@ -83,7 +83,7 @@ final class MediaRoute2ProviderWatcher { // Scan packages. // Also has the side-effect of restarting providers if needed. - mHandler.post(mScanPackagesRunnable); + postScanPackagesIfNeeded(); } } @@ -92,7 +92,7 @@ final class MediaRoute2ProviderWatcher { mRunning = false; mContext.unregisterReceiver(mScanPackagesReceiver); - mHandler.removeCallbacks(mScanPackagesRunnable); + mHandler.removeCallbacks(this::scanPackages); // Stop all providers. for (int i = mProxies.size() - 1; i >= 0; i--) { @@ -154,20 +154,19 @@ final class MediaRoute2ProviderWatcher { return -1; } + private void postScanPackagesIfNeeded() { + if (!mHandler.hasCallbacks(this::scanPackages)) { + mHandler.post(this::scanPackages); + } + } + private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { if (DEBUG) { Slog.d(TAG, "Received package manager broadcast: " + intent); } - scanPackages(); - } - }; - - private final Runnable mScanPackagesRunnable = new Runnable() { - @Override - public void run() { - scanPackages(); + postScanPackagesIfNeeded(); } }; diff --git a/services/core/java/com/android/server/om/IdmapManager.java b/services/core/java/com/android/server/om/IdmapManager.java index 43fc7ed0e39d..90c85ada9def 100644 --- a/services/core/java/com/android/server/om/IdmapManager.java +++ b/services/core/java/com/android/server/om/IdmapManager.java @@ -63,20 +63,23 @@ class IdmapManager { mIdmapDaemon = IdmapDaemon.getInstance(); } + /** + * Creates the idmap for the target/overlay combination and returns whether the idmap file was + * modified. + */ boolean createIdmap(@NonNull final PackageInfo targetPackage, @NonNull final PackageInfo overlayPackage, int userId) { if (DEBUG) { Slog.d(TAG, "create idmap for " + targetPackage.packageName + " and " + overlayPackage.packageName); } - final int sharedGid = UserHandle.getSharedAppGid(targetPackage.applicationInfo.uid); final String targetPath = targetPackage.applicationInfo.getBaseCodePath(); final String overlayPath = overlayPackage.applicationInfo.getBaseCodePath(); try { int policies = calculateFulfilledPolicies(targetPackage, overlayPackage, userId); boolean enforce = enforceOverlayable(overlayPackage); if (mIdmapDaemon.verifyIdmap(targetPath, overlayPath, policies, enforce, userId)) { - return true; + return false; } return mIdmapDaemon.createIdmap(targetPath, overlayPath, policies, enforce, userId) != null; diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java index d108e76e37df..05a4a38feef1 100644 --- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java +++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java @@ -700,14 +700,15 @@ final class OverlayManagerServiceImpl { final PackageInfo overlayPackage = mPackageManager.getPackageInfo(overlayPackageName, userId); - // Immutable RROs targeting to "android", ie framework-res.apk, are handled by native layers. + // Immutable RROs targeting to "android", ie framework-res.apk, are handled by native + // layers. + boolean modified = false; if (targetPackage != null && overlayPackage != null && !("android".equals(targetPackageName) && !isPackageConfiguredMutable(overlayPackageName))) { - mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); + modified |= mIdmapManager.createIdmap(targetPackage, overlayPackage, userId); } - boolean modified = false; if (overlayPackage != null) { modified |= mSettings.setBaseCodePath(overlayPackageName, userId, overlayPackage.applicationInfo.getBaseCodePath()); diff --git a/services/core/java/com/android/server/om/TEST_MAPPING b/services/core/java/com/android/server/om/TEST_MAPPING index 75229a1adccc..6edd76f1810a 100644 --- a/services/core/java/com/android/server/om/TEST_MAPPING +++ b/services/core/java/com/android/server/om/TEST_MAPPING @@ -15,6 +15,9 @@ "name": "OverlayHostTests" }, { + "name": "OverlayRemountedTest" + }, + { "name": "CtsAppSecurityHostTestCases", "options": [ { diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java index 9c41e6d5c6a3..59ac603875e2 100644 --- a/services/core/java/com/android/server/pm/PackageManagerService.java +++ b/services/core/java/com/android/server/pm/PackageManagerService.java @@ -263,6 +263,7 @@ import android.os.UserHandle; import android.os.UserManager; import android.os.UserManagerInternal; import android.os.incremental.IncrementalManager; +import android.os.incremental.IncrementalStorage; import android.os.storage.DiskInfo; import android.os.storage.IStorageManager; import android.os.storage.StorageEventListener; @@ -16596,6 +16597,7 @@ public class PackageManagerService extends IPackageManager.Stub * locks on {@link #mLock}. */ private void executePostCommitSteps(CommitRequest commitRequest) { + final ArraySet<IncrementalStorage> incrementalStorages = new ArraySet<>(); for (ReconciledPackage reconciledPkg : commitRequest.reconciledPackages.values()) { final boolean instantApp = ((reconciledPkg.scanResult.request.scanFlags & PackageManagerService.SCAN_AS_INSTANT_APP) != 0); @@ -16603,6 +16605,14 @@ public class PackageManagerService extends IPackageManager.Stub final String packageName = pkg.getPackageName(); final boolean onIncremental = mIncrementalManager != null && isIncrementalPath(pkg.getCodePath()); + if (onIncremental) { + IncrementalStorage storage = mIncrementalManager.openStorage(pkg.getCodePath()); + if (storage == null) { + throw new IllegalArgumentException( + "Install: null storage for incremental package " + packageName); + } + incrementalStorages.add(storage); + } prepareAppDataAfterInstallLIF(pkg); if (reconciledPkg.prepareResult.clearCodeCache) { clearAppDataLIF(pkg, UserHandle.USER_ALL, FLAG_STORAGE_DE | FLAG_STORAGE_CE @@ -16700,6 +16710,7 @@ public class PackageManagerService extends IPackageManager.Stub notifyPackageChangeObserversOnUpdate(reconciledPkg); } + NativeLibraryHelper.waitForNativeBinariesExtraction(incrementalStorages); } private void notifyPackageChangeObserversOnUpdate(ReconciledPackage reconciledPkg) { diff --git a/services/core/java/com/android/server/pm/dex/DexManager.java b/services/core/java/com/android/server/pm/dex/DexManager.java index eb7057dd2994..6dcf71e9fbf0 100644 --- a/services/core/java/com/android/server/pm/dex/DexManager.java +++ b/services/core/java/com/android/server/pm/dex/DexManager.java @@ -232,6 +232,10 @@ public class DexManager { private boolean isSystemServerDexPathSupportedForOdex(String dexPath) { ArrayList<PackagePartitions.SystemPartition> partitions = PackagePartitions.getOrderedPartitions(identity()); + // First check the apex partition as it's not part of the SystemPartitions. + if (dexPath.startsWith("/apex/")) { + return true; + } for (int i = 0; i < partitions.size(); i++) { if (partitions.get(i).containsPath(dexPath)) { return true; diff --git a/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java b/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java new file mode 100644 index 000000000000..7cdb84ba0404 --- /dev/null +++ b/services/core/java/com/android/server/stats/pull/SettingsStatsUtil.java @@ -0,0 +1,220 @@ +/* + * 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.stats.pull; + +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE; +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE; + +import android.annotation.NonNull; +import android.annotation.Nullable; +import android.content.ContentResolver; +import android.content.Context; +import android.provider.DeviceConfig; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Base64; +import android.util.Slog; +import android.util.StatsEvent; + +import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.util.FrameworkStatsLog; +import com.android.service.nano.StringListParamProto; + +import java.util.ArrayList; +import java.util.List; + +/** + * Utility methods for creating {@link StatsEvent} data. + */ +final class SettingsStatsUtil { + private static final String TAG = "SettingsStatsUtil"; + private static final FlagsData[] GLOBAL_SETTINGS = new FlagsData[]{ + new FlagsData("GlobalFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("GlobalFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("GlobalFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("GlobalFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + private static final FlagsData[] SECURE_SETTINGS = new FlagsData[]{ + new FlagsData("SecureFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("SecureFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("SecureFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("SecureFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + private static final FlagsData[] SYSTEM_SETTINGS = new FlagsData[]{ + new FlagsData("SystemFeature__boolean_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE), + new FlagsData("SystemFeature__integer_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE), + new FlagsData("SystemFeature__float_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE), + new FlagsData("SystemFeature__string_whitelist", + SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE) + }; + + @VisibleForTesting + @NonNull + static List<StatsEvent> logGlobalSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : GLOBAL_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.Global.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @NonNull + static List<StatsEvent> logSystemSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : SYSTEM_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.System.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @NonNull + static List<StatsEvent> logSecureSettings(Context context, int atomTag, int userId) { + final List<StatsEvent> output = new ArrayList<>(); + final ContentResolver resolver = context.getContentResolver(); + + for (FlagsData flagsData : SECURE_SETTINGS) { + StringListParamProto proto = getList(flagsData.mFlagName); + if (proto == null) { + continue; + } + for (String key : proto.element) { + final String value = Settings.Secure.getStringForUser(resolver, key, userId); + output.add(createStatsEvent(atomTag, key, value, userId, + flagsData.mDataType)); + } + } + return output; + } + + @VisibleForTesting + @Nullable + static StringListParamProto getList(String flag) { + final String base64 = DeviceConfig.getProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, flag); + if (TextUtils.isEmpty(base64)) { + return null; + } + final byte[] decode = Base64.decode(base64, Base64.NO_PADDING | Base64.NO_WRAP); + StringListParamProto list = null; + try { + list = StringListParamProto.parseFrom(decode); + } catch (Exception e) { + Slog.e(TAG, "Error parsing string list proto", e); + } + return list; + } + + /** + * Create {@link StatsEvent} for SETTING_SNAPSHOT atom + */ + @NonNull + private static StatsEvent createStatsEvent(int atomTag, String key, String value, int userId, + int type) { + final StatsEvent.Builder builder = StatsEvent.newBuilder() + .setAtomId(atomTag) + .writeString(key); + boolean booleanValue = false; + int intValue = 0; + float floatValue = 0; + String stringValue = ""; + if (TextUtils.isEmpty(value)) { + builder.writeInt(FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__NOTASSIGNED) + .writeBoolean(booleanValue) + .writeInt(intValue) + .writeFloat(floatValue) + .writeString(stringValue) + .writeInt(userId); + } else { + switch (type) { + case SETTING_SNAPSHOT__TYPE__ASSIGNED_BOOL_TYPE: + booleanValue = "1".equals(value); + break; + case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_INT_TYPE: + try { + intValue = Integer.parseInt(value); + } catch (NumberFormatException e) { + Slog.w(TAG, "Can not parse value to float: " + value); + } + break; + case SETTING_SNAPSHOT__TYPE__ASSIGNED_FLOAT_TYPE: + try { + floatValue = Float.parseFloat(value); + } catch (NumberFormatException e) { + Slog.w(TAG, "Can not parse value to float: " + value); + } + break; + case FrameworkStatsLog.SETTING_SNAPSHOT__TYPE__ASSIGNED_STRING_TYPE: + stringValue = value; + break; + default: + Slog.w(TAG, "Unexpected value type " + type); + } + builder.writeInt(type) + .writeBoolean(booleanValue) + .writeInt(intValue) + .writeFloat(floatValue) + .writeString(stringValue) + .writeInt(userId); + } + return builder.build(); + } + + /** Class for defining flag name and its data type. */ + static final class FlagsData { + /** {@link DeviceConfig} flag name, value of the flag is {@link StringListParamProto} */ + String mFlagName; + /** Data type of the value getting from {@link Settings} keys. */ + int mDataType; + + FlagsData(String flagName, int dataType) { + mFlagName = flagName; + mDataType = dataType; + } + } +} 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 e9da2c4c8472..288c22a94b45 100644 --- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java +++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java @@ -416,6 +416,8 @@ public class StatsPullAtomService extends SystemService { return pullHealthHal(atomTag, data); case FrameworkStatsLog.ATTRIBUTED_APP_OPS: return pullAttributedAppOps(atomTag, data); + case FrameworkStatsLog.SETTING_SNAPSHOT: + return pullSettingsStats(atomTag, data); default: throw new UnsupportedOperationException("Unknown tagId=" + atomTag); } @@ -580,6 +582,7 @@ public class StatsPullAtomService extends SystemService { registerFullBatteryCapacity(); registerBatteryVoltage(); registerBatteryCycleCount(); + registerSettingsStats(); } /** @@ -3244,6 +3247,43 @@ public class StatsPullAtomService extends SystemService { return StatsManager.PULL_SUCCESS; } + private void registerSettingsStats() { + int tagId = FrameworkStatsLog.SETTING_SNAPSHOT; + mStatsManager.setPullAtomCallback( + tagId, + null, // use default PullAtomMetadata values + BackgroundThread.getExecutor(), + mStatsCallbackImpl + ); + } + + int pullSettingsStats(int atomTag, List<StatsEvent> pulledData) { + UserManager userManager = mContext.getSystemService(UserManager.class); + if (userManager == null) { + return StatsManager.PULL_SKIP; + } + + final long token = Binder.clearCallingIdentity(); + try { + for (UserInfo user : userManager.getUsers()) { + final int userId = user.getUserHandle().getIdentifier(); + + if (userId == UserHandle.USER_SYSTEM) { + pulledData.addAll(SettingsStatsUtil.logGlobalSettings(mContext, atomTag, + UserHandle.USER_SYSTEM)); + } + pulledData.addAll(SettingsStatsUtil.logSystemSettings(mContext, atomTag, userId)); + pulledData.addAll(SettingsStatsUtil.logSecureSettings(mContext, atomTag, userId)); + } + } catch (Exception e) { + Slog.e(TAG, "failed to pullSettingsStats", e); + return StatsManager.PULL_SKIP; + } finally { + Binder.restoreCallingIdentity(token); + } + return StatsManager.PULL_SUCCESS; + } + // Thermal event received from vendor thermal management subsystem private static final class ThermalEventListener extends IThermalEventListener.Stub { @Override diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java index 78d2afc64f96..bcad7586b918 100644 --- a/services/core/java/com/android/server/wm/ActivityStack.java +++ b/services/core/java/com/android/server/wm/ActivityStack.java @@ -757,7 +757,7 @@ class ActivityStack extends Task { // warning toast about it. mAtmService.getTaskChangeNotificationController() .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed(); + taskDisplayArea.onSplitScreenModeDismissed(this); } } @@ -2272,7 +2272,7 @@ class ActivityStack extends Task { ActivityOptions.abort(options); if (DEBUG_STATES) Slog.d(TAG_STATES, "resumeNextFocusableActivityWhenStackIsEmpty: " + reason + ", go home"); - return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayId()); + return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea()); } void startActivityLocked(ActivityRecord r, ActivityRecord focusedTopActivity, @@ -3407,18 +3407,6 @@ class ActivityStack extends Task { outBounds.set(mBoundsAnimationSourceHintBounds); } - /** - * @return the final animation bounds if the task stack is currently being animated, or the - * current stack bounds otherwise. - */ - void getAnimationOrCurrentBounds(Rect outBounds) { - if ((mBoundsAnimatingRequested || mBoundsAnimating) && !mBoundsAnimationTarget.isEmpty()) { - getFinalAnimationBounds(outBounds); - return; - } - getBounds(outBounds); - } - /** Bounds of the stack with other system factors taken into consideration. */ void getDimBounds(Rect out) { getBounds(out); diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java index 0470ffa6cdca..f924bd4ea194 100644 --- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java +++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java @@ -44,7 +44,6 @@ import static android.os.Process.INVALID_UID; import static android.os.Process.SYSTEM_UID; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.view.Display.DEFAULT_DISPLAY; -import static android.view.Display.INVALID_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; import static android.view.WindowManager.TRANSIT_DOCK_TASK_FROM_RECENTS; @@ -1378,8 +1377,8 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { if (DEBUG_STACK) Slog.d(TAG_STACK, "findTaskToMoveToFront: moved to front of stack=" + currentStack); - handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, DEFAULT_DISPLAY, - currentStack, forceNonResizeable); + handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, + mRootWindowContainer.getDefaultTaskDisplayArea(), currentStack, forceNonResizeable); } private void moveHomeStackToFrontIfNeeded(int flags, TaskDisplayArea taskDisplayArea, @@ -2134,16 +2133,29 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { WindowManagerService.WINDOW_FREEZE_TIMEOUT_DURATION); } + // TODO(b/152116619): Remove after complete switch to TaskDisplayArea void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, int preferredDisplayId, ActivityStack actualStack) { - handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayId, + final DisplayContent preferredDisplayContent = mRootWindowContainer + .getDisplayContent(preferredDisplayId); + final TaskDisplayArea preferredDisplayArea = preferredDisplayContent != null + ? preferredDisplayContent.getDefaultTaskDisplayArea() + : null; + handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredDisplayArea, + actualStack); + } + + void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, + TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack) { + handleNonResizableTaskIfNeeded(task, preferredWindowingMode, preferredTaskDisplayArea, actualStack, false /* forceNonResizable */); } void handleNonResizableTaskIfNeeded(Task task, int preferredWindowingMode, - int preferredDisplayId, ActivityStack actualStack, boolean forceNonResizable) { - final boolean isSecondaryDisplayPreferred = - (preferredDisplayId != DEFAULT_DISPLAY && preferredDisplayId != INVALID_DISPLAY); + TaskDisplayArea preferredTaskDisplayArea, ActivityStack actualStack, + boolean forceNonResizable) { + final boolean isSecondaryDisplayPreferred = preferredTaskDisplayArea != null + && preferredTaskDisplayArea.getDisplayId() != DEFAULT_DISPLAY; final boolean inSplitScreenMode = actualStack != null && actualStack.getDisplayArea().isSplitScreenModeActivated(); if (((!inSplitScreenMode && preferredWindowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) @@ -2153,33 +2165,31 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // Handle incorrect launch/move to secondary display if needed. if (isSecondaryDisplayPreferred) { - final int actualDisplayId = task.getDisplayId(); - if (!task.canBeLaunchedOnDisplay(actualDisplayId)) { + if (!task.canBeLaunchedOnDisplay(task.getDisplayId())) { throw new IllegalStateException("Task resolved to incompatible display"); } - final DisplayContent preferredDisplay = - mRootWindowContainer.getDisplayContent(preferredDisplayId); + final DisplayContent preferredDisplay = preferredTaskDisplayArea.mDisplayContent; final boolean singleTaskInstance = preferredDisplay != null && preferredDisplay.isSingleTaskInstance(); - if (preferredDisplayId != actualDisplayId) { + if (preferredDisplay != task.getDisplayContent()) { // Suppress the warning toast if the preferredDisplay was set to singleTask. // The singleTaskInstance displays will only contain one task and any attempt to // launch new task will re-route to the default display. if (singleTaskInstance) { mService.getTaskChangeNotificationController() .notifyActivityLaunchOnSecondaryDisplayRerouted(task.getTaskInfo(), - preferredDisplayId); + preferredDisplay.mDisplayId); return; } - Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplayId); + Slog.w(TAG, "Failed to put " + task + " on display " + preferredDisplay.mDisplayId); // Display a warning toast that we failed to put a task on a secondary display. mService.getTaskChangeNotificationController() .notifyActivityLaunchOnSecondaryDisplayFailed(task.getTaskInfo(), - preferredDisplayId); + preferredDisplay.mDisplayId); } else if (!forceNonResizable) { handleForcedResizableTaskIfNeeded(task, FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY); } @@ -2198,7 +2208,7 @@ public class ActivityStackSupervisor implements RecentTasks.Callbacks { // split-screen in split-screen. mService.getTaskChangeNotificationController() .notifyActivityDismissingDockedStack(); - taskDisplayArea.onSplitScreenModeDismissed(); + taskDisplayArea.onSplitScreenModeDismissed(task.getStack()); taskDisplayArea.mDisplayContent.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS, true /* notifyClients */); } diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java index 4e85837e9616..ad54356bced6 100644 --- a/services/core/java/com/android/server/wm/ActivityStartController.java +++ b/services/core/java/com/android/server/wm/ActivityStartController.java @@ -172,7 +172,8 @@ public class ActivityStartController { mLastStarter.postStartActivityProcessing(r, result, targetStack); } - void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, int displayId) { + void startHomeActivity(Intent intent, ActivityInfo aInfo, String reason, + TaskDisplayArea taskDisplayArea) { final ActivityOptions options = ActivityOptions.makeBasic(); options.setLaunchWindowingMode(WINDOWING_MODE_FULLSCREEN); if (!ActivityRecord.isResolverActivity(aInfo.name)) { @@ -181,20 +182,20 @@ public class ActivityStartController { // foreground instead of bring home stack to front. options.setLaunchActivityType(ACTIVITY_TYPE_HOME); } + final int displayId = taskDisplayArea.getDisplayId(); options.setLaunchDisplayId(displayId); + // TODO(b/152116619): Enable after complete switch to WindowContainerToken + //options.setLaunchWindowContainerToken(taskDisplayArea.getWindowContainerToken()); - final DisplayContent display = - mService.mRootWindowContainer.getDisplayContent(displayId); // The home activity will be started later, defer resuming to avoid unneccerary operations // (e.g. start home recursively) when creating home stack. mSupervisor.beginDeferResume(); final ActivityStack homeStack; try { - // TODO(multi-display-area): Support starting home in a task display area - // Make sure home stack exist on display. + // Make sure home stack exists on display area. // TODO(b/153624902): Replace with TaskDisplayArea#getOrCreateRootHomeTask() - homeStack = display.getDefaultTaskDisplayArea().getOrCreateStack( - WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, ON_TOP); + homeStack = taskDisplayArea.getOrCreateStack(WINDOWING_MODE_UNDEFINED, + ACTIVITY_TYPE_HOME, ON_TOP); } finally { mSupervisor.endDeferResume(); } diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 7a6da6739dc1..0bd1aca4030a 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -2422,7 +2422,7 @@ class ActivityStarter { // be destroyed. mTargetStack = intentActivity.getRootTask(); mSupervisor.handleNonResizableTaskIfNeeded(intentTask, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, mTargetStack); + mRootWindowContainer.getDefaultTaskDisplayArea(), mTargetStack); } private void resumeTargetStackIfNeeded() { diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java index 40243e8bbedf..80a1a4592ff3 100644 --- a/services/core/java/com/android/server/wm/DisplayContent.java +++ b/services/core/java/com/android/server/wm/DisplayContent.java @@ -198,6 +198,7 @@ import android.view.ViewRootImpl; import android.view.WindowInsets; import android.view.WindowManager; import android.view.WindowManagerPolicyConstants.PointerEventListener; +import android.window.ITaskOrganizer; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.logging.MetricsLogger; @@ -3421,10 +3422,7 @@ class DisplayContent extends WindowContainer<DisplayContent.DisplayChildWindowCo private void setInputMethodTarget(WindowState target, boolean targetWaitingAnim) { // Always update control target. This is needed to handle rotation. - // We cannot set target as the control target, because mInputMethodTarget can only help - // decide the z-order of IME, but cannot control IME. Only the IME target reported from - // updateInputMethodTargetWindow can control IME. - updateImeControlTarget(mInputMethodControlTarget); + updateImeControlTarget(target); if (target == mInputMethodTarget && mInputMethodTargetWaitingAnim == targetWaitingAnim) { return; } diff --git a/services/core/java/com/android/server/wm/LockTaskController.java b/services/core/java/com/android/server/wm/LockTaskController.java index 337a68e62043..4a0da75cdad8 100644 --- a/services/core/java/com/android/server/wm/LockTaskController.java +++ b/services/core/java/com/android/server/wm/LockTaskController.java @@ -28,7 +28,6 @@ import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_NEVER; import static android.os.UserHandle.USER_ALL; import static android.os.UserHandle.USER_CURRENT; import static android.telecom.TelecomManager.EMERGENCY_DIALER_COMPONENT; -import static android.view.Display.DEFAULT_DISPLAY; import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_LOCKTASK; import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_LOCKTASK; @@ -619,7 +618,8 @@ public class LockTaskController { } } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) { mSupervisor.handleNonResizableTaskIfNeeded(task, WINDOWING_MODE_UNDEFINED, - DEFAULT_DISPLAY, task.getStack(), true /* forceNonResizable */); + mSupervisor.mRootWindowContainer.getDefaultTaskDisplayArea(), + task.getStack(), true /* forceNonResizable */); } } diff --git a/services/core/java/com/android/server/wm/PinnedStackController.java b/services/core/java/com/android/server/wm/PinnedStackController.java index 02a27410dc38..56312aa1b0b8 100644 --- a/services/core/java/com/android/server/wm/PinnedStackController.java +++ b/services/core/java/com/android/server/wm/PinnedStackController.java @@ -23,7 +23,6 @@ import android.app.RemoteAction; import android.content.ComponentName; import android.content.pm.ParceledListSlice; import android.content.res.Resources; -import android.graphics.Rect; import android.os.Handler; import android.os.IBinder; import android.os.RemoteException; @@ -285,13 +284,7 @@ class PinnedStackController { return; } try { - final Rect animatingBounds = new Rect(); - final ActivityStack pinnedStack = mDisplayContent.getDefaultTaskDisplayArea() - .getRootPinnedTask(); - if (pinnedStack != null) { - pinnedStack.getAnimationOrCurrentBounds(animatingBounds); - } - mPinnedStackListener.onMovementBoundsChanged(animatingBounds, fromImeAdjustment); + mPinnedStackListener.onMovementBoundsChanged(fromImeAdjustment); } catch (RemoteException e) { Slog.e(TAG_WM, "Error delivering actions changed event.", e); } diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 1f6170a51b91..1a70de71df4f 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -665,7 +665,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void setSecureSurfaceState(int userId, boolean disabled) { forAllWindows((w) -> { - if (w.mHasSurface && userId == UserHandle.getUserId(w.mOwnerUid)) { + if (w.mHasSurface && userId == w.mShowUserId) { w.mWinAnimator.setSecureLocked(disabled); } }, true /* traverseTopToBottom */); @@ -1461,8 +1461,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent> void startHomeOnEmptyDisplays(String reason) { for (int i = getChildCount() - 1; i >= 0; i--) { final DisplayContent display = getChildAt(i); - if (display.topRunningActivity() == null) { - startHomeOnDisplay(mCurrentUser, reason, display.mDisplayId); + for (int tdaNdx = display.getTaskDisplayAreaCount() - 1; tdaNdx >= 0; --tdaNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tdaNdx); + if (taskDisplayArea.topRunningActivity() == null) { + startHomeOnTaskDisplayArea(mCurrentUser, reason, taskDisplayArea, + false /* allowInstrumenting */, false /* fromHomeKey */); + } } } } @@ -1472,32 +1476,52 @@ class RootWindowContainer extends WindowContainer<DisplayContent> false /* fromHomeKey */); } + boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, + boolean fromHomeKey) { + // Fallback to top focused display or default display if the displayId is invalid. + if (displayId == INVALID_DISPLAY) { + final ActivityStack stack = getTopDisplayFocusedStack(); + displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; + } + + final DisplayContent display = getDisplayContent(displayId); + boolean result = false; + for (int tcNdx = display.getTaskDisplayAreaCount() - 1; tcNdx >= 0; --tcNdx) { + final TaskDisplayArea taskDisplayArea = display.getTaskDisplayAreaAt(tcNdx); + result |= startHomeOnTaskDisplayArea(userId, reason, taskDisplayArea, + allowInstrumenting, fromHomeKey); + } + return result; + } + /** - * This starts home activity on displays that can have system decorations based on displayId - - * Default display always use primary home component. - * For Secondary displays, the home activity must have category SECONDARY_HOME and then resolves - * according to the priorities listed below. + * This starts home activity on display areas that can have system decorations based on + * displayId - default display area always uses primary home component. + * For secondary display areas, the home activity must have category SECONDARY_HOME and then + * resolves according to the priorities listed below. * - If default home is not set, always use the secondary home defined in the config. * - Use currently selected primary home activity. * - Use the activity in the same package as currently selected primary home activity. * If there are multiple activities matched, use first one. * - Use the secondary home defined in the config. */ - boolean startHomeOnDisplay(int userId, String reason, int displayId, boolean allowInstrumenting, - boolean fromHomeKey) { - // Fallback to top focused display if the displayId is invalid. - if (displayId == INVALID_DISPLAY) { + boolean startHomeOnTaskDisplayArea(int userId, String reason, TaskDisplayArea taskDisplayArea, + boolean allowInstrumenting, boolean fromHomeKey) { + // Fallback to top focused display area if the provided one is invalid. + if (taskDisplayArea == null) { final ActivityStack stack = getTopDisplayFocusedStack(); - displayId = stack != null ? stack.getDisplayId() : DEFAULT_DISPLAY; + taskDisplayArea = stack != null ? stack.getDisplayArea() + : getDefaultTaskDisplayArea(); } Intent homeIntent = null; ActivityInfo aInfo = null; - if (displayId == DEFAULT_DISPLAY) { + if (taskDisplayArea == getDefaultTaskDisplayArea()) { homeIntent = mService.getHomeIntent(); aInfo = resolveHomeActivity(userId, homeIntent); - } else if (shouldPlaceSecondaryHomeOnDisplay(displayId)) { - Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, displayId); + } else if (taskDisplayArea.getDisplayId() == DEFAULT_DISPLAY + || shouldPlaceSecondaryHomeOnDisplay(taskDisplayArea.getDisplayId())) { + Pair<ActivityInfo, Intent> info = resolveSecondaryHomeActivity(userId, taskDisplayArea); aInfo = info.first; homeIntent = info.second; } @@ -1505,7 +1529,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return false; } - if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) { + if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(), allowInstrumenting)) { return false; } @@ -1520,9 +1544,9 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Update the reason for ANR debugging to verify if the user activity is the one that // actually launched. final String myReason = reason + ":" + userId + ":" + UserHandle.getUserId( - aInfo.applicationInfo.uid) + ":" + displayId; + aInfo.applicationInfo.uid) + ":" + taskDisplayArea.getDisplayId(); mService.getActivityStartController().startHomeActivity(homeIntent, aInfo, myReason, - displayId); + taskDisplayArea); return true; } @@ -1563,10 +1587,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } @VisibleForTesting - Pair<ActivityInfo, Intent> resolveSecondaryHomeActivity(int userId, int displayId) { - if (displayId == DEFAULT_DISPLAY) { + Pair<ActivityInfo, Intent> resolveSecondaryHomeActivity(int userId, + @NonNull TaskDisplayArea taskDisplayArea) { + if (taskDisplayArea == getDefaultTaskDisplayArea()) { throw new IllegalArgumentException( - "resolveSecondaryHomeActivity: Should not be DEFAULT_DISPLAY"); + "resolveSecondaryHomeActivity: Should not be default task container"); } // Resolve activities in the same package as currently selected primary home activity. Intent homeIntent = mService.getHomeIntent(); @@ -1600,7 +1625,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } if (aInfo != null) { - if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) { + if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(), + false /* allowInstrumenting */)) { aInfo = null; } } @@ -1633,19 +1659,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent> return resolutions; } - boolean resumeHomeActivity(ActivityRecord prev, String reason, int displayId) { + boolean resumeHomeActivity(ActivityRecord prev, String reason, + TaskDisplayArea taskDisplayArea) { if (!mService.isBooting() && !mService.isBooted()) { // Not ready yet! return false; } - if (displayId == INVALID_DISPLAY) { - displayId = DEFAULT_DISPLAY; + if (taskDisplayArea == null) { + taskDisplayArea = getDefaultTaskDisplayArea(); } - // TODO(multi-display-area): Resume home on the right task container - final ActivityRecord r = getDisplayContent(displayId).getDefaultTaskDisplayArea() - .getHomeActivity(); + final ActivityRecord r = taskDisplayArea.getHomeActivity(); final String myReason = reason + " resumeHomeActivity"; // Only resume home activity if isn't finishing. @@ -1653,7 +1678,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> r.moveFocusableActivityToTop(myReason); return resumeFocusedStacksTopActivities(r.getRootTask(), prev, null); } - return startHomeOnDisplay(mCurrentUser, myReason, displayId); + return startHomeOnTaskDisplayArea(mCurrentUser, myReason, taskDisplayArea, + false /* allowInstrumenting */, false /* fromHomeKey */); } /** @@ -2023,7 +2049,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> stack.moveToFront("switchUserOnHomeDisplay"); } else { // Stack was moved to another display while user was swapped out. - resumeHomeActivity(null, "switchUserOnOtherDisplay", DEFAULT_DISPLAY); + resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea()); } return homeInFront; } @@ -2047,43 +2073,58 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } /** - * Move stack with all its existing content to specified display. + * Move stack with all its existing content to specified task display area. * @param stackId Id of stack to move. - * @param displayId Id of display to move stack to. + * @param taskDisplayArea The task display area to move stack to. * @param onTop Indicates whether container should be place on top or on bottom. */ - void moveStackToDisplay(int stackId, int displayId, boolean onTop) { - final DisplayContent displayContent = getDisplayContentOrCreate(displayId); - if (displayContent == null) { - throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" - + displayId); - } + void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) { final ActivityStack stack = getStack(stackId); if (stack == null) { - throw new IllegalArgumentException("moveStackToDisplay: Unknown stackId=" + throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId=" + stackId); } - final DisplayContent currentDisplay = stack.getDisplay(); - if (currentDisplay == null) { - throw new IllegalStateException("moveStackToDisplay: Stack with stack=" + stack - + " is not attached to any display."); + final TaskDisplayArea currentTaskDisplayArea = stack.getDisplayArea(); + if (currentTaskDisplayArea == null) { + throw new IllegalStateException("moveStackToTaskDisplayArea: stack=" + stack + + " is not attached to any task display area."); } - if (currentDisplay.mDisplayId == displayId) { + if (taskDisplayArea == null) { + throw new IllegalArgumentException( + "moveStackToTaskDisplayArea: Unknown taskDisplayArea=" + taskDisplayArea); + } + + if (currentTaskDisplayArea == taskDisplayArea) { throw new IllegalArgumentException("Trying to move stack=" + stack - + " to its current displayId=" + displayId); + + " to its current taskDisplayArea=" + taskDisplayArea); + } + stack.reparent(taskDisplayArea, onTop); + // TODO(multi-display): resize stacks properly if moved from split-screen. + } + + /** + * Move stack with all its existing content to specified display. + * @param stackId Id of stack to move. + * @param displayId Id of display to move stack to. + * @param onTop Indicates whether container should be place on top or on bottom. + */ + void moveStackToDisplay(int stackId, int displayId, boolean onTop) { + final DisplayContent displayContent = getDisplayContentOrCreate(displayId); + if (displayContent == null) { + throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId=" + + displayId); } if (displayContent.isSingleTaskInstance() && displayContent.getStackCount() > 0) { // We don't allow moving stacks to single instance display that already has a child. - Slog.e(TAG, "Can not move stack=" + stack + Slog.e(TAG, "Can not move stackId=" + stackId + " to single task instance display=" + displayContent); return; } - stack.reparent(displayContent.getDefaultTaskDisplayArea(), onTop); - // TODO(multi-display): resize stacks properly if moved from split-screen. + moveStackToTaskDisplayArea(stackId, displayContent.getDefaultTaskDisplayArea(), onTop); } boolean moveTopStackActivityToPinnedStack(int stackId) { @@ -2214,7 +2255,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // It is possible that request to finish activity might also remove its task and // stack, so we need to be careful with indexes in the loop and check child count // every time. - for (int stackNdx = 0; stackNdx < display.getStackCount(); ++stackNdx) { + for (int stackNdx = 0; stackNdx < taskDisplayArea.getStackCount(); ++stackNdx) { final ActivityStack stack = taskDisplayArea.getStackAt(stackNdx); final Task t = stack.finishTopCrashedActivityLocked(app, reason); if (stack == focusedStack || finishedTask == null) { @@ -2281,7 +2322,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent> result |= focusedStack.resumeTopActivityUncheckedLocked(target, targetOptions); } else if (targetStack == null) { result |= resumeHomeActivity(null /* prev */, "no-focusable-task", - display.mDisplayId); + display.getDefaultTaskDisplayArea()); } } } diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java index 7d8a56e6c468..56147f216e73 100644 --- a/services/core/java/com/android/server/wm/Session.java +++ b/services/core/java/com/android/server/wm/Session.java @@ -162,7 +162,19 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, - outInsetsState, outActiveControls); + outInsetsState, outActiveControls, UserHandle.getUserId(mUid)); + } + + + @Override + public int addToDisplayAsUser(IWindow window, int seq, WindowManager.LayoutParams attrs, + int viewVisibility, int displayId, int userId, Rect outFrame, + Rect outContentInsets, Rect outStableInsets, + DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, outFrame, + outContentInsets, outStableInsets, outDisplayCutout, outInputChannel, + outInsetsState, outActiveControls, userId); } @Override @@ -172,7 +184,7 @@ class Session extends IWindowSession.Stub implements IBinder.DeathRecipient { return mService.addWindow(this, window, seq, attrs, viewVisibility, displayId, new Rect() /* outFrame */, outContentInsets, outStableInsets, new DisplayCutout.ParcelableWrapper() /* cutout */, null /* outInputChannel */, - outInsetsState, null); + outInsetsState, null, UserHandle.getUserId(mUid)); } @Override diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index fd32724d82a3..373abfef6470 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -58,7 +58,6 @@ import static android.content.res.Configuration.ORIENTATION_PORTRAIT; import static android.content.res.Configuration.ORIENTATION_UNDEFINED; import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER; import static android.provider.Settings.Secure.USER_SETUP_COMPLETE; -import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static android.view.SurfaceControl.METADATA_TASK_ID; import static android.view.WindowManager.TRANSIT_TASK_CHANGE_WINDOWING_MODE; @@ -900,7 +899,7 @@ class Task extends WindowContainer<WindowContainer> { // TODO: Handle incorrect request to move before the actual move, not after. supervisor.handleNonResizableTaskIfNeeded(this, preferredStack.getWindowingMode(), - DEFAULT_DISPLAY, toStack); + mRootWindowContainer.getDefaultTaskDisplayArea(), toStack); return (preferredStack == toStack); } diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index fee1c8019a07..ea9a3629a40f 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -70,7 +70,9 @@ import java.util.List; * {@link DisplayArea} that represents a section of a screen that contains app window containers. */ final class TaskDisplayArea extends DisplayArea<ActivityStack> { + DisplayContent mDisplayContent; + /** * A control placed at the appropriate level for transitions to occur. */ @@ -1068,7 +1070,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { /** * Find task for putting the Activity in. */ - void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplay, + void findTaskLocked(final ActivityRecord r, final boolean isPreferredDisplayArea, RootWindowContainer.FindTaskResult result) { mTmpFindTaskResult.clear(); for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) { @@ -1090,7 +1092,7 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { if (mTmpFindTaskResult.mIdealMatch) { result.setTo(mTmpFindTaskResult); return; - } else if (isPreferredDisplay) { + } else if (isPreferredDisplayArea) { // Note: since the traversing through the stacks is top down, the floating // tasks should always have lower priority than any affinity-matching tasks // in the fullscreen stacks @@ -1165,17 +1167,23 @@ final class TaskDisplayArea extends DisplayArea<ActivityStack> { } void onSplitScreenModeDismissed() { + onSplitScreenModeDismissed(null /* toTop */); + } + + void onSplitScreenModeDismissed(ActivityStack toTop) { mAtmService.deferWindowLayout(); try { mLaunchRootTask = null; moveSplitScreenTasksToFullScreen(); } finally { - final ActivityStack topFullscreenStack = - getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); + final ActivityStack topFullscreenStack = toTop != null + ? toTop : getTopStackInWindowingMode(WINDOWING_MODE_FULLSCREEN); final ActivityStack homeStack = getOrCreateRootHomeTask(); - if (topFullscreenStack != null && homeStack != null && !isTopStack(homeStack)) { + if (homeStack != null && ((topFullscreenStack != null && !isTopStack(homeStack)) + || toTop != null)) { // Whenever split-screen is dismissed we want the home stack directly behind the // current top fullscreen stack so it shows up when the top stack is finished. + // Or, if the caller specified a stack to be on top after split-screen is dismissed. // TODO: Would be better to use ActivityDisplay.positionChildAt() for this, however // ActivityDisplay doesn't have a direct controller to WM side yet. We can switch // once we have that. diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java index c3fb68f9e0c4..9d879765f8df 100644 --- a/services/core/java/com/android/server/wm/WindowManagerService.java +++ b/services/core/java/com/android/server/wm/WindowManagerService.java @@ -25,6 +25,7 @@ import static android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS; import static android.Manifest.permission.RESTRICTED_VR_ACCESS; import static android.Manifest.permission.WRITE_SECURE_SETTINGS; import static android.app.ActivityManagerInternal.ALLOW_FULL_ONLY; +import static android.app.ActivityManagerInternal.ALLOW_NON_FULL; import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT; import static android.app.AppOpsManager.OP_SYSTEM_ALERT_WINDOW; import static android.app.StatusBarManager.DISABLE_MASK; @@ -1359,7 +1360,8 @@ public class WindowManagerService extends IWindowManager.Stub LayoutParams attrs, int viewVisibility, int displayId, Rect outFrame, Rect outContentInsets, Rect outStableInsets, DisplayCutout.ParcelableWrapper outDisplayCutout, InputChannel outInputChannel, - InsetsState outInsetsState, InsetsSourceControl[] outActiveControls) { + InsetsState outInsetsState, InsetsSourceControl[] outActiveControls, + int requestUserId) { int[] appOp = new int[1]; final boolean isRoundedCornerOverlay = (attrs.privateFlags & PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY) != 0; @@ -1428,6 +1430,20 @@ public class WindowManagerService extends IWindowManager.Stub return WindowManagerGlobal.ADD_INVALID_DISPLAY; } + int userId = UserHandle.getUserId(session.mUid); + if (requestUserId != userId) { + try { + mAmInternal.handleIncomingUser(callingPid, callingUid, requestUserId, + false /*allowAll*/, ALLOW_NON_FULL, null, null); + } catch (Exception exp) { + ProtoLog.w(WM_ERROR, "Trying to add window with invalid user=%d", + requestUserId); + return WindowManagerGlobal.ADD_INVALID_USER; + } + // It's fine to use this userId + userId = requestUserId; + } + ActivityRecord activity = null; final boolean hasParent = parentWindow != null; // Use existing parent window token for child windows since they go in the same token @@ -1516,7 +1532,7 @@ public class WindowManagerService extends IWindowManager.Stub } final WindowState win = new WindowState(this, session, client, token, parentWindow, - appOp[0], seq, attrs, viewVisibility, session.mUid, + appOp[0], seq, attrs, viewVisibility, session.mUid, userId, session.mCanAddInternalSystemWindow); if (win.mDeathRecipient == null) { // Client has apparently died, so there is no reason to @@ -1836,8 +1852,7 @@ public class WindowManagerService extends IWindowManager.Stub if ((w.mAttrs.flags&WindowManager.LayoutParams.FLAG_SECURE) != 0) { return true; } - if (DevicePolicyCache.getInstance().getScreenCaptureDisabled( - UserHandle.getUserId(w.mOwnerUid))) { + if (DevicePolicyCache.getInstance().getScreenCaptureDisabled(w.mShowUserId)) { return true; } return false; @@ -7407,7 +7422,7 @@ public class WindowManagerService extends IWindowManager.Stub synchronized (mGlobalLock) { WindowState window = mWindowMap.get(token); if (window != null) { - return UserHandle.getUserId(window.mOwnerUid); + return window.mShowUserId; } return UserHandle.USER_NULL; } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 3e2e9be24c4f..86bc013e3638 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -156,7 +156,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub final PooledConsumer f = PooledLambda.obtainConsumer( ActivityRecord::ensureActivityConfiguration, PooledLambda.__(ActivityRecord.class), 0, - false /* preserveWindow */); + true /* preserveWindow */); try { for (int i = haveConfigChanges.size() - 1; i >= 0; --i) { haveConfigChanges.valueAt(i).forAllActivities(f); diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java index 627fdc342a9a..c11c29b5deb6 100644 --- a/services/core/java/com/android/server/wm/WindowState.java +++ b/services/core/java/com/android/server/wm/WindowState.java @@ -191,7 +191,6 @@ import android.os.RemoteCallbackList; import android.os.RemoteException; import android.os.SystemClock; import android.os.Trace; -import android.os.UserHandle; import android.os.WorkSource; import android.provider.Settings; import android.text.TextUtils; @@ -269,6 +268,12 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP final int mAppOp; // UserId and appId of the owner. Don't display windows of non-current user. final int mOwnerUid; + /** + * Requested userId, if this is not equals with the userId from mOwnerUid, then this window is + * created for secondary user. + * Use this member instead of get userId from mOwnerUid while query for visibility. + */ + final int mShowUserId; /** The owner has {@link android.Manifest.permission#INTERNAL_SYSTEM_WINDOW} */ final boolean mOwnerCanAddInternalSystemWindow; final WindowId mWindowId; @@ -806,8 +811,9 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow) { - this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow) { + this(service, s, c, token, parentWindow, appOp, seq, a, viewVisibility, ownerId, showUserId, ownerCanAddInternalSystemWindow, new PowerManagerWrapper() { @Override public void wakeUp(long time, @WakeReason int reason, String details) { @@ -823,8 +829,8 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP WindowState(WindowManagerService service, Session s, IWindow c, WindowToken token, WindowState parentWindow, int appOp, int seq, WindowManager.LayoutParams a, - int viewVisibility, int ownerId, boolean ownerCanAddInternalSystemWindow, - PowerManagerWrapper powerManagerWrapper) { + int viewVisibility, int ownerId, int showUserId, + boolean ownerCanAddInternalSystemWindow, PowerManagerWrapper powerManagerWrapper) { super(service); mSession = s; mClient = c; @@ -832,6 +838,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mToken = token; mActivityRecord = mToken.asActivityRecord(); mOwnerUid = ownerId; + mShowUserId = showUserId; mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow; mWindowId = new WindowId(this); mAttrs.copyFrom(a); @@ -3275,7 +3282,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP } return win.showForAllUsers() - || mWmService.isCurrentProfile(UserHandle.getUserId(win.mOwnerUid)); + || mWmService.isCurrentProfile(win.mShowUserId); } private static void applyInsets(Region outRegion, Rect frame, Rect inset) { @@ -3795,7 +3802,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP public void writeIdentifierToProto(ProtoOutputStream proto, long fieldId) { final long token = proto.start(fieldId); proto.write(HASH_CODE, System.identityHashCode(this)); - proto.write(USER_ID, UserHandle.getUserId(mOwnerUid)); + proto.write(USER_ID, mShowUserId); final CharSequence title = getWindowTag(); if (title != null) { proto.write(TITLE, title.toString()); @@ -3979,7 +3986,7 @@ class WindowState extends WindowContainer<WindowState> implements WindowManagerP mLastTitle = title; mWasExiting = mAnimatingExit; mStringNameCache = "Window{" + Integer.toHexString(System.identityHashCode(this)) - + " u" + UserHandle.getUserId(mOwnerUid) + + " u" + mShowUserId + " " + mLastTitle + (mAnimatingExit ? " EXITING}" : "}"); } return mStringNameCache; diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java index 5976b48db764..e34b81654c72 100644 --- a/services/core/java/com/android/server/wm/WindowToken.java +++ b/services/core/java/com/android/server/wm/WindowToken.java @@ -554,13 +554,12 @@ class WindowToken extends WindowContainer<WindowState> { // cleared and the configuration is restored from parent. if (!changed) { clearFixedRotationTransform(null /* applyDisplayRotation */); - onConfigurationChanged(getParent().getConfiguration()); } } /** - * Clears the transform and apply display rotation if the action is given. The caller needs to - * refresh the configuration of this container after this method call. + * Clears the transform and apply display rotation if the action is given. If the display will + * not rotate, the transformed containers are restored to their original states. */ void clearFixedRotationTransform(Runnable applyDisplayRotation) { final FixedRotationTransformState state = mFixedRotationTransformState; @@ -574,6 +573,12 @@ class WindowToken extends WindowContainer<WindowState> { state.mIsTransforming = false; if (applyDisplayRotation != null) { applyDisplayRotation.run(); + } else { + // The display will not rotate to the rotation of this container, let's cancel them. + for (int i = state.mAssociatedTokens.size() - 1; i >= 0; i--) { + state.mAssociatedTokens.get(i).cancelFixedRotationTransform(); + } + cancelFixedRotationTransform(); } // The state is cleared at the end, because it is used to indicate that other windows can // use seamless rotation when applying rotation to display. @@ -583,6 +588,16 @@ class WindowToken extends WindowContainer<WindowState> { mFixedRotationTransformState = null; } + /** Restores the changes that applies to this container. */ + private void cancelFixedRotationTransform() { + final WindowContainer<?> parent = getParent(); + if (parent == null) { + // The window may be detached or detaching. + return; + } + onConfigurationChanged(parent.getConfiguration()); + } + @Override void resolveOverrideConfiguration(Configuration newParentConfig) { super.resolveOverrideConfiguration(newParentConfig); diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp index e99a264c42e4..76b171337bb9 100644 --- a/services/core/jni/com_android_server_SystemServer.cpp +++ b/services/core/jni/com_android_server_SystemServer.cpp @@ -135,7 +135,7 @@ static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject) static jlong android_server_SystemServer_startIncrementalService(JNIEnv* env, jclass klass, jobject self) { - return Incremental_IncrementalService_Start(); + return Incremental_IncrementalService_Start(env); } static void android_server_SystemServer_setIncrementalServiceSystemReady(JNIEnv* env, jclass klass, diff --git a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp index 853eba71d88a..e32a343433a8 100644 --- a/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp +++ b/services/core/jni/com_android_server_pm_PackageManagerShellCommandDataLoader.cpp @@ -410,6 +410,8 @@ private: // Installation. bool onPrepareImage(dataloader::DataLoaderInstallationFiles addedFiles) final { + ALOGE("onPrepareImage: start."); + JNIEnv* env = GetOrAttachJNIEnvironment(mJvm); const auto& jni = jniIds(env); diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp index 2dbbc5ac6806..fc8c6feac22b 100644 --- a/services/incremental/BinderIncrementalService.cpp +++ b/services/incremental/BinderIncrementalService.cpp @@ -17,6 +17,7 @@ #include "BinderIncrementalService.h" #include <android-base/logging.h> +#include <android-base/no_destructor.h> #include <binder/IResultReceiver.h> #include <binder/PermissionCache.h> #include <incfs.h> @@ -57,10 +58,10 @@ static bool incFsValid(const sp<IVold>& vold) { return true; } -BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm) - : mImpl(RealServiceManager(sm), getIncrementalDir()) {} +BinderIncrementalService::BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env) + : mImpl(RealServiceManager(sm, env), getIncrementalDir()) {} -BinderIncrementalService* BinderIncrementalService::start() { +BinderIncrementalService* BinderIncrementalService::start(JNIEnv* env) { if (!incFsEnabled()) { return nullptr; } @@ -80,7 +81,7 @@ BinderIncrementalService* BinderIncrementalService::start() { return nullptr; } - sp<BinderIncrementalService> self(new BinderIncrementalService(sm)); + sp<BinderIncrementalService> self(new BinderIncrementalService(sm, env)); status_t ret = sm->addService(String16{getServiceName()}, self); if (ret != android::OK) { return nullptr; @@ -93,8 +94,8 @@ BinderIncrementalService* BinderIncrementalService::start() { } status_t BinderIncrementalService::dump(int fd, const Vector<String16>&) { - static const String16 kDump("android.permission.DUMP"); - if (!PermissionCache::checkCallingPermission(kDump)) { + static const android::base::NoDestructor<String16> kDump("android.permission.DUMP"); + if (!PermissionCache::checkCallingPermission(*kDump)) { return PERMISSION_DENIED; } mImpl.onDump(fd); @@ -115,11 +116,14 @@ binder::Status BinderIncrementalService::openStorage(const std::string& path, return ok(); } -binder::Status BinderIncrementalService::createStorage(const std::string& path, - const DataLoaderParamsParcel& params, - const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, - int32_t createMode, int32_t* _aidl_return) { - *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener, android::incremental::IncrementalService::CreateOptions(createMode)); +binder::Status BinderIncrementalService::createStorage( + const std::string& path, const DataLoaderParamsParcel& params, + const ::android::sp<::android::content::pm::IDataLoaderStatusListener>& listener, + int32_t createMode, int32_t* _aidl_return) { + *_aidl_return = + mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params), listener, + android::incremental::IncrementalService::CreateOptions( + createMode)); return ok(); } @@ -180,7 +184,8 @@ static std::tuple<int, incfs::FileId, incfs::NewFileParams> toMakeFileParams( if (!params.signature) { nfp.signature = {}; } else { - nfp.signature = {(const char*)params.signature->data(), (IncFsSize)params.signature->size()}; + nfp.signature = {(const char*)params.signature->data(), + (IncFsSize)params.signature->size()}; } return {0, id, nfp}; } @@ -277,10 +282,16 @@ binder::Status BinderIncrementalService::configureNativeBinaries( return ok(); } +binder::Status BinderIncrementalService::waitForNativeBinariesExtraction(int storageId, + bool* _aidl_return) { + *_aidl_return = mImpl.waitForNativeBinariesExtraction(storageId); + return ok(); +} + } // namespace android::os::incremental -jlong Incremental_IncrementalService_Start() { - return (jlong)android::os::incremental::BinderIncrementalService::start(); +jlong Incremental_IncrementalService_Start(JNIEnv* env) { + return (jlong)android::os::incremental::BinderIncrementalService::start(env); } void Incremental_IncrementalService_OnSystemReady(jlong self) { if (self) { diff --git a/services/incremental/BinderIncrementalService.h b/services/incremental/BinderIncrementalService.h index 28613e101b7c..5a7d5da56f18 100644 --- a/services/incremental/BinderIncrementalService.h +++ b/services/incremental/BinderIncrementalService.h @@ -18,6 +18,7 @@ #include <binder/BinderService.h> #include <binder/IServiceManager.h> +#include <jni.h> #include "IncrementalService.h" #include "android/os/incremental/BnIncrementalService.h" @@ -28,9 +29,9 @@ namespace android::os::incremental { class BinderIncrementalService : public BnIncrementalService, public BinderService<BinderIncrementalService> { public: - BinderIncrementalService(const sp<IServiceManager>& sm); + BinderIncrementalService(const sp<IServiceManager>& sm, JNIEnv* env); - static BinderIncrementalService* start(); + static BinderIncrementalService* start(JNIEnv* env); static const char16_t* getServiceName() { return u"incremental"; } status_t dump(int fd, const Vector<String16>& args) final; @@ -38,7 +39,10 @@ public: void onInvalidStorage(int mountId); 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; + 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; 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, @@ -68,9 +72,11 @@ public: std::vector<uint8_t>* _aidl_return) final; binder::Status startLoading(int32_t storageId, bool* _aidl_return) final; binder::Status deleteStorage(int32_t storageId) final; + binder::Status configureNativeBinaries(int32_t storageId, const std::string& apkFullPath, const std::string& libDirRelativePath, const std::string& abi, bool* _aidl_return) final; + binder::Status waitForNativeBinariesExtraction(int storageId, bool* _aidl_return) final; private: android::incremental::IncrementalService mImpl; diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp index 92366e51eb47..2c6bf0a80fe0 100644 --- a/services/incremental/IncrementalService.cpp +++ b/services/incremental/IncrementalService.cpp @@ -20,28 +20,24 @@ #include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/no_destructor.h> #include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android-base/strings.h> #include <android/content/pm/IDataLoaderStatusListener.h> #include <android/os/IVold.h> -#include <androidfw/ZipFileRO.h> -#include <androidfw/ZipUtils.h> #include <binder/BinderService.h> #include <binder/Nullable.h> #include <binder/ParcelFileDescriptor.h> #include <binder/Status.h> #include <sys/stat.h> #include <uuid/uuid.h> -#include <zlib.h> #include <charconv> #include <ctime> #include <filesystem> #include <iterator> #include <span> -#include <stack> -#include <thread> #include <type_traits> #include "Metadata.pb.h" @@ -163,7 +159,9 @@ const bool IncrementalService::sEnablePerfLogging = android::base::GetBoolProperty("incremental.perflogging", false); IncrementalService::IncFsMount::~IncFsMount() { - incrementalService.mDataLoaderManager->destroyDataLoader(mountId); + if (dataLoaderStub) { + dataLoaderStub->destroy(); + } LOG(INFO) << "Unmounting and cleaning up mount " << mountId << " with root '" << root << '\''; for (auto&& [target, _] : bindPoints) { LOG(INFO) << "\tbind: " << target; @@ -239,6 +237,7 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v mDataLoaderManager(sm.getDataLoaderManager()), mIncFs(sm.getIncFs()), mAppOpsManager(sm.getAppOpsManager()), + mJni(sm.getJni()), mIncrementalDir(rootDir) { if (!mVold) { LOG(FATAL) << "Vold service is unavailable"; @@ -249,6 +248,13 @@ IncrementalService::IncrementalService(ServiceManagerWrapper&& sm, std::string_v if (!mAppOpsManager) { LOG(FATAL) << "AppOpsManager is unavailable"; } + + mJobQueue.reserve(16); + mJobProcessor = std::thread([this]() { + mJni->initializeForCurrentThread(); + runJobProcessing(); + }); + mountExistingImages(); } @@ -256,7 +262,14 @@ FileId IncrementalService::idFromMetadata(std::span<const uint8_t> metadata) { return IncFs_FileIdFromMetadata({(const char*)metadata.data(), metadata.size()}); } -IncrementalService::~IncrementalService() = default; +IncrementalService::~IncrementalService() { + { + std::lock_guard lock(mJobMutex); + mRunning = false; + } + mJobCondition.notify_all(); + mJobProcessor.join(); +} inline const char* toString(TimePoint t) { using SystemClock = std::chrono::system_clock; @@ -288,9 +301,12 @@ void IncrementalService::onDump(int fd) { dprintf(fd, "\t\tmountId: %d\n", mnt.mountId); dprintf(fd, "\t\troot: %s\n", mnt.root.c_str()); dprintf(fd, "\t\tnextStorageDirNo: %d\n", mnt.nextStorageDirNo.load()); - dprintf(fd, "\t\tdataLoaderStatus: %d\n", mnt.dataLoaderStatus.load()); - { - const auto& params = mnt.dataLoaderParams; + if (mnt.dataLoaderStub) { + const auto& dataLoaderStub = *mnt.dataLoaderStub; + dprintf(fd, "\t\tdataLoaderStatus: %d\n", dataLoaderStub.status()); + dprintf(fd, "\t\tdataLoaderStartRequested: %s\n", + dataLoaderStub.startRequested() ? "true" : "false"); + const auto& params = dataLoaderStub.params(); dprintf(fd, "\t\tdataLoaderParams:\n"); dprintf(fd, "\t\t\ttype: %s\n", toString(params.type).c_str()); dprintf(fd, "\t\t\tpackageName: %s\n", params.packageName.c_str()); @@ -321,10 +337,9 @@ void IncrementalService::onDump(int fd) { } } -std::optional<std::future<void>> IncrementalService::onSystemReady() { - std::promise<void> threadFinished; +void IncrementalService::onSystemReady() { if (mSystemReady.exchange(true)) { - return {}; + return; } std::vector<IfsMountPtr> mounts; @@ -338,8 +353,8 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { } } + /* TODO(b/151241369): restore data loaders on reboot. std::thread([this, mounts = std::move(mounts)]() { - /* TODO(b/151241369): restore data loaders on reboot. for (auto&& ifs : mounts) { if (prepareDataLoader(*ifs)) { LOG(INFO) << "Successfully started data loader for mount " << ifs->mountId; @@ -348,10 +363,8 @@ std::optional<std::future<void>> IncrementalService::onSystemReady() { LOG(WARNING) << "Failed to start data loader for mount " << ifs->mountId; } } - */ - mPrepareDataLoaders.set_value_at_thread_exit(); }).detach(); - return mPrepareDataLoaders.get_future(); + */ } auto IncrementalService::getStorageSlotLocked() -> MountMap::iterator { @@ -468,15 +481,13 @@ StorageId IncrementalService::createStorage( return kInvalidStorageId; } - ifs->dataLoaderParams = std::move(dataLoaderParams); - { metadata::Mount m; m.mutable_storage()->set_id(ifs->mountId); - m.mutable_loader()->set_type((int)ifs->dataLoaderParams.type); - m.mutable_loader()->set_package_name(ifs->dataLoaderParams.packageName); - m.mutable_loader()->set_class_name(ifs->dataLoaderParams.className); - m.mutable_loader()->set_arguments(ifs->dataLoaderParams.arguments); + m.mutable_loader()->set_type((int)dataLoaderParams.type); + m.mutable_loader()->set_package_name(dataLoaderParams.packageName); + m.mutable_loader()->set_class_name(dataLoaderParams.className); + m.mutable_loader()->set_arguments(dataLoaderParams.arguments); const auto metadata = m.SerializeAsString(); m.mutable_loader()->release_arguments(); m.mutable_loader()->release_class_name(); @@ -504,14 +515,20 @@ StorageId IncrementalService::createStorage( // Done here as well, all data structures are in good state. secondCleanupOnFailure.release(); - if (!prepareDataLoader(*ifs, &dataLoaderStatusListener)) { - LOG(ERROR) << "prepareDataLoader() failed"; - deleteStorageLocked(*ifs, std::move(l)); - return kInvalidStorageId; - } + auto dataLoaderStub = + prepareDataLoader(*ifs, std::move(dataLoaderParams), &dataLoaderStatusListener); + CHECK(dataLoaderStub); mountIt->second = std::move(ifs); l.unlock(); + + if (mSystemReady.load(std::memory_order_relaxed) && !dataLoaderStub->create()) { + // failed to create data loader + LOG(ERROR) << "initializeDataLoader() failed"; + deleteStorage(dataLoaderStub->id()); + return kInvalidStorageId; + } + LOG(INFO) << "created storage " << mountId; return mountId; } @@ -585,10 +602,10 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog return -EINVAL; } + const auto& params = ifs->dataLoaderStub->params(); if (enableReadLogs) { - if (auto status = - mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, - ifs->dataLoaderParams.packageName.c_str()); + if (auto status = mAppOpsManager->checkPermission(kDataUsageStats, kOpUsage, + params.packageName.c_str()); !status.isOk()) { LOG(ERROR) << "checkPermission failed: " << status.toString8(); return fromBinderStatus(status); @@ -601,7 +618,7 @@ int IncrementalService::setStorageParams(StorageId storageId, bool enableReadLog } if (enableReadLogs) { - registerAppOpsCallback(ifs->dataLoaderParams.packageName); + registerAppOpsCallback(params.packageName); } return 0; @@ -701,8 +718,8 @@ IncrementalService::IfsMountPtr IncrementalService::getIfs(StorageId storage) co const IncrementalService::IfsMountPtr& IncrementalService::getIfsLocked(StorageId storage) const { auto it = mMounts.find(storage); if (it == mMounts.end()) { - static const IfsMountPtr kEmpty = {}; - return kEmpty; + static const android::base::NoDestructor<IfsMountPtr> kEmpty{}; + return *kEmpty; } return it->second; } @@ -984,34 +1001,19 @@ std::vector<std::string> IncrementalService::listFiles(StorageId storage) const } bool IncrementalService::startLoading(StorageId storage) const { + DataLoaderStubPtr dataLoaderStub; { std::unique_lock l(mLock); const auto& ifs = getIfsLocked(storage); if (!ifs) { return false; } - if (ifs->dataLoaderStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { - ifs->dataLoaderStartRequested = true; - return true; + dataLoaderStub = ifs->dataLoaderStub; + if (!dataLoaderStub) { + return false; } } - return startDataLoader(storage); -} - -bool IncrementalService::startDataLoader(MountId mountId) const { - sp<IDataLoader> dataloader; - auto status = mDataLoaderManager->getDataLoader(mountId, &dataloader); - if (!status.isOk()) { - return false; - } - if (!dataloader) { - return false; - } - status = dataloader->start(mountId); - if (!status.isOk()) { - return false; - } - return true; + return dataLoaderStub->start(); } void IncrementalService::mountExistingImages() { @@ -1057,13 +1059,13 @@ bool IncrementalService::mountExistingImage(std::string_view root) { mNextId = std::max(mNextId, ifs->mountId + 1); // DataLoader params + DataLoaderParamsParcel dataLoaderParams; { - auto& dlp = ifs->dataLoaderParams; const auto& loader = mount.loader(); - dlp.type = (android::content::pm::DataLoaderType)loader.type(); - dlp.packageName = loader.package_name(); - dlp.className = loader.class_name(); - dlp.arguments = loader.arguments(); + dataLoaderParams.type = (android::content::pm::DataLoaderType)loader.type(); + dataLoaderParams.packageName = loader.package_name(); + dataLoaderParams.className = loader.class_name(); + dataLoaderParams.arguments = loader.arguments(); } std::vector<std::pair<std::string, metadata::BindPoint>> bindPoints; @@ -1135,17 +1137,13 @@ bool IncrementalService::mountExistingImage(std::string_view root) { return true; } -bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, - const DataLoaderStatusListener* externalListener) { - if (!mSystemReady.load(std::memory_order_relaxed)) { - std::unique_lock l(ifs.lock); - return true; // eventually... - } - +IncrementalService::DataLoaderStubPtr IncrementalService::prepareDataLoader( + IncrementalService::IncFsMount& ifs, DataLoaderParamsParcel&& params, + const DataLoaderStatusListener* externalListener) { std::unique_lock l(ifs.lock); - if (ifs.dataLoaderStatus != -1) { + if (ifs.dataLoaderStub) { LOG(INFO) << "Skipped data loader preparation because it already exists"; - return true; + return ifs.dataLoaderStub; } FileSystemControlParcel fsControlParcel; @@ -1155,17 +1153,10 @@ bool IncrementalService::prepareDataLoader(IncrementalService::IncFsMount& ifs, base::unique_fd(::dup(ifs.control.pendingReads()))); fsControlParcel.incremental->log.reset(base::unique_fd(::dup(ifs.control.logs()))); fsControlParcel.service = new IncrementalServiceConnector(*this, ifs.mountId); - sp<IncrementalDataLoaderListener> listener = - new IncrementalDataLoaderListener(*this, - externalListener ? *externalListener - : DataLoaderStatusListener()); - bool created = false; - auto status = mDataLoaderManager->initializeDataLoader(ifs.mountId, ifs.dataLoaderParams, fsControlParcel, listener, &created); - if (!status.isOk() || !created) { - LOG(ERROR) << "Failed to create a data loader for mount " << ifs.mountId; - return false; - } - return true; + + ifs.dataLoaderStub = new DataLoaderStub(*this, ifs.mountId, std::move(params), + std::move(fsControlParcel), externalListener); + return ifs.dataLoaderStub; } template <class Duration> @@ -1177,8 +1168,6 @@ static long elapsedMcs(Duration start, Duration end) { bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi) { - namespace sc = std::chrono; - using Clock = sc::steady_clock; auto start = Clock::now(); const auto ifs = getIfs(storage); @@ -1195,33 +1184,35 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ } auto mkDirsTs = Clock::now(); - - std::unique_ptr<ZipFileRO> zipFile(ZipFileRO::open(path::c_str(apkFullPath))); - if (!zipFile) { + ZipArchiveHandle zipFileHandle; + if (OpenArchive(path::c_str(apkFullPath), &zipFileHandle)) { LOG(ERROR) << "Failed to open zip file at " << apkFullPath; return false; } + + // Need a shared pointer: will be passing it into all unpacking jobs. + std::shared_ptr<ZipArchive> zipFile(zipFileHandle, [](ZipArchiveHandle h) { CloseArchive(h); }); void* cookie = nullptr; const auto libFilePrefix = path::join(constants().libDir, abi); - if (!zipFile->startIteration(&cookie, libFilePrefix.c_str() /* prefix */, - constants().libSuffix.data() /* suffix */)) { + if (StartIteration(zipFile.get(), &cookie, libFilePrefix, constants().libSuffix)) { LOG(ERROR) << "Failed to start zip iteration for " << apkFullPath; return false; } - auto endIteration = [&zipFile](void* cookie) { zipFile->endIteration(cookie); }; + auto endIteration = [](void* cookie) { EndIteration(cookie); }; auto iterationCleaner = std::unique_ptr<void, decltype(endIteration)>(cookie, endIteration); auto openZipTs = Clock::now(); - std::vector<IncFsDataBlock> instructions; - ZipEntryRO entry = nullptr; - while ((entry = zipFile->nextEntry(cookie)) != nullptr) { - auto startFileTs = Clock::now(); - - char fileName[PATH_MAX]; - if (zipFile->getEntryFileName(entry, fileName, sizeof(fileName))) { + std::vector<Job> jobQueue; + ZipEntry entry; + std::string_view fileName; + while (!Next(cookie, &entry, &fileName)) { + if (fileName.empty()) { continue; } + + auto startFileTs = Clock::now(); + const auto libName = path::basename(fileName); const auto targetLibPath = path::join(libDirRelativePath, libName); const auto targetLibPathAbsolute = normalizePathToStorage(ifs, storage, targetLibPath); @@ -1235,16 +1226,9 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ continue; } - uint32_t uncompressedLen, compressedLen; - if (!zipFile->getEntryInfo(entry, nullptr, &uncompressedLen, &compressedLen, nullptr, - nullptr, nullptr)) { - LOG(ERROR) << "Failed to read native lib entry: " << fileName; - return false; - } - // Create new lib file without signature info incfs::NewFileParams libFileParams = { - .size = uncompressedLen, + .size = entry.uncompressed_length, .signature = {}, // Metadata of the new lib file is its relative path .metadata = {targetLibPath.c_str(), (IncFsSize)targetLibPath.size()}, @@ -1260,68 +1244,45 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ auto makeFileTs = Clock::now(); // If it is a zero-byte file, skip data writing - if (uncompressedLen == 0) { + if (entry.uncompressed_length == 0) { if (sEnablePerfLogging) { - LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> " - << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, makeFileTs) - << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs); + LOG(INFO) << "incfs: Extracted " << libName + << "(0 bytes): " << elapsedMcs(startFileTs, makeFileTs) << "mcs"; } continue; } - // Write extracted data to new file - // NOTE: don't zero-initialize memory, it may take a while - auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[uncompressedLen]); - if (!zipFile->uncompressEntry(entry, libData.get(), uncompressedLen)) { - LOG(ERROR) << "Failed to extract native lib zip entry: " << fileName; - return false; - } - - auto extractFileTs = Clock::now(); + jobQueue.emplace_back([this, zipFile, entry, ifs = std::weak_ptr<IncFsMount>(ifs), + libFileId, libPath = std::move(targetLibPath), + makeFileTs]() mutable { + extractZipFile(ifs.lock(), zipFile.get(), entry, libFileId, libPath, makeFileTs); + }); - const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId); - if (!writeFd.ok()) { - LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; - return false; - } - - auto openFileTs = Clock::now(); - - const int numBlocks = (uncompressedLen + constants().blockSize - 1) / constants().blockSize; - instructions.clear(); - instructions.reserve(numBlocks); - auto remainingData = std::span(libData.get(), uncompressedLen); - for (int i = 0; i < numBlocks; i++) { - const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size()); - auto inst = IncFsDataBlock{ - .fileFd = writeFd.get(), - .pageIndex = static_cast<IncFsBlockIndex>(i), - .compression = INCFS_COMPRESSION_KIND_NONE, - .kind = INCFS_BLOCK_KIND_DATA, - .dataSize = blockSize, - .data = reinterpret_cast<const char*>(remainingData.data()), - }; - instructions.push_back(inst); - remainingData = remainingData.subspan(blockSize); + if (sEnablePerfLogging) { + auto prepareJobTs = Clock::now(); + LOG(INFO) << "incfs: Processed " << libName << ": " + << elapsedMcs(startFileTs, prepareJobTs) + << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs) + << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs); } - auto prepareInstsTs = Clock::now(); + } - size_t res = mIncFs->writeBlocks(instructions); - if (res != instructions.size()) { - LOG(ERROR) << "Failed to write data into: " << targetLibPath; - return false; - } + auto processedTs = Clock::now(); - if (sEnablePerfLogging) { - auto endFileTs = Clock::now(); - LOG(INFO) << "incfs: Extracted " << libName << "(" << compressedLen << " -> " - << uncompressedLen << " bytes): " << elapsedMcs(startFileTs, endFileTs) - << "mcs, make: " << elapsedMcs(startFileTs, makeFileTs) - << " extract: " << elapsedMcs(makeFileTs, extractFileTs) - << " open: " << elapsedMcs(extractFileTs, openFileTs) - << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs) - << " write:" << elapsedMcs(prepareInstsTs, endFileTs); + if (!jobQueue.empty()) { + { + std::lock_guard lock(mJobMutex); + if (mRunning) { + auto& existingJobs = mJobQueue[storage]; + if (existingJobs.empty()) { + existingJobs = std::move(jobQueue); + } else { + existingJobs.insert(existingJobs.end(), std::move_iterator(jobQueue.begin()), + std::move_iterator(jobQueue.end())); + } + } } + mJobCondition.notify_all(); } if (sEnablePerfLogging) { @@ -1329,12 +1290,112 @@ bool IncrementalService::configureNativeBinaries(StorageId storage, std::string_ LOG(INFO) << "incfs: configureNativeBinaries complete in " << elapsedMcs(start, end) << "mcs, make dirs: " << elapsedMcs(start, mkDirsTs) << " open zip: " << elapsedMcs(mkDirsTs, openZipTs) - << " extract all: " << elapsedMcs(openZipTs, end); + << " make files: " << elapsedMcs(openZipTs, processedTs) + << " schedule jobs: " << elapsedMcs(processedTs, end); } return true; } +void IncrementalService::extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, + ZipEntry& entry, const incfs::FileId& libFileId, + std::string_view targetLibPath, + Clock::time_point scheduledTs) { + if (!ifs) { + LOG(INFO) << "Skipping zip file " << targetLibPath << " extraction for an expired mount"; + return; + } + + auto libName = path::basename(targetLibPath); + auto startedTs = Clock::now(); + + // Write extracted data to new file + // NOTE: don't zero-initialize memory, it may take a while for nothing + auto libData = std::unique_ptr<uint8_t[]>(new uint8_t[entry.uncompressed_length]); + if (ExtractToMemory(zipFile, &entry, libData.get(), entry.uncompressed_length)) { + LOG(ERROR) << "Failed to extract native lib zip entry: " << libName; + return; + } + + auto extractFileTs = Clock::now(); + + const auto writeFd = mIncFs->openForSpecialOps(ifs->control, libFileId); + if (!writeFd.ok()) { + LOG(ERROR) << "Failed to open write fd for: " << targetLibPath << " errno: " << writeFd; + return; + } + + auto openFileTs = Clock::now(); + const int numBlocks = + (entry.uncompressed_length + constants().blockSize - 1) / constants().blockSize; + std::vector<IncFsDataBlock> instructions(numBlocks); + auto remainingData = std::span(libData.get(), entry.uncompressed_length); + for (int i = 0; i < numBlocks; i++) { + const auto blockSize = std::min<uint16_t>(constants().blockSize, remainingData.size()); + instructions[i] = IncFsDataBlock{ + .fileFd = writeFd.get(), + .pageIndex = static_cast<IncFsBlockIndex>(i), + .compression = INCFS_COMPRESSION_KIND_NONE, + .kind = INCFS_BLOCK_KIND_DATA, + .dataSize = blockSize, + .data = reinterpret_cast<const char*>(remainingData.data()), + }; + remainingData = remainingData.subspan(blockSize); + } + auto prepareInstsTs = Clock::now(); + + size_t res = mIncFs->writeBlocks(instructions); + if (res != instructions.size()) { + LOG(ERROR) << "Failed to write data into: " << targetLibPath; + return; + } + + if (sEnablePerfLogging) { + auto endFileTs = Clock::now(); + LOG(INFO) << "incfs: Extracted " << libName << "(" << entry.compressed_length << " -> " + << entry.uncompressed_length << " bytes): " << elapsedMcs(startedTs, endFileTs) + << "mcs, scheduling delay: " << elapsedMcs(scheduledTs, startedTs) + << " extract: " << elapsedMcs(startedTs, extractFileTs) + << " open: " << elapsedMcs(extractFileTs, openFileTs) + << " prepare: " << elapsedMcs(openFileTs, prepareInstsTs) + << " write: " << elapsedMcs(prepareInstsTs, endFileTs); + } +} + +bool IncrementalService::waitForNativeBinariesExtraction(StorageId storage) { + std::unique_lock lock(mJobMutex); + mJobCondition.wait(lock, [this, storage] { + return !mRunning || + (mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end()); + }); + return mPendingJobsStorage != storage && mJobQueue.find(storage) == mJobQueue.end(); +} + +void IncrementalService::runJobProcessing() { + for (;;) { + std::unique_lock lock(mJobMutex); + mJobCondition.wait(lock, [this]() { return !mRunning || !mJobQueue.empty(); }); + if (!mRunning) { + return; + } + + auto it = mJobQueue.begin(); + mPendingJobsStorage = it->first; + auto queue = std::move(it->second); + mJobQueue.erase(it); + lock.unlock(); + + for (auto&& job : queue) { + job(); + } + + lock.lock(); + mPendingJobsStorage = kInvalidStorageId; + lock.unlock(); + mJobCondition.notify_all(); + } +} + void IncrementalService::registerAppOpsCallback(const std::string& packageName) { sp<IAppOpsCallback> listener; { @@ -1347,7 +1408,8 @@ void IncrementalService::registerAppOpsCallback(const std::string& packageName) listener = cb; } - mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, String16(packageName.c_str()), listener); + mAppOpsManager->startWatchingMode(AppOpsManager::OP_GET_USAGE_STATS, + String16(packageName.c_str()), listener); } bool IncrementalService::unregisterAppOpsCallback(const std::string& packageName) { @@ -1376,7 +1438,7 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { std::lock_guard l(mLock); affected.reserve(mMounts.size()); for (auto&& [id, ifs] : mMounts) { - if (ifs->mountId == id && ifs->dataLoaderParams.packageName == packageName) { + if (ifs->mountId == id && ifs->dataLoaderStub->params().packageName == packageName) { affected.push_back(ifs); } } @@ -1386,37 +1448,79 @@ void IncrementalService::onAppOpChanged(const std::string& packageName) { } } -binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId, - int newStatus) { - if (externalListener) { +IncrementalService::DataLoaderStub::~DataLoaderStub() { + CHECK(mStatus == -1 || mStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) + << "Dataloader has to be destroyed prior to destructor: " << mId + << ", status: " << mStatus; +} + +bool IncrementalService::DataLoaderStub::create() { + bool created = false; + auto status = mService.mDataLoaderManager->initializeDataLoader(mId, mParams, mControl, this, + &created); + if (!status.isOk() || !created) { + LOG(ERROR) << "Failed to create a data loader for mount " << mId; + return false; + } + return true; +} + +bool IncrementalService::DataLoaderStub::start() { + if (mStatus != IDataLoaderStatusListener::DATA_LOADER_CREATED) { + mStartRequested = true; + return true; + } + + sp<IDataLoader> dataloader; + auto status = mService.mDataLoaderManager->getDataLoader(mId, &dataloader); + if (!status.isOk()) { + return false; + } + if (!dataloader) { + return false; + } + status = dataloader->start(mId); + if (!status.isOk()) { + return false; + } + return true; +} + +void IncrementalService::DataLoaderStub::destroy() { + mDestroyRequested = true; + mService.mDataLoaderManager->destroyDataLoader(mId); +} + +binder::Status IncrementalService::DataLoaderStub::onStatusChanged(MountId mountId, int newStatus) { + if (mStatus == newStatus) { + return binder::Status::ok(); + } + + if (mListener) { // Give an external listener a chance to act before we destroy something. - externalListener->onStatusChanged(mountId, newStatus); + mListener->onStatusChanged(mountId, newStatus); } - bool startRequested = false; { - std::unique_lock l(incrementalService.mLock); - const auto& ifs = incrementalService.getIfsLocked(mountId); + std::unique_lock l(mService.mLock); + const auto& ifs = mService.getIfsLocked(mountId); if (!ifs) { LOG(WARNING) << "Received data loader status " << int(newStatus) << " for unknown mount " << mountId; return binder::Status::ok(); } - ifs->dataLoaderStatus = newStatus; + mStatus = newStatus; - if (newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) { - ifs->dataLoaderStatus = IDataLoaderStatusListener::DATA_LOADER_STOPPED; - incrementalService.deleteStorageLocked(*ifs, std::move(l)); + if (!mDestroyRequested && newStatus == IDataLoaderStatusListener::DATA_LOADER_DESTROYED) { + mService.deleteStorageLocked(*ifs, std::move(l)); return binder::Status::ok(); } - - startRequested = ifs->dataLoaderStartRequested; } switch (newStatus) { case IDataLoaderStatusListener::DATA_LOADER_CREATED: { - if (startRequested) { - incrementalService.startDataLoader(mountId); + if (mStartRequested) { + start(); } break; } diff --git a/services/incremental/IncrementalService.h b/services/incremental/IncrementalService.h index db14a794457e..e7705df633d1 100644 --- a/services/incremental/IncrementalService.h +++ b/services/incremental/IncrementalService.h @@ -23,16 +23,19 @@ #include <utils/String16.h> #include <utils/StrongPointer.h> #include <utils/Vector.h> +#include <ziparchive/zip_archive.h> #include <atomic> #include <chrono> -#include <future> +#include <condition_variable> +#include <functional> #include <limits> #include <map> #include <mutex> #include <span> #include <string> #include <string_view> +#include <thread> #include <unordered_map> #include <utility> #include <vector> @@ -60,7 +63,8 @@ using Clock = std::chrono::steady_clock; using TimePoint = std::chrono::time_point<Clock>; using Seconds = std::chrono::seconds; -using DataLoaderStatusListener = ::android::sp<::android::content::pm::IDataLoaderStatusListener>; +using IDataLoaderStatusListener = ::android::content::pm::IDataLoaderStatusListener; +using DataLoaderStatusListener = ::android::sp<IDataLoaderStatusListener>; class IncrementalService final { public: @@ -95,7 +99,7 @@ public: void onDump(int fd); - std::optional<std::future<void>> onSystemReady(); + void onSystemReady(); StorageId createStorage(std::string_view mountPoint, DataLoaderParamsParcel&& dataLoaderParams, const DataLoaderStatusListener& dataLoaderStatusListener, @@ -131,25 +135,15 @@ public: std::vector<std::string> listFiles(StorageId storage) const; bool startLoading(StorageId storage) const; + bool configureNativeBinaries(StorageId storage, std::string_view apkFullPath, std::string_view libDirRelativePath, std::string_view abi); - - class IncrementalDataLoaderListener : public android::content::pm::BnDataLoaderStatusListener { - public: - IncrementalDataLoaderListener(IncrementalService& incrementalService, - DataLoaderStatusListener externalListener) - : incrementalService(incrementalService), externalListener(externalListener) {} - // Callbacks interface - binder::Status onStatusChanged(MountId mount, int newStatus) final; - - private: - IncrementalService& incrementalService; - DataLoaderStatusListener externalListener; - }; + bool waitForNativeBinariesExtraction(StorageId storage); class AppOpsListener : public android::BnAppOpsCallback { public: - AppOpsListener(IncrementalService& incrementalService, std::string packageName) : incrementalService(incrementalService), packageName(std::move(packageName)) {} + AppOpsListener(IncrementalService& incrementalService, std::string packageName) + : incrementalService(incrementalService), packageName(std::move(packageName)) {} void opChanged(int32_t op, const String16& packageName) final; private: @@ -171,6 +165,45 @@ public: private: static const bool sEnablePerfLogging; + struct IncFsMount; + + class DataLoaderStub : public android::content::pm::BnDataLoaderStatusListener { + public: + DataLoaderStub(IncrementalService& service, MountId id, DataLoaderParamsParcel&& params, + FileSystemControlParcel&& control, + const DataLoaderStatusListener* externalListener) + : mService(service), + mId(id), + mParams(std::move(params)), + mControl(std::move(control)), + mListener(externalListener ? *externalListener : DataLoaderStatusListener()) {} + ~DataLoaderStub(); + + bool create(); + bool start(); + void destroy(); + + // accessors + MountId id() const { return mId; } + const DataLoaderParamsParcel& params() const { return mParams; } + int status() const { return mStatus.load(); } + bool startRequested() const { return mStartRequested; } + + private: + binder::Status onStatusChanged(MountId mount, int newStatus) final; + + IncrementalService& mService; + MountId const mId; + DataLoaderParamsParcel const mParams; + FileSystemControlParcel const mControl; + DataLoaderStatusListener const mListener; + + std::atomic<int> mStatus = -1; + bool mStartRequested = false; + bool mDestroyRequested = false; + }; + using DataLoaderStubPtr = sp<DataLoaderStub>; + struct IncFsMount { struct Bind { StorageId storage; @@ -194,10 +227,8 @@ private: /*const*/ MountId mountId; StorageMap storages; BindMap bindPoints; - DataLoaderParamsParcel dataLoaderParams; + DataLoaderStubPtr dataLoaderStub; std::atomic<int> nextStorageDirNo{0}; - std::atomic<int> dataLoaderStatus = -1; - bool dataLoaderStartRequested = false; const IncrementalService& incrementalService; IncFsMount(std::string root, MountId mountId, Control control, @@ -232,8 +263,8 @@ private: std::string&& source, std::string&& target, BindKind kind, std::unique_lock<std::mutex>& mainLock); - bool prepareDataLoader(IncFsMount& ifs, const DataLoaderStatusListener* externalListener = nullptr); - bool startDataLoader(MountId mountId) const; + DataLoaderStubPtr prepareDataLoader(IncFsMount& ifs, DataLoaderParamsParcel&& params, + const DataLoaderStatusListener* externalListener = nullptr); BindPathMap::const_iterator findStorageLocked(std::string_view path) const; StorageId findStorageId(std::string_view path) const; @@ -252,11 +283,17 @@ private: bool unregisterAppOpsCallback(const std::string& packageName); void onAppOpChanged(const std::string& packageName); - // Member variables - std::unique_ptr<VoldServiceWrapper> const mVold; - std::unique_ptr<DataLoaderManagerWrapper> const mDataLoaderManager; - std::unique_ptr<IncFsWrapper> const mIncFs; - std::unique_ptr<AppOpsManagerWrapper> const mAppOpsManager; + void runJobProcessing(); + void extractZipFile(const IfsMountPtr& ifs, ZipArchiveHandle zipFile, ZipEntry& entry, + const incfs::FileId& libFileId, std::string_view targetLibPath, + Clock::time_point scheduledTs); + +private: + const std::unique_ptr<VoldServiceWrapper> mVold; + const std::unique_ptr<DataLoaderManagerWrapper> mDataLoaderManager; + const std::unique_ptr<IncFsWrapper> mIncFs; + const std::unique_ptr<AppOpsManagerWrapper> mAppOpsManager; + const std::unique_ptr<JniWrapper> mJni; const std::string mIncrementalDir; mutable std::mutex mLock; @@ -269,7 +306,14 @@ private: std::atomic_bool mSystemReady = false; StorageId mNextId = 0; - std::promise<void> mPrepareDataLoaders; + + using Job = std::function<void()>; + std::unordered_map<StorageId, std::vector<Job>> mJobQueue; + StorageId mPendingJobsStorage = kInvalidStorageId; + std::condition_variable mJobCondition; + std::mutex mJobMutex; + std::thread mJobProcessor; + bool mRunning = true; }; } // namespace android::incremental diff --git a/services/incremental/ServiceWrappers.cpp b/services/incremental/ServiceWrappers.cpp index 9f4192fbf531..bf8e696a264c 100644 --- a/services/incremental/ServiceWrappers.cpp +++ b/services/incremental/ServiceWrappers.cpp @@ -14,8 +14,11 @@ * limitations under the License. */ +#define LOG_TAG "IncrementalService" + #include "ServiceWrappers.h" +#include <android-base/logging.h> #include <utils/String16.h> using namespace std::literals; @@ -25,8 +28,123 @@ namespace android::os::incremental { static constexpr auto kVoldServiceName = "vold"sv; static constexpr auto kDataLoaderManagerName = "dataloader_manager"sv; -RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager) - : mServiceManager(std::move(serviceManager)) {} +class RealVoldService : public VoldServiceWrapper { +public: + RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {} + ~RealVoldService() = default; + binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir, + int32_t flags, + IncrementalFileSystemControlParcel* _aidl_return) const final { + return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); + } + binder::Status unmountIncFs(const std::string& dir) const final { + return mInterface->unmountIncFs(dir); + } + binder::Status bindMount(const std::string& sourceDir, + const std::string& targetDir) const final { + return mInterface->bindMount(sourceDir, targetDir); + } + binder::Status setIncFsMountOptions( + const ::android::os::incremental::IncrementalFileSystemControlParcel& control, + bool enableReadLogs) const final { + return mInterface->setIncFsMountOptions(control, enableReadLogs); + } + +private: + sp<os::IVold> mInterface; +}; + +class RealDataLoaderManager : public DataLoaderManagerWrapper { +public: + RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager) + : mInterface(manager) {} + ~RealDataLoaderManager() = default; + binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params, + const FileSystemControlParcel& control, + const sp<IDataLoaderStatusListener>& listener, + bool* _aidl_return) const final { + return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return); + } + binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final { + return mInterface->getDataLoader(mountId, _aidl_return); + } + binder::Status destroyDataLoader(MountId mountId) const final { + return mInterface->destroyDataLoader(mountId); + } + +private: + sp<content::pm::IDataLoaderManager> mInterface; +}; + +class RealAppOpsManager : public AppOpsManagerWrapper { +public: + ~RealAppOpsManager() = default; + binder::Status checkPermission(const char* permission, const char* operation, + const char* package) const final { + return android::incremental::CheckPermissionForDataDelivery(permission, operation, package); + } + void startWatchingMode(int32_t op, const String16& packageName, + const sp<IAppOpsCallback>& callback) final { + mAppOpsManager.startWatchingMode(op, packageName, callback); + } + void stopWatchingMode(const sp<IAppOpsCallback>& callback) final { + mAppOpsManager.stopWatchingMode(callback); + } + +private: + android::AppOpsManager mAppOpsManager; +}; + +class RealJniWrapper final : public JniWrapper { +public: + RealJniWrapper(JavaVM* jvm); + void initializeForCurrentThread() const final; + + static JavaVM* getJvm(JNIEnv* env); + +private: + JavaVM* const mJvm; +}; + +class RealIncFs : public IncFsWrapper { +public: + RealIncFs() = default; + ~RealIncFs() = default; + Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final { + return incfs::createControl(cmd, pendingReads, logs); + } + ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, + NewFileParams params) const final { + return incfs::makeFile(control, path, mode, id, params); + } + ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final { + return incfs::makeDir(control, path, mode); + } + RawMetadata getMetadata(const Control& control, FileId fileid) const final { + return incfs::getMetadata(control, fileid); + } + RawMetadata getMetadata(const Control& control, std::string_view path) const final { + return incfs::getMetadata(control, path); + } + FileId getFileId(const Control& control, std::string_view path) const final { + return incfs::getFileId(control, path); + } + ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final { + return incfs::link(control, from, to); + } + ErrorCode unlink(const Control& control, std::string_view path) const final { + return incfs::unlink(control, path); + } + base::unique_fd openForSpecialOps(const Control& control, FileId id) const final { + return base::unique_fd{incfs::openForSpecialOps(control, id).release()}; + } + ErrorCode writeBlocks(Span<const DataBlock> blocks) const final { + return incfs::writeBlocks(blocks); + } +}; + +RealServiceManager::RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env) + : mServiceManager(std::move(serviceManager)), mJvm(RealJniWrapper::getJvm(env)) {} template <class INTERFACE> sp<INTERFACE> RealServiceManager::getRealService(std::string_view serviceName) const { @@ -63,4 +181,62 @@ std::unique_ptr<AppOpsManagerWrapper> RealServiceManager::getAppOpsManager() { return std::make_unique<RealAppOpsManager>(); } +std::unique_ptr<JniWrapper> RealServiceManager::getJni() { + return std::make_unique<RealJniWrapper>(mJvm); +} + +static JavaVM* getJavaVm(JNIEnv* env) { + CHECK(env); + JavaVM* jvm = nullptr; + env->GetJavaVM(&jvm); + CHECK(jvm); + return jvm; +} + +static JNIEnv* getJniEnv(JavaVM* vm) { + JNIEnv* env; + if (vm->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) { + return nullptr; + } + return env; +} + +static JNIEnv* getOrAttachJniEnv(JavaVM* jvm) { + if (!jvm) { + LOG(ERROR) << "No JVM instance"; + return nullptr; + } + + JNIEnv* env = getJniEnv(jvm); + if (!env) { + int result = jvm->AttachCurrentThread(&env, nullptr); + if (result != JNI_OK) { + LOG(ERROR) << "JVM thread attach failed: " << result; + return nullptr; + } + struct VmDetacher { + VmDetacher(JavaVM* vm) : mVm(vm) {} + ~VmDetacher() { mVm->DetachCurrentThread(); } + + private: + JavaVM* const mVm; + }; + static thread_local VmDetacher detacher(jvm); + } + + return env; +} + +RealJniWrapper::RealJniWrapper(JavaVM* jvm) : mJvm(jvm) { + CHECK(!!mJvm) << "JVM is unavailable"; +} + +void RealJniWrapper::initializeForCurrentThread() const { + (void)getOrAttachJniEnv(mJvm); +} + +JavaVM* RealJniWrapper::getJvm(JNIEnv* env) { + return getJavaVm(env); +} + } // namespace android::os::incremental diff --git a/services/incremental/ServiceWrappers.h b/services/incremental/ServiceWrappers.h index 84bf1ffaf45c..142bf2ef32f3 100644 --- a/services/incremental/ServiceWrappers.h +++ b/services/incremental/ServiceWrappers.h @@ -29,6 +29,7 @@ #include <binder/AppOpsManager.h> #include <binder/IServiceManager.h> #include <incfs.h> +#include <jni.h> #include <memory> #include <string> @@ -93,6 +94,12 @@ public: virtual void stopWatchingMode(const sp<IAppOpsCallback>& callback) = 0; }; +class JniWrapper { +public: + virtual ~JniWrapper() = default; + virtual void initializeForCurrentThread() const = 0; +}; + class ServiceManagerWrapper { public: virtual ~ServiceManagerWrapper() = default; @@ -100,127 +107,26 @@ public: virtual std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() = 0; virtual std::unique_ptr<IncFsWrapper> getIncFs() = 0; virtual std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() = 0; + virtual std::unique_ptr<JniWrapper> getJni() = 0; }; // --- Real stuff --- -class RealVoldService : public VoldServiceWrapper { -public: - RealVoldService(const sp<os::IVold> vold) : mInterface(std::move(vold)) {} - ~RealVoldService() = default; - binder::Status mountIncFs(const std::string& backingPath, const std::string& targetDir, - int32_t flags, - IncrementalFileSystemControlParcel* _aidl_return) const final { - return mInterface->mountIncFs(backingPath, targetDir, flags, _aidl_return); - } - binder::Status unmountIncFs(const std::string& dir) const final { - return mInterface->unmountIncFs(dir); - } - binder::Status bindMount(const std::string& sourceDir, - const std::string& targetDir) const final { - return mInterface->bindMount(sourceDir, targetDir); - } - binder::Status setIncFsMountOptions( - const ::android::os::incremental::IncrementalFileSystemControlParcel& control, - bool enableReadLogs) const final { - return mInterface->setIncFsMountOptions(control, enableReadLogs); - } - -private: - sp<os::IVold> mInterface; -}; - -class RealDataLoaderManager : public DataLoaderManagerWrapper { -public: - RealDataLoaderManager(const sp<content::pm::IDataLoaderManager> manager) - : mInterface(manager) {} - ~RealDataLoaderManager() = default; - binder::Status initializeDataLoader(MountId mountId, const DataLoaderParamsParcel& params, - const FileSystemControlParcel& control, - const sp<IDataLoaderStatusListener>& listener, - bool* _aidl_return) const final { - return mInterface->initializeDataLoader(mountId, params, control, listener, _aidl_return); - } - binder::Status getDataLoader(MountId mountId, sp<IDataLoader>* _aidl_return) const final { - return mInterface->getDataLoader(mountId, _aidl_return); - } - binder::Status destroyDataLoader(MountId mountId) const final { - return mInterface->destroyDataLoader(mountId); - } - -private: - sp<content::pm::IDataLoaderManager> mInterface; -}; - -class RealAppOpsManager : public AppOpsManagerWrapper { -public: - ~RealAppOpsManager() = default; - binder::Status checkPermission(const char* permission, const char* operation, - const char* package) const final { - return android::incremental::CheckPermissionForDataDelivery(permission, operation, package); - } - void startWatchingMode(int32_t op, const String16& packageName, - const sp<IAppOpsCallback>& callback) final { - mAppOpsManager.startWatchingMode(op, packageName, callback); - } - void stopWatchingMode(const sp<IAppOpsCallback>& callback) final { - mAppOpsManager.stopWatchingMode(callback); - } - -private: - android::AppOpsManager mAppOpsManager; -}; - class RealServiceManager : public ServiceManagerWrapper { public: - RealServiceManager(sp<IServiceManager> serviceManager); + RealServiceManager(sp<IServiceManager> serviceManager, JNIEnv* env); ~RealServiceManager() = default; std::unique_ptr<VoldServiceWrapper> getVoldService() final; std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final; std::unique_ptr<IncFsWrapper> getIncFs() final; std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final; + std::unique_ptr<JniWrapper> getJni() final; private: template <class INTERFACE> sp<INTERFACE> getRealService(std::string_view serviceName) const; sp<android::IServiceManager> mServiceManager; -}; - -class RealIncFs : public IncFsWrapper { -public: - RealIncFs() = default; - ~RealIncFs() = default; - Control createControl(IncFsFd cmd, IncFsFd pendingReads, IncFsFd logs) const final { - return incfs::createControl(cmd, pendingReads, logs); - } - ErrorCode makeFile(const Control& control, std::string_view path, int mode, FileId id, - NewFileParams params) const final { - return incfs::makeFile(control, path, mode, id, params); - } - ErrorCode makeDir(const Control& control, std::string_view path, int mode) const final { - return incfs::makeDir(control, path, mode); - } - RawMetadata getMetadata(const Control& control, FileId fileid) const final { - return incfs::getMetadata(control, fileid); - } - RawMetadata getMetadata(const Control& control, std::string_view path) const final { - return incfs::getMetadata(control, path); - } - FileId getFileId(const Control& control, std::string_view path) const final { - return incfs::getFileId(control, path); - } - ErrorCode link(const Control& control, std::string_view from, std::string_view to) const final { - return incfs::link(control, from, to); - } - ErrorCode unlink(const Control& control, std::string_view path) const final { - return incfs::unlink(control, path); - } - base::unique_fd openForSpecialOps(const Control& control, FileId id) const final { - return base::unique_fd{incfs::openForSpecialOps(control, id).release()}; - } - ErrorCode writeBlocks(Span<const DataBlock> blocks) const final { - return incfs::writeBlocks(blocks); - } + JavaVM* const mJvm; }; } // namespace android::os::incremental diff --git a/services/incremental/include/incremental_service.h b/services/incremental/include/incremental_service.h index 4a34b11261b9..321387531694 100644 --- a/services/incremental/include/incremental_service.h +++ b/services/incremental/include/incremental_service.h @@ -24,7 +24,7 @@ __BEGIN_DECLS #define INCREMENTAL_LIBRARY_NAME "service.incremental.so" -jlong Incremental_IncrementalService_Start(); +jlong Incremental_IncrementalService_Start(JNIEnv* env); void Incremental_IncrementalService_OnSystemReady(jlong self); void Incremental_IncrementalService_OnDump(jlong self, jint fd); diff --git a/services/incremental/test/IncrementalServiceTest.cpp b/services/incremental/test/IncrementalServiceTest.cpp index 18ae4b5af435..117dca8c37b3 100644 --- a/services/incremental/test/IncrementalServiceTest.cpp +++ b/services/incremental/test/IncrementalServiceTest.cpp @@ -131,6 +131,23 @@ public: binder::Status(int32_t mountId, sp<IDataLoader>* _aidl_return)); MOCK_CONST_METHOD1(destroyDataLoader, binder::Status(int32_t mountId)); + void initializeDataLoaderSuccess() { + ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::initializeDataLoaderOk)); + } + void initializeDataLoaderFails() { + ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) + .WillByDefault(Return( + (binder::Status::fromExceptionCode(1, String8("failed to prepare"))))); + } + void getDataLoaderSuccess() { + ON_CALL(*this, getDataLoader(_, _)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); + } + void destroyDataLoaderOk() { + ON_CALL(*this, destroyDataLoader(_)) + .WillByDefault(Invoke(this, &MockDataLoaderManager::setDataLoaderStatusDestroyed)); + } binder::Status initializeDataLoaderOk(int32_t mountId, const DataLoaderParamsParcel& params, const FileSystemControlParcel& control, const sp<IDataLoaderStatusListener>& listener, @@ -141,32 +158,22 @@ public: *_aidl_return = true; return binder::Status::ok(); } - binder::Status getDataLoaderOk(int32_t mountId, sp<IDataLoader>* _aidl_return) { *_aidl_return = mDataLoader; return binder::Status::ok(); } - - void initializeDataLoaderFails() { - ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) - .WillByDefault(Return( - (binder::Status::fromExceptionCode(1, String8("failed to prepare"))))); - } - void initializeDataLoaderSuccess() { - ON_CALL(*this, initializeDataLoader(_, _, _, _, _)) - .WillByDefault(Invoke(this, &MockDataLoaderManager::initializeDataLoaderOk)); - } - void getDataLoaderSuccess() { - ON_CALL(*this, getDataLoader(_, _)) - .WillByDefault(Invoke(this, &MockDataLoaderManager::getDataLoaderOk)); - } void setDataLoaderStatusNotReady() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); } void setDataLoaderStatusReady() { mListener->onStatusChanged(mId, IDataLoaderStatusListener::DATA_LOADER_CREATED); } - + binder::Status setDataLoaderStatusDestroyed(int32_t id) { + if (mListener) { + mListener->onStatusChanged(id, IDataLoaderStatusListener::DATA_LOADER_DESTROYED); + } + return binder::Status::ok(); + } int32_t setStorageParams(bool enableReadLogs) { int32_t result = -1; EXPECT_NE(mServiceConnector.get(), nullptr); @@ -254,28 +261,39 @@ public: sp<IAppOpsCallback> mStoredCallback; }; +class MockJniWrapper : public JniWrapper { +public: + MOCK_CONST_METHOD0(initializeForCurrentThread, void()); + + MockJniWrapper() { EXPECT_CALL(*this, initializeForCurrentThread()).Times(1); } +}; + class MockServiceManager : public ServiceManagerWrapper { public: MockServiceManager(std::unique_ptr<MockVoldService> vold, - std::unique_ptr<MockDataLoaderManager> manager, + std::unique_ptr<MockDataLoaderManager> dataLoaderManager, std::unique_ptr<MockIncFs> incfs, - std::unique_ptr<MockAppOpsManager> appOpsManager) + std::unique_ptr<MockAppOpsManager> appOpsManager, + std::unique_ptr<MockJniWrapper> jni) : mVold(std::move(vold)), - mDataLoaderManager(std::move(manager)), + mDataLoaderManager(std::move(dataLoaderManager)), mIncFs(std::move(incfs)), - mAppOpsManager(std::move(appOpsManager)) {} + mAppOpsManager(std::move(appOpsManager)), + mJni(std::move(jni)) {} std::unique_ptr<VoldServiceWrapper> getVoldService() final { return std::move(mVold); } std::unique_ptr<DataLoaderManagerWrapper> getDataLoaderManager() final { return std::move(mDataLoaderManager); } std::unique_ptr<IncFsWrapper> getIncFs() final { return std::move(mIncFs); } std::unique_ptr<AppOpsManagerWrapper> getAppOpsManager() final { return std::move(mAppOpsManager); } + std::unique_ptr<JniWrapper> getJni() final { return std::move(mJni); } private: std::unique_ptr<MockVoldService> mVold; std::unique_ptr<MockDataLoaderManager> mDataLoaderManager; std::unique_ptr<MockIncFs> mIncFs; std::unique_ptr<MockAppOpsManager> mAppOpsManager; + std::unique_ptr<MockJniWrapper> mJni; }; // --- IncrementalServiceTest --- @@ -291,14 +309,19 @@ public: mIncFs = incFs.get(); auto appOps = std::make_unique<NiceMock<MockAppOpsManager>>(); mAppOpsManager = appOps.get(); + auto jni = std::make_unique<NiceMock<MockJniWrapper>>(); + mJni = jni.get(); mIncrementalService = std::make_unique<IncrementalService>(MockServiceManager(std::move(vold), - std::move(dataloaderManager), + std::move( + dataloaderManager), std::move(incFs), - std::move(appOps)), + std::move(appOps), + std::move(jni)), mRootDir.path); mDataLoaderParcel.packageName = "com.test"; mDataLoaderParcel.arguments = "uri"; + mDataLoaderManager->destroyDataLoaderOk(); mIncrementalService->onSystemReady(); } @@ -328,6 +351,7 @@ protected: NiceMock<MockIncFs>* mIncFs; NiceMock<MockDataLoaderManager>* mDataLoaderManager; NiceMock<MockAppOpsManager>* mAppOpsManager; + NiceMock<MockJniWrapper>* mJni; std::unique_ptr<IncrementalService> mIncrementalService; TemporaryDir mRootDir; DataLoaderParamsParcel mDataLoaderParcel; @@ -346,6 +370,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsFails) { TEST_F(IncrementalServiceTest, testCreateStorageMountIncFsInvalidControlParcel) { mVold->mountIncFsInvalidControlParcel(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); TemporaryDir tempDir; int storageId = mIncrementalService->createStorage(tempDir.path, std::move(mDataLoaderParcel), {}, @@ -357,7 +382,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageMakeFileFails) { mVold->mountIncFsSuccess(); mIncFs->makeFileFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; int storageId = @@ -371,7 +396,7 @@ TEST_F(IncrementalServiceTest, testCreateStorageBindMountFails) { mIncFs->makeFileSuccess(); mVold->bindMountFails(); EXPECT_CALL(*mDataLoaderManager, initializeDataLoader(_, _, _, _, _)).Times(0); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(0); EXPECT_CALL(*mVold, unmountIncFs(_)); TemporaryDir tempDir; int storageId = @@ -385,7 +410,7 @@ TEST_F(IncrementalServiceTest, testCreateStoragePrepareDataLoaderFails) { mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderFails(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = @@ -399,7 +424,7 @@ TEST_F(IncrementalServiceTest, testDeleteStorageSuccess) { mIncFs->makeFileSuccess(); mVold->bindMountSuccess(); mDataLoaderManager->initializeDataLoaderSuccess(); - EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)); + EXPECT_CALL(*mDataLoaderManager, destroyDataLoader(_)).Times(1); EXPECT_CALL(*mVold, unmountIncFs(_)).Times(2); TemporaryDir tempDir; int storageId = diff --git a/services/net/Android.bp b/services/net/Android.bp index c54102fb1d3d..9f2979906d42 100644 --- a/services/net/Android.bp +++ b/services/net/Android.bp @@ -12,8 +12,8 @@ java_library_static { ":services.net-sources", ], static_libs: [ - "dnsresolver_aidl_interface-V2-java", - "netd_aidl_interface-unstable-java", + "dnsresolver_aidl_interface-V4-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-client", "net-utils-services-common", @@ -44,7 +44,7 @@ java_library { ], static_libs: [ "dnsresolver_aidl_interface-V2-java", - "netd_aidl_interface-unstable-java", + "netd_aidl_interface-V3-java", "netlink-client", "networkstack-client", "net-utils-services-common", 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 f4d7b8bd5b1a..d338b587e059 100644 --- a/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java +++ b/services/tests/mockingservicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java @@ -382,6 +382,7 @@ public class BlobStoreManagerServiceTest { doReturn(hasLeases).when(blobMetadata).hasLeases(); doReturn(blobHandle).when(blobMetadata).getBlobHandle(); doCallRealMethod().when(blobMetadata).shouldBeDeleted(anyBoolean()); + doReturn(true).when(blobMetadata).hasLeaseWaitTimeElapsedForAll(); return blobMetadata; } diff --git a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java index ccbaee41af7c..aa923e22444d 100644 --- a/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java +++ b/services/tests/servicestests/src/com/android/server/lights/LightsServiceTest.java @@ -63,6 +63,16 @@ public class LightsServiceTest { fakeHwLight(105, LightsManager.LIGHT_TYPE_MICROPHONE, 2) }; } + + @Override + public int getInterfaceVersion() { + return this.VERSION; + } + + @Override + public String getInterfaceHash() { + return this.HASH; + } }; private static HwLight fakeHwLight(int id, int type, int ordinal) { 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 820e61cb0a08..9eda718ed922 100644 --- a/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java +++ b/services/tests/servicestests/src/com/android/server/om/OverlayManagerServiceImplTestsBase.java @@ -377,8 +377,7 @@ class OverlayManagerServiceImplTestsBase { return false; } final String key = createKey(overlayPackage.packageName, userId); - mIdmapFiles.add(key); - return true; + return mIdmapFiles.add(key); } @Override diff --git a/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java b/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java new file mode 100644 index 000000000000..cfeadc6893db --- /dev/null +++ b/services/tests/servicestests/src/com/android/server/stats/pull/SettingsStatsUtilTest.java @@ -0,0 +1,109 @@ +/* + * 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.stats.pull; + +import static android.os.UserHandle.USER_SYSTEM; + +import static com.android.internal.util.FrameworkStatsLog.SETTING_SNAPSHOT; + +import static org.junit.Assert.assertArrayEquals; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNull; + +import android.content.Context; +import android.provider.DeviceConfig; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +/** + * Build/Install/Run: + * atest FrameworksServicesTests:SettingsStatsUtilTest + */ +@RunWith(AndroidJUnit4.class) +public class SettingsStatsUtilTest { + private static final String[] KEYS = new String[]{ + "screen_auto_brightness_adj", + "font_scale" + }; + private static final String ENCODED = "ChpzY3JlZW5fYXV0b19icmlnaHRuZXNzX2FkagoKZm9udF9zY2FsZQ"; + private static final String FLAG = "testflag"; + private Context mContext; + + @Before + public void setUp() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + FLAG, + "", + false /* makeDefault*/); + mContext = InstrumentationRegistry.getInstrumentation().getContext(); + } + + @Test + public void getList_emptyString_nullValue() { + assertNull(SettingsStatsUtil.getList(FLAG)); + } + + @Test + public void getList_notValidString_nullValue() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, "abcd", false); + + assertNull(SettingsStatsUtil.getList(FLAG)); + } + + @Test + public void getList_validString_correctValue() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, FLAG, ENCODED, false); + + assertArrayEquals(KEYS, SettingsStatsUtil.getList(FLAG).element); + } + + @Test + public void logGlobalSettings_noWhitelist_correctSize() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__boolean_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__integer_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__float_whitelist", "", false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__string_whitelist", "", false); + + assertEquals(0, SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, + USER_SYSTEM).size()); + } + + @Test + public void logGlobalSettings_correctSize() { + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__boolean_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__integer_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__float_whitelist", ENCODED, false); + DeviceConfig.setProperty(DeviceConfig.NAMESPACE_SETTINGS_STATS, + "GlobalFeature__string_whitelist", ENCODED, false); + + assertEquals(KEYS.length * 4, + SettingsStatsUtil.logGlobalSettings(mContext, SETTING_SNAPSHOT, + USER_SYSTEM).size()); + } +} diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java index 22d7fcbb4162..5c6906cfa942 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStackSupervisorTests.java @@ -125,7 +125,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { spyOn(taskChangeNotifier); mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(), - newDisplay.mDisplayId, stack); + newDisplay.getDefaultTaskDisplayArea(), stack); // The top activity is unresizable, so it should notify the activity is forced resizing. verify(taskChangeNotifier).notifyActivityForcedResizable(eq(task.mTaskId), eq(FORCED_RESIZEABLE_REASON_SECONDARY_DISPLAY), @@ -138,7 +138,7 @@ public class ActivityStackSupervisorTests extends ActivityTestsBase { resizableActivity.info.resizeMode = ActivityInfo.RESIZE_MODE_RESIZEABLE; mSupervisor.handleNonResizableTaskIfNeeded(task, newDisplay.getWindowingMode(), - newDisplay.mDisplayId, stack); + newDisplay.getDefaultTaskDisplayArea(), stack); // For the resizable activity, it is no need to force resizing or dismiss the docked stack. verify(taskChangeNotifier, never()).notifyActivityForcedResizable(anyInt() /* taskId */, anyInt() /* reason */, anyString() /* packageName */); diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java index 1144272a0e46..8a9504dd11b5 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsControllerTests.java @@ -23,12 +23,14 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.INVALID_DISPLAY; import static com.android.dx.mockito.inline.extended.ExtendedMockito.any; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyBoolean; import static com.android.dx.mockito.inline.extended.ExtendedMockito.anyInt; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.eq; import static com.android.dx.mockito.inline.extended.ExtendedMockito.mock; import static com.android.dx.mockito.inline.extended.ExtendedMockito.never; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy; +import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.times; import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify; import static com.android.server.wm.LaunchParamsController.LaunchParamsModifier.PHASE_BOUNDS; @@ -54,6 +56,7 @@ import com.android.server.wm.LaunchParamsController.LaunchParamsModifier; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; import java.util.Map; @@ -65,6 +68,7 @@ import java.util.Map; */ @MediumTest @Presubmit +@RunWith(WindowTestRunner.class) public class LaunchParamsControllerTests extends ActivityTestsBase { private LaunchParamsController mController; private TestLaunchParamsPersister mPersister; @@ -276,16 +280,21 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { @Test public void testLayoutTaskPreferredDisplayChange() { final LaunchParams params = new LaunchParams(); - params.mPreferredDisplayId = 2; + final TestDisplayContent display = createNewDisplayContent(); + final TaskDisplayArea preferredTaskDisplayArea = display.getDefaultTaskDisplayArea(); + // TODO(b/152116619): Enable after complete switch to WindowContainerToken + //params.mPreferredWindowContainerToken = preferredTaskDisplayAreaToken; + params.mPreferredDisplayId = display.mDisplayId; final InstrumentedPositioner positioner = new InstrumentedPositioner(RESULT_DONE, params); final Task task = new TaskBuilder(mService.mStackSupervisor).build(); mController.registerModifier(positioner); - doNothing().when(mService).moveStackToDisplay(anyInt(), anyInt()); + doNothing().when(mRootWindowContainer).moveStackToTaskDisplayArea(anyInt(), any(), + anyBoolean()); mController.layoutTask(task, null /* windowLayout */); - verify(mService, times(1)).moveStackToDisplay(eq(task.getRootTaskId()), - eq(params.mPreferredDisplayId)); + verify(mRootWindowContainer, times(1)).moveStackToTaskDisplayArea(eq(task.getRootTaskId()), + eq(preferredTaskDisplayArea), anyBoolean()); } /** @@ -452,4 +461,14 @@ public class LaunchParamsControllerTests extends ActivityTestsBase { } } } + + private TestDisplayContent createNewDisplayContent() { + final TestDisplayContent display = addNewDisplayContentAt(DisplayContent.POSITION_TOP); + spyOn(display.mDisplayContent.mDisplayFrames); + + // We didn't set up the overall environment for this test, so we need to mute the side + // effect of layout passes that loosen the stable frame. + doNothing().when(display.mDisplayContent.mDisplayFrames).onBeginLayout(); + return display; + } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java index b648346eeb28..7613655e9f35 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootActivityContainerTests.java @@ -26,6 +26,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMAR import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE; import static android.view.Display.DEFAULT_DISPLAY; import static android.view.Display.TYPE_VIRTUAL; +import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing; import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; @@ -247,6 +248,44 @@ public class RootActivityContainerTests extends ActivityTestsBase { assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); } + /** + * Verifies that removal of activities with task and stack is done correctly when there are + * several task display areas. + */ + @Test + public void testRemovingStackOnAppCrash_multipleDisplayAreas() { + final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer + .getDefaultTaskDisplayArea(); + final int originalStackCount = defaultTaskDisplayArea.getStackCount(); + final ActivityStack stack = defaultTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + final ActivityRecord firstActivity = new ActivityBuilder(mService).setCreateTask(true) + .setStack(stack).build(); + assertEquals(originalStackCount + 1, defaultTaskDisplayArea.getStackCount()); + + final DisplayContent dc = defaultTaskDisplayArea.getDisplayContent(); + doReturn(2).when(dc).getTaskDisplayAreaCount(); + final TaskDisplayArea secondTaskDisplayArea = new TaskDisplayArea(dc, + mRootWindowContainer.mWmService, "SecondaryTaskDisplayArea", FEATURE_VENDOR_FIRST); + // Add second display area right above the default one + defaultTaskDisplayArea.getParent().addChild(secondTaskDisplayArea, + defaultTaskDisplayArea.getParent().mChildren.indexOf(defaultTaskDisplayArea) + 1); + doReturn(secondTaskDisplayArea).when(dc).getTaskDisplayAreaAt(1); + final ActivityStack secondStack = secondTaskDisplayArea.createStack( + WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); + new ActivityBuilder(mService).setCreateTask(true).setStack(secondStack) + .setUseProcess(firstActivity.app).build(); + assertEquals(1, secondTaskDisplayArea.getStackCount()); + + // Let's pretend that the app has crashed. + firstActivity.app.setThread(null); + mRootWindowContainer.finishTopCrashedActivities(firstActivity.app, "test"); + + // Verify that the stacks were removed. + assertEquals(originalStackCount, defaultTaskDisplayArea.getStackCount()); + assertEquals(0, secondTaskDisplayArea.getStackCount()); + } + @Test public void testFocusability() { final TaskDisplayArea defaultTaskDisplayArea = mRootWindowContainer @@ -400,7 +439,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { taskDisplayArea.getRootHomeTask().removeIfPossible(); taskDisplayArea.createStack(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_HOME, ON_TOP); - doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt()); + doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); mService.setBooted(true); @@ -408,7 +447,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.resumeFocusedStacksTopActivities(); // Verify that home activity was started on the default display - verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY)); + verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); } /** @@ -430,7 +469,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { final Task task = new TaskBuilder(mSupervisor).setStack(stack).build(); new ActivityBuilder(mService).setTask(task).build(); - doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), anyInt()); + doReturn(true).when(mRootWindowContainer).resumeHomeActivity(any(), any(), any()); mService.setBooted(true); @@ -438,7 +477,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.resumeFocusedStacksTopActivities(); // Verify that home activity was started on the default display - verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(DEFAULT_DISPLAY)); + verify(mRootWindowContainer).resumeHomeActivity(any(), any(), eq(taskDisplayArea)); } /** @@ -575,8 +614,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); try { - verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), - anyInt()); + verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); } finally { mRootWindowContainer.mCurrentUser = currentUser; } @@ -596,7 +634,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { mRootWindowContainer.startHomeOnDisplay(0 /* userId */, "testStartSecondaryHome", secondDisplay.mDisplayId, true /* allowInstrumenting */, true /* fromHomeKey */); - verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), anyInt()); + verify(mRootWindowContainer, never()).resolveSecondaryHomeActivity(anyInt(), any()); } /** @@ -634,7 +672,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, @@ -665,7 +703,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -686,7 +724,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false /* primaryHome*/); assertEquals(aInfoSecondary.name, resolvedInfo.first.name); assertEquals(aInfoSecondary.applicationInfo.packageName, @@ -718,7 +756,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Run the test. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(aInfoPrimary.name, resolvedInfo.first.name); assertEquals(aInfoPrimary.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -752,7 +790,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { // Use the first one of matched activities in the same package as selected primary home. final Pair<ActivityInfo, Intent> resolvedInfo = mRootWindowContainer - .resolveSecondaryHomeActivity(0 /* userId */, 1 /* displayId */); + .resolveSecondaryHomeActivity(0 /* userId */, mock(TaskDisplayArea.class)); assertEquals(infoFake1.activityInfo.applicationInfo.packageName, resolvedInfo.first.applicationInfo.packageName); @@ -862,7 +900,7 @@ public class RootActivityContainerTests extends ActivityTestsBase { .getSecondaryHomeIntent(null /* preferredPackage */); final ActivityInfo aInfoSecondary = getFakeHomeActivityInfo(false); doReturn(Pair.create(aInfoSecondary, secondaryHomeIntent)).when(mRootWindowContainer) - .resolveSecondaryHomeActivity(anyInt(), anyInt()); + .resolveSecondaryHomeActivity(anyInt(), any()); } private ActivityInfo getFakeHomeActivityInfo(boolean primaryHome) { diff --git a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java index 7a075a26cb31..4a8e8dafb57d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java +++ b/services/tests/wmtests/src/com/android/server/wm/TestWindowManagerPolicy.java @@ -120,8 +120,8 @@ class TestWindowManagerPolicy implements WindowManagerPolicy { IWindow iWindow = mock(IWindow.class); doReturn(mock(IBinder.class)).when(iWindow).asBinder(); window = WindowTestsBase.createWindow(null, TYPE_APPLICATION_STARTING, activity, - "Starting window", 0 /* ownerId */, false /* internalWindows */, wm, - mock(Session.class), iWindow, mPowerManagerWrapper); + "Starting window", 0 /* ownerId */, 0 /* userId*/, false /* internalWindows */, + wm, mock(Session.class), iWindow, mPowerManagerWrapper); activity.startingWindow = window; } if (mRunnableWhenAddingSplashScreen != null) { diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java index 084216a9a543..fc95556750f1 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestUtils.java @@ -112,7 +112,7 @@ class WindowTestUtils { TestWindowState(WindowManagerService service, Session session, IWindow window, WindowManager.LayoutParams attrs, WindowToken token) { - super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, + super(service, session, window, token, null, OP_NONE, 0, attrs, 0, 0, 0, false /* ownerCanAddInternalSystemWindow */); } diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 397f73c3e67c..e561c13a4e99 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -41,6 +41,7 @@ import static org.mockito.Mockito.mock; import android.content.Context; import android.content.Intent; +import android.os.UserHandle; import android.util.Log; import android.view.Display; import android.view.DisplayInfo; @@ -296,12 +297,13 @@ class WindowTestsBase extends SystemServiceTestsBase { WindowState createWindow(WindowState parent, int type, WindowToken token, String name, int ownerId, boolean ownerCanAddInternalSystemWindow) { - return createWindow(parent, type, token, name, ownerId, ownerCanAddInternalSystemWindow, - mWm, mMockSession, mIWindow, mSystemServicesTestRule.getPowerManagerWrapper()); + return createWindow(parent, type, token, name, ownerId, UserHandle.getUserId(ownerId), + ownerCanAddInternalSystemWindow, mWm, mMockSession, mIWindow, + mSystemServicesTestRule.getPowerManagerWrapper()); } static WindowState createWindow(WindowState parent, int type, WindowToken token, - String name, int ownerId, boolean ownerCanAddInternalSystemWindow, + String name, int ownerId, int userId, boolean ownerCanAddInternalSystemWindow, WindowManagerService service, Session session, IWindow iWindow, WindowState.PowerManagerWrapper powerManagerWrapper) { synchronized (service.mGlobalLock) { @@ -309,8 +311,8 @@ class WindowTestsBase extends SystemServiceTestsBase { attrs.setTitle(name); final WindowState w = new WindowState(service, session, iWindow, token, parent, - OP_NONE, - 0, attrs, VISIBLE, ownerId, ownerCanAddInternalSystemWindow, + OP_NONE, 0, attrs, VISIBLE, ownerId, userId, + ownerCanAddInternalSystemWindow, powerManagerWrapper); // TODO: Probably better to make this call in the WindowState ctor to avoid errors with // adding it to the token... diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java index 76479cb95b09..535d53eeef71 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java @@ -29,6 +29,7 @@ import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.Mockito.mock; +import android.content.res.Configuration; import android.os.IBinder; import android.platform.test.annotations.Presubmit; @@ -134,6 +135,30 @@ public class WindowTokenTests extends WindowTestsBase { assertEquals(0, token.getWindowsCount()); } + @Test + public void testClearFixedRotationTransform() { + final WindowToken appToken = mAppWindow.mToken; + final WindowToken wallpaperToken = mWallpaperWindow.mToken; + final Configuration config = new Configuration(mDisplayContent.getConfiguration()); + final int originalRotation = config.windowConfiguration.getRotation(); + final int targetRotation = (originalRotation + 1) % 4; + + config.windowConfiguration.setRotation(targetRotation); + appToken.applyFixedRotationTransform(mDisplayInfo, mDisplayContent.mDisplayFrames, config); + wallpaperToken.linkFixedRotationTransform(appToken); + + // The window tokens should apply the rotation by the transformation. + assertEquals(targetRotation, appToken.getWindowConfiguration().getRotation()); + assertEquals(targetRotation, wallpaperToken.getWindowConfiguration().getRotation()); + + // The display doesn't rotate, the transformation will be canceled. + mAppWindow.mToken.clearFixedRotationTransform(null /* applyDisplayRotation */); + + // The window tokens should restore to the original rotation. + assertEquals(originalRotation, appToken.getWindowConfiguration().getRotation()); + assertEquals(originalRotation, wallpaperToken.getWindowConfiguration().getRotation()); + } + /** * Test that {@link WindowToken} constructor parameters is set with expectation. */ diff --git a/telecomm/java/android/telecom/Conference.java b/telecomm/java/android/telecom/Conference.java index bce06e4777a2..4e14fd3d59a1 100644 --- a/telecomm/java/android/telecom/Conference.java +++ b/telecomm/java/android/telecom/Conference.java @@ -1092,16 +1092,16 @@ public abstract class Conference extends Conferenceable { * This is applicable in two cases: * <ol> * <li>When {@link #setConferenceState(boolean)} is used to mark a conference as - * temporarily "not a conference"; we need to present the correct address in the in-call - * UI.</li> + * temporarily "not a conference"; we need to present the correct address presentation in + * the in-call UI.</li> * <li>When the conference is not hosted on the current device, we need to know the address - * information for the purpose of showing the original address to the user, as well as for - * logging to the call log.</li> + * presentation information for the purpose of showing the original address to the user, as + * well as for logging to the call log.</li> * </ol> - * @return The address of the conference, or {@code null} if not applicable. + * @return The address presentation of the conference. * @hide */ - public final int getAddressPresentation() { + public final @TelecomManager.Presentation int getAddressPresentation() { return mAddressPresentation; } diff --git a/telecomm/java/android/telecom/ConnectionService.java b/telecomm/java/android/telecom/ConnectionService.java index 0d66013d92a1..73296986d82e 100755 --- a/telecomm/java/android/telecom/ConnectionService.java +++ b/telecomm/java/android/telecom/ConnectionService.java @@ -1865,25 +1865,23 @@ public abstract class ConnectionService extends Service { mConferenceById.put(callId, conference); mIdByConference.put(conference, callId); conference.addListener(mConferenceListener); - ParcelableConference parcelableConference = new ParcelableConference( - request.getAccountHandle(), - conference.getState(), - conference.getConnectionCapabilities(), - conference.getConnectionProperties(), - Collections.<String>emptyList(), //connectionIds - conference.getVideoProvider() == null ? - null : conference.getVideoProvider().getInterface(), - conference.getVideoState(), - conference.getConnectTimeMillis(), - conference.getConnectionStartElapsedRealtimeMillis(), - conference.getStatusHints(), - conference.getExtras(), - conference.getAddress(), - conference.getAddressPresentation(), - conference.getCallerDisplayName(), - conference.getCallerDisplayNamePresentation(), - conference.getDisconnectCause(), - conference.isRingbackRequested()); + ParcelableConference parcelableConference = new ParcelableConference.Builder( + request.getAccountHandle(), conference.getState()) + .setConnectionCapabilities(conference.getConnectionCapabilities()) + .setConnectionProperties(conference.getConnectionProperties()) + .setVideoAttributes(conference.getVideoProvider() == null + ? null : conference.getVideoProvider().getInterface(), + conference.getVideoState()) + .setConnectTimeMillis(conference.getConnectTimeMillis(), + conference.getConnectionStartElapsedRealtimeMillis()) + .setStatusHints(conference.getStatusHints()) + .setExtras(conference.getExtras()) + .setAddress(conference.getAddress(), conference.getAddressPresentation()) + .setCallerDisplayName(conference.getCallerDisplayName(), + conference.getCallerDisplayNamePresentation()) + .setDisconnectCause(conference.getDisconnectCause()) + .setRingbackRequested(conference.isRingbackRequested()) + .build(); if (conference.getState() != Connection.STATE_DISCONNECTED) { conference.setTelecomCallId(callId); mAdapter.setVideoProvider(callId, conference.getVideoProvider()); @@ -2484,23 +2482,25 @@ public abstract class ConnectionService extends Service { } } conference.setTelecomCallId(id); - ParcelableConference parcelableConference = new ParcelableConference( - conference.getPhoneAccountHandle(), - conference.getState(), - conference.getConnectionCapabilities(), - conference.getConnectionProperties(), - connectionIds, - conference.getVideoProvider() == null ? - null : conference.getVideoProvider().getInterface(), - conference.getVideoState(), - conference.getConnectTimeMillis(), - conference.getConnectionStartElapsedRealtimeMillis(), - conference.getStatusHints(), - conference.getExtras(), - conference.getAddress(), - conference.getAddressPresentation(), - conference.getCallerDisplayName(), - conference.getCallerDisplayNamePresentation()); + ParcelableConference parcelableConference = new ParcelableConference.Builder( + conference.getPhoneAccountHandle(), conference.getState()) + .setConnectionCapabilities(conference.getConnectionCapabilities()) + .setConnectionProperties(conference.getConnectionProperties()) + .setConnectionIds(connectionIds) + .setVideoAttributes(conference.getVideoProvider() == null + ? null : conference.getVideoProvider().getInterface(), + conference.getVideoState()) + .setConnectTimeMillis(conference.getConnectTimeMillis(), + conference.getConnectionStartElapsedRealtimeMillis()) + .setStatusHints(conference.getStatusHints()) + .setExtras(conference.getExtras()) + .setAddress(conference.getAddress(), conference.getAddressPresentation()) + .setCallerDisplayName(conference.getCallerDisplayName(), + conference.getCallerDisplayNamePresentation()) + .setDisconnectCause(conference.getDisconnectCause()) + .setRingbackRequested(conference.isRingbackRequested()) + .setCallDirection(conference.getCallDirection()) + .build(); mAdapter.addConferenceCall(id, parcelableConference); mAdapter.setVideoProvider(id, conference.getVideoProvider()); diff --git a/telecomm/java/android/telecom/ParcelableConference.java b/telecomm/java/android/telecom/ParcelableConference.java index 90b69a338c7e..1f8aafbca476 100644 --- a/telecomm/java/android/telecom/ParcelableConference.java +++ b/telecomm/java/android/telecom/ParcelableConference.java @@ -22,6 +22,7 @@ import android.os.Parcel; import android.os.Parcelable; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import com.android.internal.telecom.IVideoProvider; @@ -32,25 +33,130 @@ import com.android.internal.telecom.IVideoProvider; */ public final class ParcelableConference implements Parcelable { - private PhoneAccountHandle mPhoneAccount; - private int mState; - private int mConnectionCapabilities; - private int mConnectionProperties; - private List<String> mConnectionIds; - private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + public static final class Builder { + private final PhoneAccountHandle mPhoneAccount; + private final int mState; + private int mConnectionCapabilities; + private int mConnectionProperties; + private List<String> mConnectionIds = Collections.emptyList(); + private long mConnectTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private IVideoProvider mVideoProvider; + private int mVideoState = VideoProfile.STATE_AUDIO_ONLY; + private StatusHints mStatusHints; + private Bundle mExtras; + private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private Uri mAddress; + private int mAddressPresentation = TelecomManager.PRESENTATION_UNKNOWN; + private String mCallerDisplayName; + private int mCallerDisplayNamePresentation = TelecomManager.PRESENTATION_UNKNOWN;; + private DisconnectCause mDisconnectCause; + private boolean mRingbackRequested; + private int mCallDirection = Call.Details.DIRECTION_UNKNOWN; + + public Builder( + PhoneAccountHandle phoneAccount, + int state) { + mPhoneAccount = phoneAccount; + mState = state; + } + + public Builder setDisconnectCause(DisconnectCause cause) { + mDisconnectCause = cause; + return this; + } + + public Builder setRingbackRequested(boolean requested) { + mRingbackRequested = requested; + return this; + } + + public Builder setCallerDisplayName(String callerDisplayName, + @TelecomManager.Presentation int callerDisplayNamePresentation) { + mCallerDisplayName = callerDisplayName; + mCallerDisplayNamePresentation = callerDisplayNamePresentation; + return this; + } + + public Builder setAddress(Uri address, + @TelecomManager.Presentation int addressPresentation) { + mAddress = address; + mAddressPresentation = addressPresentation; + return this; + } + + public Builder setExtras(Bundle extras) { + mExtras = extras; + return this; + } + + public Builder setStatusHints(StatusHints hints) { + mStatusHints = hints; + return this; + } + + public Builder setConnectTimeMillis(long connectTimeMillis, long connectElapsedTimeMillis) { + mConnectTimeMillis = connectTimeMillis; + mConnectElapsedTimeMillis = connectElapsedTimeMillis; + return this; + } + + public Builder setVideoAttributes(IVideoProvider provider, + @VideoProfile.VideoState int videoState) { + mVideoProvider = provider; + mVideoState = videoState; + return this; + } + + public Builder setConnectionIds(List<String> connectionIds) { + mConnectionIds = connectionIds; + return this; + } + + public Builder setConnectionProperties(int properties) { + mConnectionProperties = properties; + return this; + } + + public Builder setConnectionCapabilities(int capabilities) { + mConnectionCapabilities = capabilities; + return this; + } + + public Builder setCallDirection(int callDirection) { + mCallDirection = callDirection; + return this; + } + + public ParcelableConference build() { + return new ParcelableConference(mPhoneAccount, mState, mConnectionCapabilities, + mConnectionProperties, mConnectionIds, mVideoProvider, mVideoState, + mConnectTimeMillis, mConnectElapsedTimeMillis, mStatusHints, mExtras, mAddress, + mAddressPresentation, mCallerDisplayName, mCallerDisplayNamePresentation, + mDisconnectCause, mRingbackRequested, mCallDirection); + } + } + + + private final PhoneAccountHandle mPhoneAccount; + private final int mState; + private final int mConnectionCapabilities; + private final int mConnectionProperties; + private final List<String> mConnectionIds; + private final long mConnectTimeMillis; private final IVideoProvider mVideoProvider; private final int mVideoState; - private StatusHints mStatusHints; - private Bundle mExtras; - private long mConnectElapsedTimeMillis = Conference.CONNECT_TIME_NOT_SPECIFIED; + private final StatusHints mStatusHints; + private final Bundle mExtras; + private final long mConnectElapsedTimeMillis; private final Uri mAddress; private final int mAddressPresentation; private final String mCallerDisplayName; private final int mCallerDisplayNamePresentation; - private DisconnectCause mDisconnectCause; - private boolean mRingbackRequested; + private final DisconnectCause mDisconnectCause; + private final boolean mRingbackRequested; + private final int mCallDirection; - public ParcelableConference( + private ParcelableConference( PhoneAccountHandle phoneAccount, int state, int connectionCapabilities, @@ -67,31 +173,8 @@ public final class ParcelableConference implements Parcelable { String callerDisplayName, int callerDisplayNamePresentation, DisconnectCause disconnectCause, - boolean ringbackRequested) { - this(phoneAccount, state, connectionCapabilities, connectionProperties, connectionIds, - videoProvider, videoState, connectTimeMillis, connectElapsedTimeMillis, - statusHints, extras, address, addressPresentation, callerDisplayName, - callerDisplayNamePresentation); - mDisconnectCause = disconnectCause; - mRingbackRequested = ringbackRequested; - } - - public ParcelableConference( - PhoneAccountHandle phoneAccount, - int state, - int connectionCapabilities, - int connectionProperties, - List<String> connectionIds, - IVideoProvider videoProvider, - int videoState, - long connectTimeMillis, - long connectElapsedTimeMillis, - StatusHints statusHints, - Bundle extras, - Uri address, - int addressPresentation, - String callerDisplayName, - int callerDisplayNamePresentation) { + boolean ringbackRequested, + int callDirection) { mPhoneAccount = phoneAccount; mState = state; mConnectionCapabilities = connectionCapabilities; @@ -107,8 +190,9 @@ public final class ParcelableConference implements Parcelable { mAddressPresentation = addressPresentation; mCallerDisplayName = callerDisplayName; mCallerDisplayNamePresentation = callerDisplayNamePresentation; - mDisconnectCause = null; - mRingbackRequested = false; + mDisconnectCause = disconnectCause; + mRingbackRequested = ringbackRequested; + mCallDirection = callDirection; } @Override @@ -134,6 +218,8 @@ public final class ParcelableConference implements Parcelable { .append(mRingbackRequested) .append(", disconnectCause: ") .append(mDisconnectCause) + .append(", callDirection: ") + .append(mCallDirection) .toString(); } @@ -192,10 +278,15 @@ public final class ParcelableConference implements Parcelable { public boolean isRingbackRequested() { return mRingbackRequested; } + public int getHandlePresentation() { return mAddressPresentation; } + public int getCallDirection() { + return mCallDirection; + } + public static final @android.annotation.NonNull Parcelable.Creator<ParcelableConference> CREATOR = new Parcelable.Creator<ParcelableConference> () { @Override @@ -220,12 +311,13 @@ public final class ParcelableConference implements Parcelable { int callerDisplayNamePresentation = source.readInt(); DisconnectCause disconnectCause = source.readParcelable(classLoader); boolean isRingbackRequested = source.readInt() == 1; + int callDirection = source.readInt(); return new ParcelableConference(phoneAccount, state, capabilities, properties, connectionIds, videoCallProvider, videoState, connectTimeMillis, connectElapsedTimeMillis, statusHints, extras, address, addressPresentation, callerDisplayName, callerDisplayNamePresentation, disconnectCause, - isRingbackRequested); + isRingbackRequested, callDirection); } @Override @@ -261,5 +353,6 @@ public final class ParcelableConference implements Parcelable { destination.writeInt(mCallerDisplayNamePresentation); destination.writeParcelable(mDisconnectCause, 0); destination.writeInt(mRingbackRequested ? 1 : 0); + destination.writeInt(mCallDirection); } } diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java index 56f3c3ec0622..7f6e123ce69e 100755 --- a/telephony/java/android/telephony/CarrierConfigManager.java +++ b/telephony/java/android/telephony/CarrierConfigManager.java @@ -3074,6 +3074,28 @@ public class CarrierConfigManager { public static final String KEY_UNMETERED_NR_NSA_SUB6_BOOL = "unmetered_nr_nsa_sub6_bool"; /** + * Whether NR (standalone) should be unmetered for all frequencies. + * If either {@link #KEY_UNMETERED_NR_SA_MMWAVE_BOOL} or + * {@link #KEY_UNMETERED_NR_SA_SUB6_BOOL} are true, then this value will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_BOOL = "unmetered_nr_sa_bool"; + + /** + * Whether NR (standalone) frequencies above 6GHz (millimeter wave) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_SA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_MMWAVE_BOOL = "unmetered_nr_sa_mmwave_bool"; + + /** + * Whether NR (standalone) frequencies below 6GHz (sub6) should be unmetered. + * If this is true, then the value for {@link #KEY_UNMETERED_NR_SA_BOOL} will be ignored. + * @hide + */ + public static final String KEY_UNMETERED_NR_SA_SUB6_BOOL = "unmetered_nr_sa_sub6_bool"; + + /** * Support ASCII 7-BIT encoding for long SMS. This carrier config is used to enable * this feature. * @hide @@ -3625,6 +3647,17 @@ public class CarrierConfigManager { public static final String KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY = "missed_incoming_call_sms_originator_string_array"; + + /** + * String array of Apn Type configurations. + * The entries should be of form "APN_TYPE_NAME:priority". + * priority is an integer that is sorted from highest to lowest. + * example: cbs:5 + * + * @hide + */ + public static final String KEY_APN_PRIORITY_STRING_ARRAY = "apn_priority_string_array"; + /** * The patterns of missed incoming call sms. This is the regular expression used for * matching the missed incoming call's date, time, and caller id. The pattern should match @@ -4090,6 +4123,9 @@ public class CarrierConfigManager { sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_MMWAVE_BOOL, false); sDefaults.putBoolean(KEY_UNMETERED_NR_NSA_SUB6_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_MMWAVE_BOOL, false); + sDefaults.putBoolean(KEY_UNMETERED_NR_SA_SUB6_BOOL, false); sDefaults.putBoolean(KEY_ASCII_7_BIT_SUPPORT_FOR_LONG_MESSAGE_BOOL, false); sDefaults.putBoolean(KEY_SHOW_WIFI_CALLING_ICON_IN_STATUS_BAR_BOOL, false); /* Default value is minimum RSRP level needed for SIGNAL_STRENGTH_GOOD */ @@ -4154,6 +4190,10 @@ public class CarrierConfigManager { sDefaults.putLong(KEY_DATA_SWITCH_VALIDATION_MIN_GAP_LONG, TimeUnit.DAYS.toMillis(1)); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_ORIGINATOR_STRING_ARRAY, new String[0]); + sDefaults.putStringArray(KEY_APN_PRIORITY_STRING_ARRAY, new String[] { + "default:0", "mms:2", "supl:2", "dun:2", "hipri:3", "fota:2", + "ims:2", "cbs:2", "ia:2", "emergency:2", "mcx:3", "xcap:3" + }); sDefaults.putStringArray(KEY_MISSED_INCOMING_CALL_SMS_PATTERN_STRING_ARRAY, new String[0]); } diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java index 912a27f08f30..b864e37f9ed0 100644 --- a/tests/net/java/com/android/server/ConnectivityServiceTest.java +++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java @@ -4908,6 +4908,29 @@ public class ConnectivityServiceTest { } @Test + public void testDnsConfigurationTransTypesPushed() throws Exception { + // Clear any interactions that occur as a result of CS starting up. + reset(mMockDnsResolver); + + final NetworkRequest request = new NetworkRequest.Builder() + .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) + .build(); + final TestNetworkCallback callback = new TestNetworkCallback(); + mCm.registerNetworkCallback(request, callback); + + mWiFiNetworkAgent = new TestNetworkAgentWrapper(TRANSPORT_WIFI); + mWiFiNetworkAgent.connect(false); + callback.expectAvailableCallbacksUnvalidated(mWiFiNetworkAgent); + verify(mMockDnsResolver, times(1)).createNetworkCache( + eq(mWiFiNetworkAgent.getNetwork().netId)); + verify(mMockDnsResolver, times(2)).setResolverConfiguration( + mResolverParamsParcelCaptor.capture()); + final ResolverParamsParcel resolverParams = mResolverParamsParcelCaptor.getValue(); + assertContainsExactly(resolverParams.transportTypes, TRANSPORT_WIFI); + reset(mMockDnsResolver); + } + + @Test public void testPrivateDnsNotification() throws Exception { NetworkRequest request = new NetworkRequest.Builder() .clearCapabilities().addCapability(NET_CAPABILITY_INTERNET) diff --git a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java index 8fa0ab979a54..a392ae3f130a 100644 --- a/tests/net/java/com/android/server/connectivity/DnsManagerTest.java +++ b/tests/net/java/com/android/server/connectivity/DnsManagerTest.java @@ -18,22 +18,34 @@ package com.android.server.connectivity; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_OFF; import static android.net.ConnectivityManager.PRIVATE_DNS_MODE_PROVIDER_HOSTNAME; +import static android.net.NetworkCapabilities.TRANSPORT_VPN; +import static android.net.NetworkCapabilities.TRANSPORT_WIFI; import static android.provider.Settings.Global.PRIVATE_DNS_DEFAULT_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_MODE; import static android.provider.Settings.Global.PRIVATE_DNS_SPECIFIER; +import static com.android.testutils.MiscAssertsKt.assertContainsExactly; +import static com.android.testutils.MiscAssertsKt.assertContainsStringsExactly; +import static com.android.testutils.MiscAssertsKt.assertFieldCountEquals; + import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.annotation.NonNull; import android.content.Context; import android.net.IDnsResolver; import android.net.IpPrefix; import android.net.LinkAddress; import android.net.LinkProperties; import android.net.Network; +import android.net.ResolverOptionsParcel; +import android.net.ResolverParamsParcel; import android.net.RouteInfo; import android.net.shared.PrivateDnsConfig; import android.provider.Settings; @@ -47,6 +59,7 @@ import com.android.internal.util.test.FakeSettingsProvider; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -66,8 +79,11 @@ public class DnsManagerTest { static final int TEST_NETID = 100; static final int TEST_NETID_ALTERNATE = 101; static final int TEST_NETID_UNTRACKED = 102; - final boolean IS_DEFAULT = true; - final boolean NOT_DEFAULT = false; + static final int TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS = 1800; + static final int TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT = 25; + static final int TEST_DEFAULT_MIN_SAMPLES = 8; + static final int TEST_DEFAULT_MAX_SAMPLES = 64; + static final int[] TEST_TRANSPORT_TYPES = {TRANSPORT_WIFI, TRANSPORT_VPN}; DnsManager mDnsManager; MockContentResolver mContentResolver; @@ -76,6 +92,35 @@ public class DnsManagerTest { @Mock IDnsResolver mMockDnsResolver; @Mock MockableSystemProperties mSystemProperties; + private void assertResolverOptionsEquals( + @NonNull ResolverOptionsParcel actual, + @NonNull ResolverOptionsParcel expected) { + assertEquals(actual.hosts, expected.hosts); + assertEquals(actual.tcMode, expected.tcMode); + assertFieldCountEquals(2, ResolverOptionsParcel.class); + } + + private void assertResolverParamsEquals(@NonNull ResolverParamsParcel actual, + @NonNull ResolverParamsParcel expected) { + assertEquals(actual.netId, expected.netId); + assertEquals(actual.sampleValiditySeconds, expected.sampleValiditySeconds); + assertEquals(actual.successThreshold, expected.successThreshold); + assertEquals(actual.minSamples, expected.minSamples); + assertEquals(actual.maxSamples, expected.maxSamples); + assertEquals(actual.baseTimeoutMsec, expected.baseTimeoutMsec); + assertEquals(actual.retryCount, expected.retryCount); + assertContainsStringsExactly(actual.servers, expected.servers); + assertContainsStringsExactly(actual.domains, expected.domains); + assertEquals(actual.tlsName, expected.tlsName); + assertContainsStringsExactly(actual.tlsServers, expected.tlsServers); + assertContainsStringsExactly(actual.tlsFingerprints, expected.tlsFingerprints); + assertEquals(actual.caCertificate, expected.caCertificate); + assertEquals(actual.tlsConnectTimeoutMs, expected.tlsConnectTimeoutMs); + assertResolverOptionsEquals(actual.resolverOptions, expected.resolverOptions); + assertContainsExactly(actual.transportTypes, expected.transportTypes); + assertFieldCountEquals(16, ResolverParamsParcel.class); + } + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); @@ -103,8 +148,13 @@ public class DnsManagerTest { lp.addDnsServer(InetAddress.getByName("4.4.4.4")); // Send a validation event that is tracked on the alternate netId - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID_ALTERNATE, lp, NOT_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); + mDnsManager.updateTransportsForNetwork(TEST_NETID_ALTERNATE, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID_ALTERNATE, lp); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_ALTERNATE, InetAddress.parseNumericAddress("4.4.4.4"), "", true)); @@ -135,7 +185,10 @@ public class DnsManagerTest { InetAddress.parseNumericAddress("6.6.6.6"), InetAddress.parseNumericAddress("2001:db8:66:66::1") })); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); fixedLp = new LinkProperties(lp); mDnsManager.updatePrivateDnsStatus(TEST_NETID, fixedLp); assertTrue(fixedLp.isPrivateDnsActive()); @@ -168,7 +221,10 @@ public class DnsManagerTest { // be tracked. LinkProperties lp = new LinkProperties(); lp.addDnsServer(InetAddress.getByName("3.3.3.3")); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -179,7 +235,10 @@ public class DnsManagerTest { // Validation event has untracked netId mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID_UNTRACKED, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -225,7 +284,10 @@ public class DnsManagerTest { Settings.Global.putString(mContentResolver, PRIVATE_DNS_MODE, PRIVATE_DNS_MODE_OFF); mDnsManager.updatePrivateDns(new Network(TEST_NETID), mDnsManager.getPrivateDnsConfig()); - mDnsManager.setDnsConfigurationForNetwork(TEST_NETID, lp, IS_DEFAULT); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); mDnsManager.updatePrivateDnsValidation( new DnsManager.PrivateDnsValidationUpdate(TEST_NETID, InetAddress.parseNumericAddress("3.3.3.3"), "", true)); @@ -258,4 +320,38 @@ public class DnsManagerTest { assertEquals("strictmode.com", cfgStrict.hostname); assertEquals(new InetAddress[0], cfgStrict.ips); } + + @Test + public void testSendDnsConfiguration() throws Exception { + reset(mMockDnsResolver); + mDnsManager.updatePrivateDns(new Network(TEST_NETID), + mDnsManager.getPrivateDnsConfig()); + final LinkProperties lp = new LinkProperties(); + lp.setInterfaceName(TEST_IFACENAME); + lp.addDnsServer(InetAddress.getByName("3.3.3.3")); + lp.addDnsServer(InetAddress.getByName("4.4.4.4")); + mDnsManager.updateTransportsForNetwork(TEST_NETID, TEST_TRANSPORT_TYPES); + mDnsManager.noteDnsServersForNetwork(TEST_NETID, lp); + mDnsManager.setDefaultDnsSystemProperties(lp.getDnsServers()); + mDnsManager.flushVmDnsCache(); + + final ArgumentCaptor<ResolverParamsParcel> resolverParamsParcelCaptor = + ArgumentCaptor.forClass(ResolverParamsParcel.class); + verify(mMockDnsResolver, times(1)).setResolverConfiguration( + resolverParamsParcelCaptor.capture()); + final ResolverParamsParcel actualParams = resolverParamsParcelCaptor.getValue(); + final ResolverParamsParcel expectedParams = new ResolverParamsParcel(); + expectedParams.netId = TEST_NETID; + expectedParams.sampleValiditySeconds = TEST_DEFAULT_SAMPLE_VALIDITY_SECONDS; + expectedParams.successThreshold = TEST_DEFAULT_SUCCESS_THRESHOLD_PERCENT; + expectedParams.minSamples = TEST_DEFAULT_MIN_SAMPLES; + expectedParams.maxSamples = TEST_DEFAULT_MAX_SAMPLES; + expectedParams.servers = new String[]{"3.3.3.3", "4.4.4.4"}; + expectedParams.domains = new String[]{}; + expectedParams.tlsName = ""; + expectedParams.tlsServers = new String[]{"3.3.3.3", "4.4.4.4"}; + expectedParams.transportTypes = TEST_TRANSPORT_TYPES; + expectedParams.resolverOptions = new ResolverOptionsParcel(); + assertResolverParamsEquals(actualParams, expectedParams); + } } diff --git a/wifi/jarjar-rules.txt b/wifi/jarjar-rules.txt index f0333c98b8a7..f85231114f96 100644 --- a/wifi/jarjar-rules.txt +++ b/wifi/jarjar-rules.txt @@ -1,6 +1,13 @@ # used by wifi-service +# TODO (b/153596226): Find a solution for networkstack's AIDL parcelables & interfaces. +# Parcelable class names are serialized in the wire, so renaming them +# will result in the class not being found for any parcelable received/sent from the +# wifi-service jar. + +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). rule android.net.DhcpResultsParcelable* @0 rule android.net.DhcpResults* com.android.server.x.wifi.net.DhcpResults@1 +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). rule android.net.InterfaceConfigurationParcel* @0 rule android.net.InterfaceConfiguration* com.android.server.x.wifi.net.InterfaceConfiguration@1 rule android.net.IpMemoryStore* com.android.server.x.wifi.net.IpMemoryStore@1 @@ -12,6 +19,7 @@ rule android.net.ip.IpClientManager* com.android.server.x.wifi.net.ip.IpClientMa rule android.net.ip.IpClientUtil* com.android.server.x.wifi.net.ip.IpClientUtil@1 rule android.net.ipmemorystore.OnBlobRetrievedListener* com.android.server.x.wifi.net.ipmemorystore.OnBlobRetrievedListener@1 rule android.net.ipmemorystore.OnStatusListener* com.android.server.x.wifi.net.ipmemorystore.OnStatusListener@1 +# Note: This rule is needed to ensure the rule below does not rename a Parcelable (see TODO above). rule android.net.ipmemorystore.StatusParcelable* @0 rule android.net.ipmemorystore.Status* com.android.server.x.wifi.net.ipmemorystore.Status@1 rule android.net.networkstack.ModuleNetworkStackClient* com.android.server.x.wifi.net.networkstack.ModuleNetworkStackClient@1 @@ -62,7 +70,11 @@ rule com.android.internal.messages.SystemMessageProto* com.android.server.x.wifi # Use our statically linked PlatformProperties library rule android.sysprop.** com.android.server.x.wifi.sysprop.@1 # Use our statically linked HIDL stubs -rule android.hardware.** com.android.server.x.wifi.hardware.@1 +# Note: android.hardware.wifi.** is used by various wifi feature flags. This unfortunately is also the namespace +# used by vendor HAL stubs. So, this rule is intentionally weird to try and filter the vendor HAL stubs only. +rule android.hardware.wifi.V** com.android.server.x.wifi.hardware.wifi.V@1 +rule android.hardware.wifi.supplicant.** com.android.server.x.wifi.hardware.wifi.supplicant.@1 +rule android.hardware.wifi.hostapd.** com.android.server.x.wifi.hardware.wifi.hostapd.@1 rule android.hidl.** com.android.server.x.wifi.hidl.@1 # Use our statically linked ksoap2 rule org.ksoap2.** com.android.server.x.wifi.ksoap2.@1 diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java index b110a6139429..71f0ab8087ab 100644 --- a/wifi/java/android/net/wifi/WifiConfiguration.java +++ b/wifi/java/android/net/wifi/WifiConfiguration.java @@ -2973,4 +2973,15 @@ public class WifiConfiguration implements Parcelable { */ public boolean isMostRecentlyConnected = false; + /** + * Whether the key mgmt indicates if the WifiConfiguration needs a preSharedKey or not. + * @return true if preSharedKey is needed, false otherwise. + * @hide + */ + public boolean needsPreSharedKey() { + return allowedKeyManagement.get(KeyMgmt.WPA_PSK) + || allowedKeyManagement.get(KeyMgmt.SAE) + || allowedKeyManagement.get(KeyMgmt.WAPI_PSK); + } + } diff --git a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java index e210e4fec98e..a7b6765e886a 100644 --- a/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java +++ b/wifi/tests/src/android/net/wifi/WifiConfigurationTest.java @@ -16,9 +16,13 @@ package android.net.wifi; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_EAP_SUITE_B; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OPEN; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_OWE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_PSK; import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_SAE; +import static android.net.wifi.WifiConfiguration.SECURITY_TYPE_WAPI_PSK; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; @@ -507,4 +511,30 @@ public class WifiConfigurationTest { assertEquals(NetworkSelectionStatus.NETWORK_SELECTION_PERMANENTLY_DISABLED, status2.getNetworkSelectionStatus()); } + + @Test + public void testNeedsPreSharedKey() throws Exception { + WifiConfiguration configuration = new WifiConfiguration(); + + configuration.setSecurityParams(SECURITY_TYPE_PSK); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_SAE); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_WAPI_PSK); + assertTrue(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_OPEN); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_OWE); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP); + assertFalse(configuration.needsPreSharedKey()); + + configuration.setSecurityParams(SECURITY_TYPE_EAP_SUITE_B); + assertFalse(configuration.needsPreSharedKey()); + } } |