Merge "Do not unparcel bundle from application in LaunchActivityItem" into rvc-dev
diff --git a/StubLibraries.bp b/StubLibraries.bp
index 60f6174..f06f279 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -256,18 +256,16 @@
/////////////////////////////////////////////////////////////////////
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_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 5f418d4..67cd0d7 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -67,7 +67,7 @@
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 @@
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 e64edc3..dbfdcba 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 @@
// 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 c8ca44b..49b3ec1 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.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.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 @@
}
}
- void addCommitters(ArraySet<Committer> committers) {
+ void setCommitters(ArraySet<Committer> committers) {
synchronized (mMetadataLock) {
mCommitters.clear();
mCommitters.addAll(committers);
@@ -153,11 +156,16 @@
}
@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 @@
}
}
- void addLeasees(ArraySet<Leasee> leasees) {
+ void setLeasees(ArraySet<Leasee> leasees) {
synchronized (mMetadataLock) {
mLeasees.clear();
mLeasees.addAll(leasees);
@@ -380,8 +388,7 @@
}
// 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 @@
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 @@
}
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 @@
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 @@
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 @@
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 f2c1586..6af1178 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 @@
// 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 @@
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 @@
< 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 e472d05..35a2436 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.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 @@
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 fabce76..1d07e88 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.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 @@
? 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 d5b5949..80308d2 100644
--- a/apex/statsd/aidl/android/os/IStatsd.aidl
+++ b/apex/statsd/aidl/android/os/IStatsd.aidl
@@ -31,6 +31,11 @@
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 @@
*/
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 c1ba73f..dc477a5 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 @@
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 66e41cc..ce5309e 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 @@
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 @@
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 @@
mContext.unregisterReceiver(receiver);
}
statsdNotReadyLocked();
+ mSentBootComplete = false;
}
}
}
@@ -758,6 +784,28 @@
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 58c78da..90764b0 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 @@
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 26ccf03..9e0fb84 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 e55ea6c..75fc7f7 100644
--- a/cmds/idmap2/idmap2d/Idmap2Service.cpp
+++ b/cmds/idmap2/idmap2d/Idmap2Service.cpp
@@ -149,15 +149,21 @@
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 65061d0..b357904 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -301,6 +301,8 @@
"-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 @@
include_dirs: ["external/protobuf/src"],
},
- shared_libs: [
- "libprotobuf-cpp-lite",
- ],
-
}
//#############################
diff --git a/cmds/statsd/AndroidTest.xml b/cmds/statsd/AndroidTest.xml
deleted file mode 100644
index afe30a2..0000000
--- a/cmds/statsd/AndroidTest.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
-
- Licensed under the Apache License, Version 2.0 (the "License");
- you may not use this file except in compliance with the License.
- You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing, software
- distributed under the License is distributed on an "AS IS" BASIS,
- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- See the License for the specific language governing permissions and
- limitations under the License.
--->
-<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
diff --git a/cmds/statsd/TEST_MAPPING b/cmds/statsd/TEST_MAPPING
new file mode 100644
index 0000000..8dee073
--- /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 9169eb17..dd1d400 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -1054,6 +1054,14 @@
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 @@
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 114c84f..23d4c1b 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -64,6 +64,7 @@
virtual Status systemRunning();
virtual Status statsCompanionReady();
+ virtual Status bootCompleted();
virtual Status informAnomalyAlarmFired();
virtual Status informPollAlarmFired();
virtual Status informAlarmForSubscriberTriggeringFired();
@@ -165,6 +166,11 @@
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 ed98f50..f4247ec 100644
--- a/cmds/statsd/src/stats_log.proto
+++ b/cmds/statsd/src/stats_log.proto
@@ -181,12 +181,15 @@
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 9e7b7c8..d29394b 100644
--- a/cmds/statsd/tests/StatsLogProcessor_test.cpp
+++ b/cmds/statsd/tests/StatsLogProcessor_test.cpp
@@ -1564,7 +1564,7 @@
// 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 86f786e..cc38c4a 100644
--- a/cmds/statsd/tests/StatsService_test.cpp
+++ b/cmds/statsd/tests/StatsService_test.cpp
@@ -65,7 +65,6 @@
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 @@
EXPECT_TRUE(service->getUidFromArgs(args, 2, uid));
EXPECT_EQ(1, uid);
- // "999999999999999999"
+ // "a1"
EXPECT_FALSE(service->getUidFromArgs(args, 3, uid));
- // "a1"
- EXPECT_FALSE(service->getUidFromArgs(args, 4, 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 69326cb..a5da9c8 100644
--- a/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/CountMetric_e2e_test.cpp
@@ -141,36 +141,38 @@
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);
- 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(1, data.bucket_info(0).count());
- EXPECT_EQ(1, data.bucket_info(1).count());
-
- data = reports.reports(0).metrics(0).count_metrics().data(1);
+ 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_UNKNOWN,
data.slice_by_state(0).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(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_OFF, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(2, data.bucket_info(1).count());
+
+ 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_ON, data.slice_by_state(0).value());
+ ASSERT_EQ(2, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+ EXPECT_EQ(1, data.bucket_info(1).count());
}
/**
@@ -191,7 +193,9 @@
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 @@
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 @@
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(2, data.bucket_info_size());
- EXPECT_EQ(4, data.bucket_info(0).count());
- EXPECT_EQ(2, data.bucket_info(1).count());
-
- data = reports.reports(0).metrics(0).count_metrics().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(screenOnId, 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());
+
+ 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(screenOffId, 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());
}
/**
@@ -499,50 +505,52 @@
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);
- 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, data.bucket_info(0).count());
-
- data = reports.reports(0).metrics(0).count_metrics().data(1);
+ 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(-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(1, data.bucket_info(0).count());
- data = reports.reports(0).metrics(0).count_metrics().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());
-
- data = reports.reports(0).metrics(0).count_metrics().data(3);
+ 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(android::app::PROCESS_STATE_TOP, data.slice_by_state(0).value());
- EXPECT_EQ(1, data.bucket_info_size());
+ 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(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_FOREGROUND_SERVICE, data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ ASSERT_EQ(2, data.bucket_info_size());
EXPECT_EQ(1, data.bucket_info(0).count());
EXPECT_EQ(2, data.bucket_info(1).count());
+
+ 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_IMPORTANT_FOREGROUND, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(2, data.bucket_info(0).count());
+
+ 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_IMPORTANT_BACKGROUND, data.slice_by_state(0).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
}
TEST(CountMetricE2eTest, TestMultipleSlicedStates) {
@@ -554,7 +562,9 @@
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,22 +735,13 @@
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);
- 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(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(1, data.bucket_info(0).count());
-
- data = reports.reports(0).metrics(0).count_metrics().data(1);
+ 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_value());
@@ -748,53 +749,64 @@
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(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_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());
-
- data = reports.reports(0).metrics(0).count_metrics().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(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(4);
+ 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_ON"), 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_BACKGROUND, 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(5);
+ 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_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());
+ ASSERT_EQ(1, data.bucket_info_size());
EXPECT_EQ(2, data.bucket_info(0).count());
+
+ 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(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_FOREGROUND_SERVICE, data.slice_by_state(1).value());
+ ASSERT_EQ(1, data.bucket_info_size());
+ EXPECT_EQ(1, data.bucket_info(0).count());
+
+ 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(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());
+ 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 2659944..ba09a35 100644
--- a/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/DurationMetric_e2e_test.cpp
@@ -98,8 +98,9 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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,47 +1337,25 @@
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);
- 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(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());
- 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(2);
- 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(-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(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(1);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid1,
"wakelock1");
EXPECT_EQ(1, data.slice_by_state_size());
@@ -1362,7 +1363,7 @@
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());
+ 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());
@@ -1370,7 +1371,45 @@
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(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(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 = durationMetrics.data(3);
+ 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(android::app::ProcessStateEnum::PROCESS_STATE_IMPORTANT_BACKGROUND,
+ data.slice_by_state(0).value());
+ 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());
+
+ 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(-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 = durationMetrics.data(5);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock1");
EXPECT_EQ(1, data.slice_by_state_size());
@@ -1378,12 +1417,24 @@
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(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());
- data = reports.reports(0).metrics(0).duration_metrics().data(5);
+ 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());
+ 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 = durationMetrics.data(7);
ValidateWakelockAttributionUidAndTagDimension(data.dimensions_in_what(), 10, appUid2,
"wakelock2");
EXPECT_EQ(1, data.slice_by_state_size());
@@ -1391,7 +1442,7 @@
EXPECT_TRUE(data.slice_by_state(0).has_value());
EXPECT_EQ(android::app::ProcessStateEnum::PROCESS_STATE_FOREGROUND_SERVICE,
data.slice_by_state(0).value());
- EXPECT_EQ(2, data.bucket_info_size());
+ 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());
@@ -1399,32 +1450,7 @@
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);
- 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());
- 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");
- 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(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(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 @@
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 f1e2744..ba8d283 100644
--- a/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
+++ b/cmds/statsd/tests/e2e/MetricActivation_e2e_test.cpp
@@ -391,7 +391,6 @@
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 @@
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 @@
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 @@
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 @@
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 009e49a5..3b4d646 100644
--- a/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
+++ b/cmds/statsd/tests/metrics/ValueMetricProducer_test.cpp
@@ -3726,7 +3726,8 @@
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 ed3cf5b..687014f 100644
--- a/cmds/statsd/tests/statsd_test_util.cpp
+++ b/cmds/statsd/tests/statsd_test_util.cpp
@@ -324,40 +324,29 @@
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 @@
return group;
}
-StateMap CreateScreenStateOnOffMap() {
+StateMap CreateScreenStateOnOffMap(int64_t screenOnId, int64_t screenOffId) {
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 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 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 @@
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 d6ea77eb..37b9889 100644
--- a/cmds/statsd/tests/statsd_test_util.h
+++ b/cmds/statsd/tests/statsd_test_util.h
@@ -138,27 +138,16 @@
// 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 @@
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 @@
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 d00366b..47ccc2f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -344,7 +344,7 @@
ApkAssets apkAssets = null;
if (mLoadedApkAssets != null) {
apkAssets = mLoadedApkAssets.get(newKey);
- if (apkAssets != null) {
+ if (apkAssets != null && apkAssets.isUpToDate()) {
return apkAssets;
}
}
@@ -353,7 +353,7 @@
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 @@
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 c94d428..6bd8b1d 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.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 @@
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 6f59c5f..ebb534a 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 @@
"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 e9bcefe..31d7d082 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -812,7 +812,7 @@
* 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 2041cfb..c87b827 100644
--- a/core/java/android/net/VpnManager.java
+++ b/core/java/android/net/VpnManager.java
@@ -75,7 +75,7 @@
}
/**
- * 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 2dbaea8..25cb040 100644
--- a/core/java/android/os/incremental/IIncrementalService.aidl
+++ b/core/java/android/os/incremental/IIncrementalService.aidl
@@ -109,4 +109,9 @@
* 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 7092751..70ebbaa 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -480,4 +480,18 @@
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 c047dc0..60373ac 100644
--- a/core/java/android/service/dataloader/DataLoaderService.java
+++ b/core/java/android/service/dataloader/DataLoaderService.java
@@ -34,6 +34,8 @@
import android.util.ExceptionUtils;
import android.util.Slog;
+import libcore.io.IoUtils;
+
import java.io.IOException;
import java.util.Collection;
@@ -115,22 +117,10 @@
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 071c259..b6ce9f5 100644
--- a/core/java/android/view/IPinnedStackListener.aidl
+++ b/core/java/android/view/IPinnedStackListener.aidl
@@ -37,13 +37,9 @@
/**
* 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 81bfcb0..a0527b7 100644
--- a/core/java/android/view/IWindowSession.aidl
+++ b/core/java/android/view/IWindowSession.aidl
@@ -48,6 +48,11 @@
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 dab1108..ed1edc3 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -111,6 +111,7 @@
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 @@
* 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 @@
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 @@
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 ab968d7..fba6a55 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -144,6 +144,7 @@
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 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 @@
// 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 316a5f2..2975d5e 100644
--- a/core/java/android/view/WindowManagerImpl.java
+++ b/core/java/android/view/WindowManagerImpl.java
@@ -104,7 +104,8 @@
@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 39ed401..ec51301 100644
--- a/core/java/android/view/WindowlessWindowManager.java
+++ b/core/java/android/view/WindowlessWindowManager.java
@@ -130,6 +130,20 @@
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 482d5b25..71dd665 100644
--- a/core/java/android/view/inputmethod/InputMethodManager.java
+++ b/core/java/android/view/inputmethod/InputMethodManager.java
@@ -1968,6 +1968,38 @@
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 04bf915..02cf25a 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_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.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 @@
}
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 1c978bf..32a79f3 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 37fd965..cafa7e8 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 4715823..1ed36a8 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 c0e070b..dae9867 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 ec69606..462ca3a 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 0636ea9..8454589 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 133df6c..9d3ca53 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 468b825..ff0838d 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 a8cc986..4090e21 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 a6aa753..bd05452 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 b3cb436..a0e404a 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 36adc52..f56b8b5 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 6d8a2b4..6e9098b 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 3de322e..bfb7b4d 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 57b02f4..5fdbe9e 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 366d19d..cf58937 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 197a47c..b57b692 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 2e9ea38..070fd79f 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 9af4b68..c5922e1 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 b62d8b0..315f7ea 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 84c1c18..6198d0e 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 1de01a3..3708d3a 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 1f6e4d7..7f621ca 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 29a9847..fa88ebc 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 cd6eec1..ca9ad67 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 94ff54c..4dab599 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 30a75dc..a2eac83 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 21aa148..8ca3176 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 6f2deee..c45f349 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 39e5a6e..704b233 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 4b13124..5c0ab14 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 f31f1c8..1e5f5ec 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 b5892eb..a417eab 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 7de5a8b..50cea44 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 8d4b30a..bbe9201 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 73a769b..a5c8832 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 69d886f..5ea4383 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 2e331a0..b22fa0e 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 021717d..1b2d0b5 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 6ea61a1..9cb4bd6 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 9c434db..3807da8 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 ad0cde1..e54cf72 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 462d3a5..4fcbe76 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 5dc7433..feba806 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 752a9c7..1a69a73 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 e94e553..c93ca0f 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 e41127b..7858064 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 6693823..2ad119f 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 2fb675c..9017203 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 b5757c6..e28ed6f 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 760b08b..9a3ae250 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 aa48ea6f..b2c7606 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 3400cb1..303a28f 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 6ad26b5..f07f23511 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 3400cb1..303a28f 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 3dbc019..1db0917 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 7f4f005..3a96385 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 a2e556d..a131b18 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 8039c1a..aec983c 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 2d742ef..5aa0e02 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 460287d..5e7351a 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 d72c209..995e949 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 9b7318b..54eec00 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 f6a831a..7e9a1ea 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 43eca0e..7135240 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 f9e95a6..e0990a2 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 041423d..83f7a1b 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 0b1ee65..773020b 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 5861589..69f41dd 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 0cb185c..c9d29a2 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 e717898..216f624 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 d2dde71..a1c9faa7 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 cbe131f..7e24e64 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 5f921bc..18eb7d9 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 d85b271..e6d5395 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 88301a9..59b5cdc 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 8d51a60..1e16ee0 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -72,6 +72,7 @@
":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 ed9d3f5..04952bd 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 94d85e6..4dd4d1c 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.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 @@
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 4bfffd7..a9f251e 100644
--- a/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
+++ b/core/tests/coretests/src/android/widget/EditorCursorDragTest.java
@@ -69,7 +69,6 @@
@RunWith(AndroidJUnit4.class)
@MediumTest
-@Presubmit
public class EditorCursorDragTest {
private static final String LOG_TAG = EditorCursorDragTest.class.getSimpleName();
@@ -97,6 +96,7 @@
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 a2fcef5..2b38cca 100644
--- a/core/tests/overlaytests/host/Android.bp
+++ b/core/tests/overlaytests/host/Android.bp
@@ -16,7 +16,7 @@
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 eec7be2..d898d22 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 @@
}
@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 @@
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 cc7704b..f3c0abd 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 @@
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 @@
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 @@
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 f8607f4..878f05d 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_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 @@
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 @@
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 @@
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 @@
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
similarity index 84%
rename from core/tests/overlaytests/remount/host/Android.bp
rename to core/tests/overlaytests/remount/Android.bp
index 3825c55..5757cfe 100644
--- a/core/tests/overlaytests/remount/host/Android.bp
+++ b/core/tests/overlaytests/remount/Android.bp
@@ -21,8 +21,12 @@
],
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
similarity index 100%
rename from core/tests/overlaytests/remount/host/AndroidTest.xml
rename to 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 0000000..3fa8bcd
--- /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 0000000..14b5bf6
--- /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
similarity index 60%
rename from core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
rename to core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/OverlaySharedLibraryTest.java
index 06b2ac8..7f2c060 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 @@
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 @@
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 @@
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 @@
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 @@
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 0000000..70e3423
--- /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
similarity index 75%
rename from core/tests/overlaytests/remount/host/src/com/android/overlaytest/remounted/SystemPreparer.java
rename to core/tests/overlaytests/remount/src/com/android/overlaytest/remounted/SystemPreparer.java
index 8696091..bb72d0e 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 @@
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.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 @@
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 @@
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 @@
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 @@
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
similarity index 73%
rename from core/tests/overlaytests/remount/target/Android.bp
rename to core/tests/overlaytests/remount/test-apps/Overlay/Android.bp
index 83f9f28..a1fdbfd 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/target/AndroidManifest.xml b/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml
similarity index 66%
copy from core/tests/overlaytests/remount/target/AndroidManifest.xml
copy to core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml
index dc07dca..d6d706c 100644
--- a/core/tests/overlaytests/remount/target/AndroidManifest.xml
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -16,11 +16,8 @@
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
- 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" />
- </application>
-</manifest>
+ 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/target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
similarity index 70%
copy from core/tests/overlaytests/remount/target/res/values/values.xml
copy to core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
index b5f444a..675e44f 100644
--- a/core/tests/overlaytests/remount/target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Overlay/res/values/values.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,6 +15,6 @@
~ limitations under the License.
-->
-<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>
+<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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibrary/Android.bp
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibrary/AndroidManifest.xml
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/overlayable.xml
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/public.xml
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibrary/res/values/values.xml
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/Android.bp
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/AndroidManifest.xml
rename to 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
similarity index 100%
rename from core/tests/overlaytests/remount/host/test-apps/SharedLibraryOverlay/res/values/values.xml
rename to core/tests/overlaytests/remount/test-apps/SharedLibraryOverlay/res/values/values.xml
diff --git a/core/tests/overlaytests/remount/target/Android.bp b/core/tests/overlaytests/remount/test-apps/Target/Android.bp
similarity index 72%
copy from core/tests/overlaytests/remount/target/Android.bp
copy to core/tests/overlaytests/remount/test-apps/Target/Android.bp
index 83f9f28..19947b1 100644
--- a/core/tests/overlaytests/remount/target/Android.bp
+++ b/core/tests/overlaytests/remount/test-apps/Target/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.
@@ -14,7 +14,15 @@
android_test_helper_app {
name: "OverlayRemountedTest_Target",
- srcs: ["src/**/*.java"],
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
similarity index 89%
rename from core/tests/overlaytests/remount/target/AndroidManifest.xml
rename to core/tests/overlaytests/remount/test-apps/Target/AndroidManifest.xml
index dc07dca..d1c7b7e8 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/target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
similarity index 70%
copy from core/tests/overlaytests/remount/target/res/values/values.xml
copy to core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
index b5f444a..4aa5bce 100644
--- a/core/tests/overlaytests/remount/target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res/values/overlayable.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,6 +15,10 @@
~ limitations under the License.
-->
-<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>
+<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
similarity index 72%
rename from core/tests/overlaytests/remount/target/res/values/values.xml
rename to core/tests/overlaytests/remount/test-apps/Target/res/values/values.xml
index b5f444a..76253a9 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/target/res/values/values.xml b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml
similarity index 70%
copy from core/tests/overlaytests/remount/target/res/values/values.xml
copy to core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml
index b5f444a..4aa5bce 100644
--- a/core/tests/overlaytests/remount/target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/overlayable.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,6 +15,10 @@
~ limitations under the License.
-->
-<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>
+<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_upgrade/values/values.xml
similarity index 60%
copy from core/tests/overlaytests/remount/target/res/values/values.xml
copy to core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml
index b5f444a..f552cb0 100644
--- a/core/tests/overlaytests/remount/target/res/values/values.xml
+++ b/core/tests/overlaytests/remount/test-apps/Target/res_upgrade/values/values.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -14,7 +14,10 @@
~ See the License for the specific language governing permissions and
~ limitations under the License.
-->
-
-<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>
-</resources>
+<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 0000000..e6ebd5e
--- /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 0000000..9a5102f
--- /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 0000000..07f27ee
--- /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 0000000..ac5f846
--- /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 63a6b40..18086ec 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 918e7af..05f4d6b 100644
--- a/libs/androidfw/ApkAssets.cpp
+++ b/libs/androidfw/ApkAssets.cpp
@@ -385,7 +385,7 @@
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 @@
// 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 0b2fd9e..eb6ee95 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 @@
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 @@
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 @@
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 @@
// 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 ccb57f3..ecc1ce6 100644
--- a/libs/androidfw/include/androidfw/Idmap.h
+++ b/libs/androidfw/include/androidfw/Idmap.h
@@ -142,7 +142,13 @@
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 @@
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 @@
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 41ba637..7aa0dbb 100644
--- a/libs/androidfw/tests/Idmap_test.cpp
+++ b/libs/androidfw/tests/Idmap_test.cpp
@@ -38,7 +38,7 @@
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 @@
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, 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 @@
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 48aed34..861eeea 100644
--- a/media/java/android/media/tv/tuner/Tuner.java
+++ b/media/java/android/media/tv/tuner/Tuner.java
@@ -394,7 +394,7 @@
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 @@
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 fc9b91c..a31f177 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -676,8 +676,6 @@
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 @@
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 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 ac7fe5d..7579ca5 100644
--- a/media/jni/android_media_tv_Tuner.cpp
+++ b/media/jni/android_media_tv_Tuner.cpp
@@ -880,10 +880,12 @@
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 @@
(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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 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 @@
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 @@
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 @@
(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 73fc38d..6749ba0 100644
--- a/media/jni/android_media_tv_Tuner.h
+++ b/media/jni/android_media_tv_Tuner.h
@@ -188,9 +188,9 @@
jobject openDvr(DvrType type, jlong bufferSize);
jobject getDemuxCaps();
jobject getFrontendStatus(jintArray types);
+ Result openDemux();
protected:
- Result openDemux();
virtual ~JTuner();
private:
@@ -204,15 +204,15 @@
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 062f7bd..d105e44 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 0000000..3e35df9
--- /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 6ecab51..534c51e 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 067e359..3542323 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 0b56d05..bf1bf38 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 c275536..4ea48ba 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -24,6 +24,7 @@
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 @@
@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 0000000..707ee4f
--- /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 0000000..db0f5d8
--- /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 50e43be..149531f 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 @@
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;
+ CarKeyguardViewController carKeyguardViewController,
+ FullScreenUserSwitcherViewController fullScreenUserSwitcherViewController) {
- mIsUserSwitcherEnabled = resources.getBoolean(R.bool.config_enableFullscreenUserSwitcher);
-
- 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 @@
});
}
- 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 @@
/**
* 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) {
+ if (record.mType != UserGridRecyclerView.UserRecord.FOREGROUND_USER) {
+ mCarKeyguardViewController.hideKeyguardToPrepareBouncer();
+ }
+
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 (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);
- }
}
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 dd29f8d..6b4f3e3 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 @@
*/
@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 @@
@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 4ae6ea6..a492e47 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 199476f..bf4c8c3 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 c6dc263..0e028b0 100644
--- a/packages/PrintSpooler/tests/outofprocess/Android.bp
+++ b/packages/PrintSpooler/tests/outofprocess/Android.bp
@@ -27,4 +27,5 @@
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 b649e82..922d735 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 61c2f54..132545b 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.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 @@
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 ff40d8e..450bdb1 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 @@
}
/**
+ * 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 @@
// 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 9d7e2c8..b1234f2 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 @@
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 @@
* 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());
+ final TelephonyManager telephonyManager = context.getSystemService(TelephonyManager.class);
+ final int mobileDefaultSubId = telephonyManager.getSubscriptionId();
- if (!subscriptionManager.isActiveSubscriptionId(subId)) {
- Log.i(TAG, "Subscription is not active: " + subId);
- return mobileAll;
+ 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 c6f0327..133d375b 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 0000000..0d5efeb
--- /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 0000000..01f8d2d
--- /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/packages/SystemUI/res/drawable/rounded_bg_top.xml b/packages/SystemUI/res/drawable/rounded_bg_top.xml
new file mode 100644
index 0000000..988ab58
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_bg_top.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2020 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+ android:shape="rectangle">
+ <solid android:color="?android:attr/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 bfa252c..8342a2a 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 db81e23..55c9083 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 f2de45a..34b603f 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 0000000..90b3398
--- /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 9d5eb63..ae57563 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 42d73f3..94df9d8 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/core/tests/overlaytests/remount/target/res/values/values.xml b/packages/SystemUI/res/layout/controls_management_editing.xml
similarity index 60%
copy from core/tests/overlaytests/remount/target/res/values/values.xml
copy to packages/SystemUI/res/layout/controls_management_editing.xml
index b5f444a..8a14ec3 100644
--- a/core/tests/overlaytests/remount/target/res/values/values.xml
+++ b/packages/SystemUI/res/layout/controls_management_editing.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
- ~ Copyright (C) 2019 The Android Open Source Project
+ ~ Copyright (C) 2020 The Android Open Source Project
~
~ Licensed under the Apache License, Version 2.0 (the "License");
~ you may not use this file except in compliance with the License.
@@ -15,6 +15,13 @@
~ limitations under the License.
-->
-<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>
-</resources>
+<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 87cb5c7f..9dc502e 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 dc94697..5399f57 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 73b711d..5b36382 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 6a8a4b9..2a4d5ef 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 566d143..7c0b605 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 3e02b30..118aa5b 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 34a0268..4794847 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 @@
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 @@
}
@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 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 1e1ce4e..5c3d17c 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.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.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 2f10394..03ccc1c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardViewController.java
@@ -147,6 +147,28 @@
*/
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 61e6f39..71dbbbc 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 @@
if (show
&& mShouldShowManageEducation
&& mManageEducationView.getVisibility() != VISIBLE
- && mIsExpanded) {
+ && mIsExpanded
+ && mExpandedBubble.getExpandedView() != null) {
mManageEducationView.setAlpha(0);
mManageEducationView.setVisibility(VISIBLE);
mManageEducationView.post(() -> {
@@ -1909,7 +1910,8 @@
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 @@
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 @@
}
private void updatePointerPosition() {
- if (mExpandedBubble == null) {
+ if (mExpandedBubble == null || mExpandedBubble.getExpandedView() == null) {
return;
}
int index = getBubbleIndex(mExpandedBubble);
@@ -2049,7 +2051,7 @@
* 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 dec6007..5891a7f 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 @@
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 6e59ac1..40606c2 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 @@
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 @@
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 568fb28..7cab847 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 @@
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 8805694..6d34009 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 @@
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 946a236..3bed559 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.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 @@
@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 11181e5..175ed06 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 @@
* @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 @@
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 @@
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 1291dd9..607934c 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 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 @@
/**
* 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 @@
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 @@
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 @@
}
}
+ 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 @@
* 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 @@
}
/**
- * 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 @@
}
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 0000000..ee1ce7a
--- /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 fe1e632..6f34dee 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 @@
// 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 @@
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 @@
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 @@
}
}
+ 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 @@
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 a995a2e..37b6d15 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 @@
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 @@
* 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 @@
* [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 0c41f7e..3be5900 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 @@
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 5c51e3d..0000000
--- 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 0000000..411170cb
--- /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 680d006..ad86eeb 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 @@
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 b1cb04e..0eb6cb1 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 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 @@
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 @@
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 @@
})
}
- 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 @@
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 @@
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 7da3d70..fab6fc7 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.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.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 @@
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,16 +210,30 @@
}
private fun startFavoritingActivity(context: Context, si: StructureInfo) {
- val i = Intent(context, ControlsFavoritingActivity::class.java).apply {
- putExtra(ControlsFavoritingActivity.EXTRA_APP,
- controlsListingController.get().getAppLabel(si.componentName))
- putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure)
- putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName)
+ 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))
+ putExtra(ControlsFavoritingActivity.EXTRA_STRUCTURE, si.structure)
+ putExtra(Intent.EXTRA_COMPONENT_NAME, si.componentName)
+ }
+ }
+
private fun startProviderSelectorActivity(context: Context) {
val i = Intent(context, ControlsProviderSelectorActivity::class.java).apply {
addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP or Intent.FLAG_ACTIVITY_NEW_TASK)
@@ -253,6 +267,7 @@
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 @@
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 @@
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 @@
baseLayout,
controlsController.get(),
uiExecutor,
- bgExecutor
+ bgExecutor,
+ usePanels
)
val key = ControlKey(selectedStructure.componentName, it.controlId)
cvh.bindData(controlsById.getValue(key))
@@ -500,6 +521,7 @@
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 d3d4287..15c41a2 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 @@
* 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 @@
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 @@
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 15c1dab..6340db1 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 @@
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 d64a5f0..b02c9c8 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.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 @@
*/
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 @@
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 a4a5894..3f095dc 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 @@
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 @@
}
}
- 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 @@
@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 @@
}
}
+ @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 @@
}
}
- 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 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 @@
@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 @@
}
}
- 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 @@
// 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 @@
} catch (RemoteException e) {
}
}
- }, 500);
+ }, mDialogPressDelay);
}
@Override
@@ -815,6 +848,7 @@
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 @@
}
}
+ @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 @@
} catch (RemoteException re) {
Log.e(TAG, "Couldn't logout user " + re);
}
- }, 500);
+ }, mDialogPressDelay);
}
}
@@ -1599,6 +1638,11 @@
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 9873d24..62efd8c 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.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 @@
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 @@
private int mForegroundColor;
private int mBackgroundColor;
protected ComponentName mRecvComponent;
+ private MediaDevice mDevice;
private boolean mIsRegistered = false;
private final int[] mActionIds;
@@ -121,19 +125,44 @@
}
};
+ 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 @@
// mStateListener to be unregistered in detach.
mMediaNotifView.addOnAttachStateChangeListener(mStateListener);
mMediaManager = manager;
+ mLocalMediaManager = routeManager;
mActionIds = actionIds;
mForegroundExecutor = foregroundExecutor;
mBackgroundExecutor = backgroundExecutor;
@@ -176,7 +206,7 @@
* @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 @@
// 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 @@
* 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 @@
Assert.isMainThread();
if (!mIsRegistered) {
mMediaManager.addCallback(mMediaListener);
+ if (mLocalMediaManager != null) {
+ mLocalMediaManager.registerCallback(mDeviceCallback);
+ mLocalMediaManager.startScan();
+ }
mIsRegistered = true;
}
}
@@ -463,6 +497,10 @@
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 cf8f268..dd83e42 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 @@
/** 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 @@
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 @@
@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 d2994ae..a95d6b7 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 @@
/**
* 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 @@
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 918c45b..a2667d9 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 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 @@
}
@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 @@
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 1e9daab..ddba9ea 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 @@
}
// 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 @@
// 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 99a01d3..3a2d786 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 @@
}
@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 @@
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 @@
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 339a408..e636707 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.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 @@
* @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 @@
* @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 c8412ff..0566b2e 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.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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 0c50194..0ba4cb1 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 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 @@
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 c8b34f1..4e6df0a 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 @@
// 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 fb88ea5..8c9bb6c 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 fa55b74..900b3ea 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 @@
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 @@
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 45719c7..03021c2 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 @@
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 a94af24..1c7a9b5 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 @@
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 0266a84..7a31fa5 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 @@
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 8630570..f6ee46b 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 @@
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 @@
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 5e0d28f..236384b 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.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 @@
@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 @@
it in favoritesIndices
)
}
- model = AllModel(controls, favoritesList, EMPTY_STRING)
+ model = AllModel(controls, favoritesList, EMPTY_STRING, controlsModelCallback)
}
@Test
@@ -93,28 +97,28 @@
// 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 @@
@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 @@
model.favorites.zip(expectedFavorites).forEach {
assertTrue(sameControl(it.first, it.second))
}
+
+ verify(controlsModelCallback).onFirstChange()
}
@Test
@@ -163,10 +170,12 @@
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 @@
model.favorites.zip(expectedFavorites).forEach {
assertTrue(sameControl(it.first, it.second))
}
+
+ verify(controlsModelCallback, never()).onFirstChange()
}
@Test
@@ -194,6 +205,8 @@
model.favorites.zip(expectedFavorites).forEach {
assertTrue(sameControl(it.first, it.second))
}
+
+ verify(controlsModelCallback).onFirstChange()
}
@Test
@@ -203,10 +216,12 @@
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 @@
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 c330b38..0000000
--- 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 0000000..ce33a8d
--- /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 300cb21..3af164d 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.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 @@
@SmallTest
@RunWith(AndroidTestingRunner.class)
-@TestableLooper.RunWithLooper
+@TestableLooper.RunWithLooper()
public class GlobalActionsDialogTest extends SysuiTestCase {
private GlobalActionsDialog mGlobalActionsDialog;
@@ -143,11 +144,60 @@
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 4d7e6ae..7211254 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.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.util.Size;
-import android.view.DisplayInfo;
import androidx.test.filters.SmallTest;
@@ -59,12 +58,8 @@
@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 @@
@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 @@
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 @@
@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 bfcf41d..a927c80 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 @@
mNotificationShadeWindowController, mKeyguardStateController, mHandler,
mUpdateMonitor, res.getResources(), mKeyguardBypassController, mDozeParameters,
mMetricsLogger, mDumpManager);
- mBiometricUnlockController.setStatusBarKeyguardViewManager(mStatusBarKeyguardViewManager);
+ mBiometricUnlockController.setKeyguardViewController(mStatusBarKeyguardViewManager);
}
@Test
@@ -202,7 +202,7 @@
@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 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 @@
@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 190b443..5b052df 100644
--- a/packages/Tethering/Android.bp
+++ b/packages/Tethering/Android.bp
@@ -25,7 +25,7 @@
],
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 3509801..cc095a0 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 @@
/**
* 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 @@
@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 @@
}
/**
+ * 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 d6bc063..82a26be 100644
--- a/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
+++ b/packages/Tethering/src/android/net/dhcp/DhcpServingParamsParcelExt.java
@@ -18,10 +18,12 @@
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 @@
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 5b6fe91..1dac5b7 100644
--- a/packages/Tethering/src/android/net/ip/IpServer.java
+++ b/packages/Tethering/src/android/net/ip/IpServer.java
@@ -18,6 +18,7 @@
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 @@
}
}
- 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 @@
}
}
- 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 @@
// 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 @@
mLinkProperties.removeRoute(route);
}
- return configureDhcp(enabled, srvAddr, prefixLen);
+ return configureDhcp(enabled, mIpv4Address, mStaticIpv4ClientAddr);
}
private String getRandomWifiIPv4Address() {
@@ -962,7 +971,14 @@
}
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 e8add98..f8eb147 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 @@
@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 @@
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 3a580dd..2955903c 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_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 @@
}
@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 @@
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 0000000..c2b3b18
--- /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 ca230b6..ea4aaa4 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.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 @@
// 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 @@
+ 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 a8bc2b4..77773ed 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -127,7 +127,7 @@
"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 8a1de1f..51427c1 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -3339,6 +3339,8 @@
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 @@
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 @@
// 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 ba89fce..0a0d8d8 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 @@
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 @@
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 @@
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 @@
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 @@
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 ea607cb..0e34801 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.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 @@
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 5250a77..506c8e3 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_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.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 @@
// 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 @@
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 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 @@
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 @@
// 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 @@
.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 @@
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 @@
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 @@
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 2aa53cc..a5de90c 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 @@
}
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 fe118e5..b688e09 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 @@
// Scan packages.
// Also has the side-effect of restarting providers if needed.
- mHandler.post(mScanPackagesRunnable);
+ postScanPackagesIfNeeded();
}
}
@@ -92,7 +92,7 @@
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 @@
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 43fc7ed..90c85ad 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 @@
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 d108e76..05a4a38 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 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 75229a1..6edd76f 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 9c41e6d..59ac603 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.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 @@
* 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 @@
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 @@
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 eb7057d..6dcf71e 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 @@
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 0000000..7cdb84b
--- /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 e9da2c4..288c22a 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 @@
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 @@
registerFullBatteryCapacity();
registerBatteryVoltage();
registerBatteryCycleCount();
+ registerSettingsStats();
}
/**
@@ -3244,6 +3247,43 @@
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 78d2afc..bcad758 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 @@
// warning toast about it.
mAtmService.getTaskChangeNotificationController()
.notifyActivityDismissingDockedStack();
- taskDisplayArea.onSplitScreenModeDismissed();
+ taskDisplayArea.onSplitScreenModeDismissed(this);
}
}
@@ -2272,7 +2272,7 @@
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 @@
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 0470ffa..f924bd4 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.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 @@
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 @@
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 @@
// 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 @@
// 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 4e85837..ad54356 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 @@
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 @@
// 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 7a6da67..0bd1aca 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 @@
// 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 40243e8..80a1a45 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.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 @@
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 337a68e..4a0da75 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.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 @@
}
} 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 02a2741..56312aa 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.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 @@
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 1f6170a..1a70de7 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 @@
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 @@
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 @@
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 @@
return false;
}
- if (!canStartHomeOnDisplay(aInfo, displayId, allowInstrumenting)) {
+ if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(), allowInstrumenting)) {
return false;
}
@@ -1520,9 +1544,9 @@
// 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 @@
}
@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 @@
}
if (aInfo != null) {
- if (!canStartHomeOnDisplay(aInfo, displayId, false /* allowInstrumenting */)) {
+ if (!canStartHomeOnDisplay(aInfo, taskDisplayArea.getDisplayId(),
+ false /* allowInstrumenting */)) {
aInfo = null;
}
}
@@ -1633,19 +1659,18 @@
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 @@
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 @@
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,6 +2073,38 @@
}
/**
+ * Move stack with all its existing content to specified task display area.
+ * @param stackId Id of stack to move.
+ * @param taskDisplayArea The task display area to move stack to.
+ * @param onTop Indicates whether container should be place on top or on bottom.
+ */
+ void moveStackToTaskDisplayArea(int stackId, TaskDisplayArea taskDisplayArea, boolean onTop) {
+ final ActivityStack stack = getStack(stackId);
+ if (stack == null) {
+ throw new IllegalArgumentException("moveStackToTaskDisplayArea: Unknown stackId="
+ + stackId);
+ }
+
+ final TaskDisplayArea currentTaskDisplayArea = stack.getDisplayArea();
+ if (currentTaskDisplayArea == null) {
+ throw new IllegalStateException("moveStackToTaskDisplayArea: stack=" + stack
+ + " is not attached to any task display area.");
+ }
+
+ if (taskDisplayArea == null) {
+ throw new IllegalArgumentException(
+ "moveStackToTaskDisplayArea: Unknown taskDisplayArea=" + taskDisplayArea);
+ }
+
+ if (currentTaskDisplayArea == taskDisplayArea) {
+ throw new IllegalArgumentException("Trying to move stack=" + stack
+ + " 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.
@@ -2058,32 +2116,15 @@
throw new IllegalArgumentException("moveStackToDisplay: Unknown displayId="
+ displayId);
}
- final ActivityStack stack = getStack(stackId);
- if (stack == null) {
- throw new IllegalArgumentException("moveStackToDisplay: 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.");
- }
-
- if (currentDisplay.mDisplayId == displayId) {
- throw new IllegalArgumentException("Trying to move stack=" + stack
- + " to its current 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 @@
// 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 @@
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 7d8a56e..56147f2 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 @@
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 @@
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 fd32724..373abfe 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_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 @@
// 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 fee1c80..ea9a362 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 @@
* {@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 @@
/**
* 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 @@
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 @@
}
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 c3fb68f..9d87976 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.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 @@
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 @@
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 @@
}
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 @@
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 @@
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 3e2e9be..86bc013 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 @@
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 627fdc3..c11c29b5 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.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 @@
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 @@
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 @@
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 @@
mToken = token;
mActivityRecord = mToken.asActivityRecord();
mOwnerUid = ownerId;
+ mShowUserId = showUserId;
mOwnerCanAddInternalSystemWindow = ownerCanAddInternalSystemWindow;
mWindowId = new WindowId(this);
mAttrs.copyFrom(a);
@@ -3275,7 +3282,7 @@
}
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 @@
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 @@
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 5976b48..e34b816 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 @@
// 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 @@
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 @@
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 e99a264..76b1713 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -135,7 +135,7 @@
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 853eba7..e32a343 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 @@
// 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 2dbbc5a..fc8c6fe 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 @@
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 @@
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 @@
}
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 @@
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 @@
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 @@
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 28613e1..5a7d5da 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 @@
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 @@
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 @@
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 92366e5..2c6bf0a 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 @@
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 @@
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 @@
if (!mAppOpsManager) {
LOG(FATAL) << "AppOpsManager is unavailable";
}
+
+ mJobQueue.reserve(16);
+ mJobProcessor = std::thread([this]() {
+ mJni->initializeForCurrentThread();
+ runJobProcessing();
+ });
+
mountExistingImages();
}
@@ -256,7 +262,14 @@
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 @@
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 @@
}
}
-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 @@
}
}
+ /* 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 @@
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 @@
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 @@
// 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 @@
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 @@
}
if (enableReadLogs) {
- registerAppOpsCallback(ifs->dataLoaderParams.packageName);
+ registerAppOpsCallback(params.packageName);
}
return 0;
@@ -701,8 +718,8 @@
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 @@
}
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 @@
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 @@
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 @@
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 @@
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 @@
}
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 @@
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,81 +1244,158 @@
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();
-
- 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);
- }
- auto prepareInstsTs = Clock::now();
-
- size_t res = mIncFs->writeBlocks(instructions);
- if (res != instructions.size()) {
- LOG(ERROR) << "Failed to write data into: " << targetLibPath;
- return false;
- }
+ 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);
+ });
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);
+ auto prepareJobTs = Clock::now();
+ LOG(INFO) << "incfs: Processed " << libName << ": "
+ << elapsedMcs(startFileTs, prepareJobTs)
+ << "mcs, make file: " << elapsedMcs(startFileTs, makeFileTs)
+ << " prepare job: " << elapsedMcs(makeFileTs, prepareJobTs);
}
}
+ auto processedTs = Clock::now();
+
+ 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) {
auto end = Clock::now();
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 @@
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 @@
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 @@
}
}
-binder::Status IncrementalService::IncrementalDataLoaderListener::onStatusChanged(MountId mountId,
- int newStatus) {
- if (externalListener) {
- // Give an external listener a chance to act before we destroy something.
- externalListener->onStatusChanged(mountId, newStatus);
+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;
}
- bool startRequested = false;
+ 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.
+ mListener->onStatusChanged(mountId, newStatus);
+ }
+
{
- 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 db14a79..e7705df 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 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 @@
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 @@
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 @@
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 @@
/*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 @@
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 @@
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 @@
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 9f4192f..bf8e696 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 @@
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 @@
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 84bf1ff..142bf2e 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 @@
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 @@
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 4a34b11..3213875 100644
--- a/services/incremental/include/incremental_service.h
+++ b/services/incremental/include/incremental_service.h
@@ -24,7 +24,7 @@
#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 18ae4b5..117dca8 100644
--- a/services/incremental/test/IncrementalServiceTest.cpp
+++ b/services/incremental/test/IncrementalServiceTest.cpp
@@ -131,6 +131,23 @@
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 @@
*_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 @@
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 @@
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 @@
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, 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 @@
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 @@
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 @@
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 @@
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 c54102f..9f29799 100644
--- a/services/net/Android.bp
+++ b/services/net/Android.bp
@@ -12,8 +12,8 @@
":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 @@
],
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 f4d7b8b..d338b58 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 @@
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 ccbaee4..aa923e2 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 @@
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 820e61c..9eda718 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 @@
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 0000000..cfeadc6
--- /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 22d7fcb..5c6906c 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 @@
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 @@
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 1144272a..8a9504d 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.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 org.junit.Before;
import org.junit.Test;
+import org.junit.runner.RunWith;
import java.util.Map;
@@ -65,6 +68,7 @@
*/
@MediumTest
@Presubmit
+@RunWith(WindowTestRunner.class)
public class LaunchParamsControllerTests extends ActivityTestsBase {
private LaunchParamsController mController;
private TestLaunchParamsPersister mPersister;
@@ -276,16 +280,21 @@
@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 @@
}
}
}
+
+ 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 b648346..7613655 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.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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
// 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 @@
.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 7a075a2..4a8e8da 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 @@
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 084216a..fc95556 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 @@
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 397f73c..e561c13 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 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 @@
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 @@
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 76479cb..535d53e 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.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 @@
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 bce06e4..4e14fd3 100644
--- a/telecomm/java/android/telecom/Conference.java
+++ b/telecomm/java/android/telecom/Conference.java
@@ -1092,16 +1092,16 @@
* 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 0d66013..73296986 100755
--- a/telecomm/java/android/telecom/ConnectionService.java
+++ b/telecomm/java/android/telecom/ConnectionService.java
@@ -1865,25 +1865,23 @@
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 @@
}
}
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 90b69a3..1f8aafb 100644
--- a/telecomm/java/android/telecom/ParcelableConference.java
+++ b/telecomm/java/android/telecom/ParcelableConference.java
@@ -22,6 +22,7 @@
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 @@
*/
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 @@
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 @@
mAddressPresentation = addressPresentation;
mCallerDisplayName = callerDisplayName;
mCallerDisplayNamePresentation = callerDisplayNamePresentation;
- mDisconnectCause = null;
- mRingbackRequested = false;
+ mDisconnectCause = disconnectCause;
+ mRingbackRequested = ringbackRequested;
+ mCallDirection = callDirection;
}
@Override
@@ -134,6 +218,8 @@
.append(mRingbackRequested)
.append(", disconnectCause: ")
.append(mDisconnectCause)
+ .append(", callDirection: ")
+ .append(mCallDirection)
.toString();
}
@@ -192,10 +278,15 @@
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 @@
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 @@
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 56f3c3e..7f6e123 100755
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3074,6 +3074,28 @@
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 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 @@
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 @@
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 912a27f..b864e37 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -4908,6 +4908,29 @@
}
@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 8fa0ab9..a392ae3 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 @@
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 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 @@
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 @@
@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 @@
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 @@
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 @@
// 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 @@
// 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 @@
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 @@
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 f0333c9..f852311 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.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 @@
# 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 b110a61..71f0ab8 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -2973,4 +2973,15 @@
*/
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 e210e4f..a7b6765 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 @@
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());
+ }
}