Merge "Remove debug log"
diff --git a/Android.bp b/Android.bp
index ffb4d3a..c899179 100644
--- a/Android.bp
+++ b/Android.bp
@@ -551,17 +551,25 @@
java_library {
name: "framework-annotation-proc",
- srcs: [":framework-all-sources"],
+ srcs: [
+ ":framework-all-sources",
+ "core/java/**/*.logtags",
+ ],
+ sdk_version: "core_platform",
libs: [
"app-compat-annotations",
+ "ext",
+ "icing-java-proto-lite",
"unsupportedappusage",
],
+
installable: false,
plugins: [
"unsupportedappusage-annotation-processor",
"compat-changeid-annotation-processor",
],
static_libs: [
+ "framework-internal-utils",
"exoplayer2-extractor",
"android.hardware.wifi-V1.0-java-constants",
]
@@ -734,6 +742,7 @@
"core/java/android/annotation/RequiresPermission.java",
"core/java/android/annotation/SystemApi.java",
"core/java/android/annotation/TestApi.java",
+ "core/java/com/android/internal/annotations/GuardedBy.java",
],
}
// Build ext.jar
diff --git a/apex/Android.bp b/apex/Android.bp
index abebfa3..362cf95 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -29,6 +29,16 @@
// TODO: remove this server classes are cleaned up.
mainline_stubs_args += "--hide-package com.android.server "
+priv_apps = " " +
+ "--show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
+ "\\) "
+
+module_libs = " " +
+ " --show-annotation android.annotation.SystemApi\\(" +
+ "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
+ "\\) "
+
stubs_defaults {
name: "framework-module-stubs-defaults-publicapi",
args: mainline_stubs_args,
@@ -37,36 +47,23 @@
stubs_defaults {
name: "framework-module-stubs-defaults-systemapi",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ args: mainline_stubs_args + priv_apps,
installable: false,
}
+// The defaults for module_libs comes in two parts - defaults for API checks
+// and defaults for stub generation. This is because we want the API txt
+// files to *only* include the module_libs_api, but the stubs to include
+// module_libs_api as well as priv_apps.
+
stubs_defaults {
- name: "framework-module-stubs-defaults-module_apps_api",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ name: "framework-module-api-defaults-module_libs_api",
+ args: mainline_stubs_args + module_libs,
installable: false,
}
stubs_defaults {
name: "framework-module-stubs-defaults-module_libs_api",
- args: mainline_stubs_args +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.PRIVILEGED_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_APPS," +
- "process=android.annotation.SystemApi.Process.ALL\\) " +
- " --show-annotation android.annotation.SystemApi\\(" +
- "client=android.annotation.SystemApi.Client.MODULE_LIBRARIES," +
- "process=android.annotation.SystemApi.Process.ALL\\) ",
+ args: mainline_stubs_args + module_libs + priv_apps,
installable: false,
}
diff --git a/apex/blobstore/TEST_MAPPING b/apex/blobstore/TEST_MAPPING
index 4dc0c49..cfe19a5 100644
--- a/apex/blobstore/TEST_MAPPING
+++ b/apex/blobstore/TEST_MAPPING
@@ -2,6 +2,14 @@
"presubmit": [
{
"name": "CtsBlobStoreTestCases"
+ },
+ {
+ "name": "FrameworksServicesTests",
+ "options": [
+ {
+ "include-filter": "com.android.server.blob"
+ }
+ ]
}
]
}
\ No newline at end of file
diff --git a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
index f7e6a98..f110b36 100644
--- a/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
+++ b/apex/blobstore/framework/java/android/app/blob/BlobHandle.java
@@ -45,6 +45,10 @@
public final class BlobHandle implements Parcelable {
private static final String ALGO_SHA_256 = "SHA-256";
+ private static final String[] SUPPORTED_ALGOS = {
+ ALGO_SHA_256
+ };
+
private static final int LIMIT_BLOB_TAG_LENGTH = 128; // characters
/**
@@ -104,14 +108,9 @@
public static @NonNull BlobHandle create(@NonNull String algorithm, @NonNull byte[] digest,
@NonNull CharSequence label, @CurrentTimeMillisLong long expiryTimeMillis,
@NonNull String tag) {
- Preconditions.checkNotNull(algorithm, "algorithm must not be null");
- Preconditions.checkNotNull(digest, "digest must not be null");
- Preconditions.checkNotNull(label, "label must not be null");
- Preconditions.checkArgumentNonnegative(expiryTimeMillis,
- "expiryTimeMillis must not be negative");
- Preconditions.checkNotNull(tag, "tag must not be null");
- Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
- return new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ final BlobHandle handle = new BlobHandle(algorithm, digest, label, expiryTimeMillis, tag);
+ handle.assertIsValid();
+ return handle;
}
/**
@@ -215,12 +214,47 @@
}
/** @hide */
- public void dump(IndentingPrintWriter fout) {
- fout.println("algo: " + algorithm);
- fout.println("digest: " + Base64.encodeToString(digest, Base64.NO_WRAP));
- fout.println("label: " + label);
- fout.println("expiryMs: " + expiryTimeMillis);
- fout.println("tag: " + tag);
+ public void dump(IndentingPrintWriter fout, boolean dumpFull) {
+ if (dumpFull) {
+ fout.println("algo: " + algorithm);
+ fout.println("digest: " + (dumpFull ? encodeDigest() : safeDigest()));
+ fout.println("label: " + label);
+ fout.println("expiryMs: " + expiryTimeMillis);
+ fout.println("tag: " + tag);
+ } else {
+ fout.println(toString());
+ }
+ }
+
+ /** @hide */
+ public void assertIsValid() {
+ Preconditions.checkArgumentIsSupported(SUPPORTED_ALGOS, algorithm);
+ Preconditions.checkByteArrayNotEmpty(digest, "digest");
+ Preconditions.checkStringNotEmpty(label, "label must not be null");
+ Preconditions.checkArgumentNonnegative(expiryTimeMillis,
+ "expiryTimeMillis must not be negative");
+ Preconditions.checkStringNotEmpty(tag, "tag must not be null");
+ Preconditions.checkArgument(tag.length() <= LIMIT_BLOB_TAG_LENGTH, "tag too long");
+ }
+
+ @Override
+ public String toString() {
+ return "BlobHandle {"
+ + "algo:" + algorithm + ","
+ + "digest:" + safeDigest() + ","
+ + "label:" + label + ","
+ + "expiryMs:" + expiryTimeMillis + ","
+ + "tag:" + tag
+ + "}";
+ }
+
+ private String safeDigest() {
+ final String digestStr = encodeDigest();
+ return digestStr.substring(0, 2) + ".." + digestStr.substring(digestStr.length() - 2);
+ }
+
+ private String encodeDigest() {
+ return Base64.encodeToString(digest, Base64.NO_WRAP);
}
public static final @NonNull Creator<BlobHandle> CREATOR = new Creator<BlobHandle>() {
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 e9838d6..aba3e8c 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobMetadata.java
@@ -48,6 +48,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.XmlUtils;
+import com.android.server.blob.BlobStoreManagerService.DumpArgs;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -156,6 +157,12 @@
}
}
+ boolean hasLeases() {
+ synchronized (mMetadataLock) {
+ return mLeasees.isEmpty();
+ }
+ }
+
boolean isAccessAllowedForCaller(String callingPackage, int callingUid) {
// TODO: verify blob is still valid (expiryTime is not elapsed)
synchronized (mMetadataLock) {
@@ -234,10 +241,10 @@
return revocableFd.getRevocableFileDescriptor();
}
- void dump(IndentingPrintWriter fout) {
+ void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
fout.println("blobHandle:");
fout.increaseIndent();
- blobHandle.dump(fout);
+ blobHandle.dump(fout, dumpArgs.shouldDumpFull());
fout.decreaseIndent();
fout.println("Committers:");
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 fcc30e30..13f095e 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerService.java
@@ -40,6 +40,7 @@
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.UserIdInt;
import android.app.blob.BlobHandle;
import android.app.blob.IBlobStoreManager;
import android.app.blob.IBlobStoreSession;
@@ -49,6 +50,7 @@
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManagerInternal;
+import android.content.res.ResourceId;
import android.os.Binder;
import android.os.Handler;
import android.os.HandlerThread;
@@ -67,6 +69,8 @@
import android.util.Xml;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
import com.android.internal.util.IndentingPrintWriter;
@@ -91,6 +95,7 @@
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
+import java.util.Objects;
/**
* Service responsible for maintaining and facilitating access to data blobs published by apps.
@@ -112,20 +117,35 @@
private final Context mContext;
private final Handler mHandler;
+ private final Injector mInjector;
private final SessionStateChangeListener mSessionStateChangeListener =
new SessionStateChangeListener();
private PackageManagerInternal mPackageManagerInternal;
- public BlobStoreManagerService(Context context) {
- super(context);
- mContext = context;
+ private final Runnable mSaveBlobsInfoRunnable = this::writeBlobsInfo;
+ private final Runnable mSaveSessionsRunnable = this::writeBlobSessions;
+ public BlobStoreManagerService(Context context) {
+ this(context, new Injector());
+ }
+
+ @VisibleForTesting
+ BlobStoreManagerService(Context context, Injector injector) {
+ super(context);
+
+ mContext = context;
+ mInjector = injector;
+ mHandler = mInjector.initializeMessageHandler();
+ }
+
+ private static Handler initializeMessageHandler() {
final HandlerThread handlerThread = new ServiceThread(TAG,
Process.THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
handlerThread.start();
- mHandler = new Handler(handlerThread.getLooper());
- Watchdog.getInstance().addThread(mHandler);
+ final Handler handler = new Handler(handlerThread.getLooper());
+ Watchdog.getInstance().addThread(handler);
+ return handler;
}
@Override
@@ -181,6 +201,20 @@
return userBlobs;
}
+ @VisibleForTesting
+ void addUserSessionsForTest(LongSparseArray<BlobStoreSession> userSessions, int userId) {
+ synchronized (mBlobsLock) {
+ mSessions.put(userId, userSessions);
+ }
+ }
+
+ @VisibleForTesting
+ void addUserBlobsForTest(ArrayMap<BlobHandle, BlobMetadata> userBlobs, int userId) {
+ synchronized (mBlobsLock) {
+ mBlobsMap.put(userId, userBlobs);
+ }
+ }
+
private long createSessionInternal(BlobHandle blobHandle,
int callingUid, String callingPackage) {
synchronized (mBlobsLock) {
@@ -293,23 +327,23 @@
case STATE_ABANDONED:
case STATE_VERIFIED_INVALID:
session.getSessionFile().delete();
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
- .remove(session.sessionId);
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
+ .remove(session.getSessionId());
break;
case STATE_COMMITTED:
session.verifyBlobData();
break;
case STATE_VERIFIED_VALID:
- final int userId = UserHandle.getUserId(session.ownerUid);
+ final int userId = UserHandle.getUserId(session.getOwnerUid());
final ArrayMap<BlobHandle, BlobMetadata> userBlobs = getUserBlobsLocked(userId);
- BlobMetadata blob = userBlobs.get(session.blobHandle);
+ BlobMetadata blob = userBlobs.get(session.getBlobHandle());
if (blob == null) {
blob = new BlobMetadata(mContext,
- session.sessionId, session.blobHandle, userId);
- userBlobs.put(session.blobHandle, blob);
+ session.getSessionId(), session.getBlobHandle(), userId);
+ userBlobs.put(session.getBlobHandle(), blob);
}
- final Committer newCommitter = new Committer(session.ownerPackageName,
- session.ownerUid, session.getBlobAccessMode());
+ final Committer newCommitter = new Committer(session.getOwnerPackageName(),
+ session.getOwnerUid(), session.getBlobAccessMode());
final Committer existingCommitter = blob.getExistingCommitter(newCommitter);
blob.addCommitter(newCommitter);
try {
@@ -319,8 +353,8 @@
blob.addCommitter(existingCommitter);
session.sendCommitCallbackResult(COMMIT_RESULT_ERROR);
}
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid))
- .remove(session.sessionId);
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid()))
+ .remove(session.getSessionId());
break;
default:
Slog.wtf(TAG, "Invalid session state: "
@@ -399,17 +433,17 @@
continue;
}
final SparseArray<String> userPackages = allPackages.get(
- UserHandle.getUserId(session.ownerUid));
+ UserHandle.getUserId(session.getOwnerUid()));
if (userPackages != null
- && session.ownerPackageName.equals(
- userPackages.get(session.ownerUid))) {
- getUserSessionsLocked(UserHandle.getUserId(session.ownerUid)).put(
- session.sessionId, session);
+ && session.getOwnerPackageName().equals(
+ userPackages.get(session.getOwnerUid()))) {
+ getUserSessionsLocked(UserHandle.getUserId(session.getOwnerUid())).put(
+ session.getSessionId(), session);
} else {
// Unknown package or the session data does not belong to this package.
session.getSessionFile().delete();
}
- mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.sessionId);
+ mCurrentMaxSessionId = Math.max(mCurrentMaxSessionId, session.getSessionId());
}
}
} catch (Exception e) {
@@ -504,9 +538,9 @@
}
private void writeBlobsInfoAsync() {
- mHandler.post(PooledLambda.obtainRunnable(
- BlobStoreManagerService::writeBlobsInfo,
- BlobStoreManagerService.this).recycleOnUse());
+ if (!mHandler.hasCallbacks(mSaveBlobsInfoRunnable)) {
+ mHandler.post(mSaveBlobsInfoRunnable);
+ }
}
private void writeBlobSessions() {
@@ -520,9 +554,9 @@
}
private void writeBlobSessionsAsync() {
- mHandler.post(PooledLambda.obtainRunnable(
- BlobStoreManagerService::writeBlobSessions,
- BlobStoreManagerService.this).recycleOnUse());
+ if (!mHandler.hasCallbacks(mSaveSessionsRunnable)) {
+ mHandler.post(mSaveSessionsRunnable);
+ }
}
private int getPackageUid(String packageName, int userId) {
@@ -568,7 +602,8 @@
return new AtomicFile(file, "blobs_index" /* commitLogTag */);
}
- private void handlePackageRemoved(String packageName, int uid) {
+ @VisibleForTesting
+ void handlePackageRemoved(String packageName, int uid) {
synchronized (mBlobsLock) {
// Clean up any pending sessions
final LongSparseArray<BlobStoreSession> userSessions =
@@ -576,25 +611,35 @@
final ArrayList<Integer> indicesToRemove = new ArrayList<>();
for (int i = 0, count = userSessions.size(); i < count; ++i) {
final BlobStoreSession session = userSessions.valueAt(i);
- if (session.ownerUid == uid
- && session.ownerPackageName.equals(packageName)) {
+ if (session.getOwnerUid() == uid
+ && session.getOwnerPackageName().equals(packageName)) {
session.getSessionFile().delete();
indicesToRemove.add(i);
}
}
for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
- userSessions.removeAt(i);
+ userSessions.removeAt(indicesToRemove.get(i));
}
+ writeBlobSessionsAsync();
// Remove the package from the committer and leasee list
final ArrayMap<BlobHandle, BlobMetadata> userBlobs =
getUserBlobsLocked(UserHandle.getUserId(uid));
+ indicesToRemove.clear();
for (int i = 0, count = userBlobs.size(); i < count; ++i) {
final BlobMetadata blobMetadata = userBlobs.valueAt(i);
blobMetadata.removeCommitter(packageName, uid);
blobMetadata.removeLeasee(packageName, uid);
+ // Delete the blob if it doesn't have any active leases.
+ if (!blobMetadata.hasLeases()) {
+ blobMetadata.getBlobFile().delete();
+ indicesToRemove.add(i);
+ }
}
- // TODO: clean-up blobs which doesn't have any active leases.
+ for (int i = 0, count = indicesToRemove.size(); i < count; ++i) {
+ userBlobs.removeAt(indicesToRemove.get(i));
+ }
+ writeBlobsInfoAsync();
}
}
@@ -620,6 +665,80 @@
}
}
+ void runClearAllSessions(@UserIdInt int userId) {
+ synchronized (mBlobsLock) {
+ if (userId == UserHandle.USER_ALL) {
+ mSessions.clear();
+ } else {
+ mSessions.remove(userId);
+ }
+ writeBlobSessionsAsync();
+ }
+ }
+
+ void runClearAllBlobs(@UserIdInt int userId) {
+ synchronized (mBlobsLock) {
+ if (userId == UserHandle.USER_ALL) {
+ mBlobsMap.clear();
+ } else {
+ mBlobsMap.remove(userId);
+ }
+ writeBlobsInfoAsync();
+ }
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void dumpSessionsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
+ for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
+ final int userId = mSessions.keyAt(i);
+ if (!dumpArgs.shouldDumpUser(userId)) {
+ continue;
+ }
+ final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
+ fout.println("List of sessions in user #"
+ + userId + " (" + userSessions.size() + "):");
+ fout.increaseIndent();
+ for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
+ final long sessionId = userSessions.keyAt(j);
+ final BlobStoreSession session = userSessions.valueAt(j);
+ if (!dumpArgs.shouldDumpSession(session.getOwnerPackageName(),
+ session.getOwnerUid(), session.getSessionId())) {
+ continue;
+ }
+ fout.println("Session #" + sessionId);
+ fout.increaseIndent();
+ session.dump(fout, dumpArgs);
+ fout.decreaseIndent();
+ }
+ fout.decreaseIndent();
+ }
+ }
+
+ @GuardedBy("mBlobsLock")
+ private void dumpBlobsLocked(IndentingPrintWriter fout, DumpArgs dumpArgs) {
+ for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
+ final int userId = mBlobsMap.keyAt(i);
+ if (!dumpArgs.shouldDumpUser(userId)) {
+ continue;
+ }
+ final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
+ fout.println("List of blobs in user #"
+ + userId + " (" + userBlobs.size() + "):");
+ fout.increaseIndent();
+ for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
+ final BlobMetadata blobMetadata = userBlobs.valueAt(j);
+ if (!dumpArgs.shouldDumpBlob(blobMetadata.blobId)) {
+ continue;
+ }
+ fout.println("Blob #" + blobMetadata.blobId);
+ fout.increaseIndent();
+ blobMetadata.dump(fout, dumpArgs);
+ fout.decreaseIndent();
+ }
+ fout.decreaseIndent();
+ }
+ }
+
private class PackageChangedReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
@@ -658,10 +777,9 @@
@IntRange(from = 1)
public long createSession(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- // TODO: verify blobHandle.algorithm is sha-256
- // TODO: assert blobHandle is valid.
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -682,7 +800,7 @@
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -695,7 +813,7 @@
@NonNull String packageName) {
Preconditions.checkArgumentPositive(sessionId,
"sessionId must be positive: " + sessionId);
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -706,8 +824,9 @@
@Override
public ParcelFileDescriptor openBlob(@NonNull BlobHandle blobHandle,
@NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -727,24 +846,27 @@
@Override
public void acquireLease(@NonNull BlobHandle blobHandle, @IdRes int descriptionResId,
- @CurrentTimeSecondsLong long leaseTimeoutSecs, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
- Preconditions.checkArgumentPositive(descriptionResId,
- "descriptionResId must be positive; value=" + descriptionResId);
+ @CurrentTimeSecondsLong long leaseExpiryTimeMillis, @NonNull String packageName) {
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Preconditions.checkArgument(ResourceId.isValid(descriptionResId),
+ "descriptionResId is not valid");
+ Preconditions.checkArgumentNonnegative(leaseExpiryTimeMillis,
+ "leaseExpiryTimeMillis must not be negative");
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
- acquireLeaseInternal(blobHandle, descriptionResId, leaseTimeoutSecs,
+ acquireLeaseInternal(blobHandle, descriptionResId, leaseExpiryTimeMillis,
callingUid, packageName);
}
@Override
public void releaseLease(@NonNull BlobHandle blobHandle, @NonNull String packageName) {
- Preconditions.checkNotNull(blobHandle, "blobHandle must not be null");
- Preconditions.checkNotNull(packageName, "packageName must not be null");
-
+ Objects.requireNonNull(blobHandle, "blobHandle must not be null");
+ blobHandle.assertIsValid();
+ Objects.requireNonNull(packageName, "packageName must not be null");
final int callingUid = Binder.getCallingUid();
verifyCallingPackage(callingUid, packageName);
@@ -754,7 +876,7 @@
@Override
public void waitForIdle(@NonNull RemoteCallback remoteCallback) {
- Preconditions.checkNotNull(remoteCallback, "remoteCallback must not be null");
+ Objects.requireNonNull(remoteCallback, "remoteCallback must not be null");
mContext.enforceCallingOrSelfPermission(android.Manifest.permission.DUMP,
"Caller is not allowed to call this; caller=" + Binder.getCallingUid());
@@ -766,47 +888,164 @@
public void dump(@NonNull FileDescriptor fd, @NonNull PrintWriter writer,
@Nullable String[] args) {
// TODO: add proto-based version of this.
- if (!DumpUtils.checkDumpPermission(mContext, TAG, writer)) return;
+ if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, TAG, writer)) return;
+
+ final DumpArgs dumpArgs = DumpArgs.parse(args);
final IndentingPrintWriter fout = new IndentingPrintWriter(writer, " ");
synchronized (mBlobsLock) {
fout.println("mCurrentMaxSessionId: " + mCurrentMaxSessionId);
fout.println();
- for (int i = 0, userCount = mSessions.size(); i < userCount; ++i) {
- final int userId = mSessions.keyAt(i);
- final LongSparseArray<BlobStoreSession> userSessions = mSessions.valueAt(i);
- fout.println("List of sessions in user #"
- + userId + " (" + userSessions.size() + "):");
- fout.increaseIndent();
- for (int j = 0, sessionsCount = userSessions.size(); j < sessionsCount; ++j) {
- final long sessionId = userSessions.keyAt(j);
- final BlobStoreSession session = userSessions.valueAt(j);
- fout.println("Session #" + sessionId);
- fout.increaseIndent();
- session.dump(fout);
- fout.decreaseIndent();
- }
- fout.decreaseIndent();
+
+ if (dumpArgs.shouldDumpSessions()) {
+ dumpSessionsLocked(fout, dumpArgs);
+ fout.println();
}
-
- fout.print("\n\n");
-
- for (int i = 0, userCount = mBlobsMap.size(); i < userCount; ++i) {
- final int userId = mBlobsMap.keyAt(i);
- final ArrayMap<BlobHandle, BlobMetadata> userBlobs = mBlobsMap.valueAt(i);
- fout.println("List of blobs in user #"
- + userId + " (" + userBlobs.size() + "):");
- fout.increaseIndent();
- for (int j = 0, blobsCount = userBlobs.size(); j < blobsCount; ++j) {
- final BlobMetadata blobMetadata = userBlobs.valueAt(j);
- fout.println("Blob #" + blobMetadata.blobId);
- fout.increaseIndent();
- blobMetadata.dump(fout);
- fout.decreaseIndent();
- }
- fout.decreaseIndent();
+ if (dumpArgs.shouldDumpBlobs()) {
+ dumpBlobsLocked(fout, dumpArgs);
+ fout.println();
}
}
}
+
+ @Override
+ public int handleShellCommand(@NonNull ParcelFileDescriptor in,
+ @NonNull ParcelFileDescriptor out, @NonNull ParcelFileDescriptor err,
+ @NonNull String[] args) {
+ return (new BlobStoreManagerShellCommand(BlobStoreManagerService.this)).exec(this,
+ in.getFileDescriptor(), out.getFileDescriptor(), err.getFileDescriptor(), args);
+ }
+ }
+
+ static final class DumpArgs {
+ private boolean mDumpFull;
+ private final ArrayList<String> mDumpPackages = new ArrayList<>();
+ private final ArrayList<Integer> mDumpUids = new ArrayList<>();
+ private final ArrayList<Integer> mDumpUserIds = new ArrayList<>();
+ private final ArrayList<Long> mDumpBlobIds = new ArrayList<>();
+ private boolean mDumpOnlySelectedSections;
+ private boolean mDumpSessions;
+ private boolean mDumpBlobs;
+
+ public boolean shouldDumpSession(String packageName, int uid, long blobId) {
+ if (!CollectionUtils.isEmpty(mDumpPackages)
+ && mDumpPackages.indexOf(packageName) < 0) {
+ return false;
+ }
+ if (!CollectionUtils.isEmpty(mDumpUids)
+ && mDumpUids.indexOf(uid) < 0) {
+ return false;
+ }
+ if (!CollectionUtils.isEmpty(mDumpBlobIds)
+ && mDumpBlobIds.indexOf(blobId) < 0) {
+ return false;
+ }
+ return true;
+ }
+
+ public boolean shouldDumpSessions() {
+ if (!mDumpOnlySelectedSections) {
+ return true;
+ }
+ return mDumpSessions;
+ }
+
+ public boolean shouldDumpBlobs() {
+ if (!mDumpOnlySelectedSections) {
+ return true;
+ }
+ return mDumpBlobs;
+ }
+
+ public boolean shouldDumpBlob(long blobId) {
+ return CollectionUtils.isEmpty(mDumpBlobIds)
+ || mDumpBlobIds.indexOf(blobId) >= 0;
+ }
+
+ public boolean shouldDumpFull() {
+ return mDumpFull;
+ }
+
+ public boolean shouldDumpUser(int userId) {
+ return CollectionUtils.isEmpty(mDumpUserIds)
+ || mDumpUserIds.indexOf(userId) >= 0;
+ }
+
+ private DumpArgs() {}
+
+ public static DumpArgs parse(String[] args) {
+ final DumpArgs dumpArgs = new DumpArgs();
+ if (args == null) {
+ return dumpArgs;
+ }
+
+ for (int i = 0; i < args.length; ++i) {
+ final String opt = args[i];
+ if ("--full".equals(opt) || "-f".equals(opt)) {
+ final int callingUid = Binder.getCallingUid();
+ if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
+ dumpArgs.mDumpFull = true;
+ }
+ } else if ("--sessions".equals(opt)) {
+ dumpArgs.mDumpOnlySelectedSections = true;
+ dumpArgs.mDumpSessions = true;
+ } else if ("--blobs".equals(opt)) {
+ dumpArgs.mDumpOnlySelectedSections = true;
+ dumpArgs.mDumpBlobs = true;
+ } else if ("--package".equals(opt) || "-p".equals(opt)) {
+ dumpArgs.mDumpPackages.add(getStringArgRequired(args, ++i, "packageName"));
+ } else if ("--uid".equals(opt) || "-u".equals(opt)) {
+ dumpArgs.mDumpUids.add(getIntArgRequired(args, ++i, "uid"));
+ } else if ("--user".equals(opt)) {
+ dumpArgs.mDumpUserIds.add(getIntArgRequired(args, ++i, "userId"));
+ } else if ("--blob".equals(opt) || "-b".equals(opt)) {
+ dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, ++i, "blobId"));
+ } else {
+ // Everything else is assumed to be blob ids.
+ dumpArgs.mDumpBlobIds.add(getLongArgRequired(args, i, "blobId"));
+ }
+ }
+ return dumpArgs;
+ }
+
+ private static String getStringArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ return args[index];
+ }
+
+ private static int getIntArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ final int value;
+ try {
+ value = Integer.parseInt(args[index]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid " + argName + ": " + args[index]);
+ }
+ return value;
+ }
+
+ private static long getLongArgRequired(String[] args, int index, String argName) {
+ if (index >= args.length) {
+ throw new IllegalArgumentException("Missing " + argName);
+ }
+ final long value;
+ try {
+ value = Long.parseLong(args[index]);
+ } catch (NumberFormatException e) {
+ throw new IllegalArgumentException("Invalid " + argName + ": " + args[index]);
+ }
+ return value;
+ }
+ }
+
+ @VisibleForTesting
+ static class Injector {
+ public Handler initializeMessageHandler() {
+ return BlobStoreManagerService.initializeMessageHandler();
+ }
}
}
\ No newline at end of file
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
new file mode 100644
index 0000000..3ac30f8
--- /dev/null
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreManagerShellCommand.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 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.blob;
+
+import android.os.ShellCommand;
+import android.os.UserHandle;
+
+import java.io.PrintWriter;
+
+class BlobStoreManagerShellCommand extends ShellCommand {
+
+ private final BlobStoreManagerService mService;
+
+ BlobStoreManagerShellCommand(BlobStoreManagerService blobStoreManagerService) {
+ mService = blobStoreManagerService;
+ }
+
+ @Override
+ public int onCommand(String cmd) {
+ if (cmd == null) {
+ return handleDefaultCommands(null);
+ }
+ final PrintWriter pw = getOutPrintWriter();
+ switch (cmd) {
+ case "clear-all-sessions":
+ return runClearAllSessions(pw);
+ case "clear-all-blobs":
+ return runClearAllBlobs(pw);
+ default:
+ return handleDefaultCommands(cmd);
+ }
+ }
+
+ private int runClearAllSessions(PrintWriter pw) {
+ final ParsedArgs args = new ParsedArgs();
+ args.userId = UserHandle.USER_ALL;
+
+ if (parseOptions(pw, args) < 0) {
+ return -1;
+ }
+
+ mService.runClearAllSessions(args.userId);
+ return 0;
+ }
+
+ private int runClearAllBlobs(PrintWriter pw) {
+ final ParsedArgs args = new ParsedArgs();
+ args.userId = UserHandle.USER_ALL;
+
+ if (parseOptions(pw, args) < 0) {
+ return -1;
+ }
+
+ mService.runClearAllBlobs(args.userId);
+ return 0;
+ }
+
+ @Override
+ public void onHelp() {
+ final PrintWriter pw = getOutPrintWriter();
+ pw.println("BlobStore service (blob_store) commands:");
+ pw.println("help");
+ pw.println(" Print this help text.");
+ pw.println();
+ pw.println("clear-all-sessions [-u | --user USER_ID]");
+ pw.println(" Remove all sessions.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's sessions to be removed;");
+ pw.println(" If not specified, sessions in all users are removed.");
+ pw.println();
+ pw.println("clear-all-blobs [-u | --user USER_ID]");
+ pw.println(" Remove all blobs.");
+ pw.println(" Options:");
+ pw.println(" -u or --user: specify which user's blobs to be removed;");
+ pw.println(" If not specified, blobs in all users are removed.");
+ pw.println();
+ }
+
+ private int parseOptions(PrintWriter pw, ParsedArgs args) {
+ String opt;
+ while ((opt = getNextOption()) != null) {
+ switch (opt) {
+ case "-u":
+ case "--user":
+ args.userId = Integer.parseInt(getNextArgRequired());
+ break;
+ default:
+ pw.println("Error: unknown option '" + opt + "'");
+ return -1;
+ }
+ }
+ return 0;
+ }
+
+ private static class ParsedArgs {
+ public int userId;
+ }
+}
diff --git a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
index 7d1c166..54a2997 100644
--- a/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
+++ b/apex/blobstore/service/java/com/android/server/blob/BlobStoreSession.java
@@ -47,9 +47,11 @@
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.internal.util.XmlUtils;
+import com.android.server.blob.BlobStoreManagerService.DumpArgs;
import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
import org.xmlpull.v1.XmlPullParser;
@@ -62,9 +64,11 @@
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Objects;
/** TODO: add doc */
-public class BlobStoreSession extends IBlobStoreSession.Stub {
+@VisibleForTesting
+class BlobStoreSession extends IBlobStoreSession.Stub {
static final int STATE_OPENED = 1;
static final int STATE_CLOSED = 0;
@@ -78,10 +82,10 @@
private final Context mContext;
private final SessionStateChangeListener mListener;
- public final BlobHandle blobHandle;
- public final long sessionId;
- public final int ownerUid;
- public final String ownerPackageName;
+ private final BlobHandle mBlobHandle;
+ private final long mSessionId;
+ private final int mOwnerUid;
+ private final String mOwnerPackageName;
// Do not access this directly, instead use getSessionFile().
private File mSessionFile;
@@ -101,15 +105,31 @@
BlobStoreSession(Context context, long sessionId, BlobHandle blobHandle,
int ownerUid, String ownerPackageName, SessionStateChangeListener listener) {
this.mContext = context;
- this.blobHandle = blobHandle;
- this.sessionId = sessionId;
- this.ownerUid = ownerUid;
- this.ownerPackageName = ownerPackageName;
+ this.mBlobHandle = blobHandle;
+ this.mSessionId = sessionId;
+ this.mOwnerUid = ownerUid;
+ this.mOwnerPackageName = ownerPackageName;
this.mListener = listener;
}
+ public BlobHandle getBlobHandle() {
+ return mBlobHandle;
+ }
+
+ public long getSessionId() {
+ return mSessionId;
+ }
+
+ public int getOwnerUid() {
+ return mOwnerUid;
+ }
+
+ public String getOwnerPackageName() {
+ return mOwnerPackageName;
+ }
+
boolean hasAccess(int callingUid, String callingPackageName) {
- return ownerUid == callingUid && ownerPackageName.equals(callingPackageName);
+ return mOwnerUid == callingUid && mOwnerPackageName.equals(callingPackageName);
}
void open() {
@@ -155,6 +175,8 @@
@NonNull
public ParcelFileDescriptor openWrite(@BytesLong long offsetBytes,
@BytesLong long lengthBytes) {
+ Preconditions.checkArgumentNonnegative(offsetBytes, "offsetBytes must not be negative");
+
assertCallerIsOwner();
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
@@ -242,7 +264,7 @@
public void allowPackageAccess(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to change access type in state: "
@@ -280,7 +302,9 @@
public boolean isPackageAccessAllowed(@NonNull String packageName,
@NonNull byte[] certificate) {
assertCallerIsOwner();
- Preconditions.checkNotNull(packageName, "packageName must not be null");
+ Objects.requireNonNull(packageName, "packageName must not be null");
+ Preconditions.checkByteArrayNotEmpty(certificate, "certificate");
+
synchronized (mSessionLock) {
if (mState != STATE_OPENED) {
throw new IllegalStateException("Not allowed to get access type in state: "
@@ -357,12 +381,12 @@
void verifyBlobData() {
byte[] actualDigest = null;
try {
- actualDigest = FileUtils.digest(getSessionFile(), blobHandle.algorithm);
+ actualDigest = FileUtils.digest(getSessionFile(), mBlobHandle.algorithm);
} catch (IOException | NoSuchAlgorithmException e) {
Slog.e(TAG, "Error computing the digest", e);
}
synchronized (mSessionLock) {
- if (actualDigest != null && Arrays.equals(actualDigest, blobHandle.digest)) {
+ if (actualDigest != null && Arrays.equals(actualDigest, mBlobHandle.digest)) {
mState = STATE_VERIFIED_VALID;
// Commit callback will be sent once the data is persisted.
} else {
@@ -401,7 +425,7 @@
@Nullable
File getSessionFile() {
if (mSessionFile == null) {
- mSessionFile = BlobStoreConfig.prepareBlobFile(sessionId);
+ mSessionFile = BlobStoreConfig.prepareBlobFile(mSessionId);
}
return mSessionFile;
}
@@ -425,20 +449,20 @@
private void assertCallerIsOwner() {
final int callingUid = Binder.getCallingUid();
- if (callingUid != ownerUid) {
- throw new SecurityException(ownerUid + " is not the session owner");
+ if (callingUid != mOwnerUid) {
+ throw new SecurityException(mOwnerUid + " is not the session owner");
}
}
- void dump(IndentingPrintWriter fout) {
+ void dump(IndentingPrintWriter fout, DumpArgs dumpArgs) {
synchronized (mSessionLock) {
fout.println("state: " + stateToString(mState));
- fout.println("ownerUid: " + ownerUid);
- fout.println("ownerPkg: " + ownerPackageName);
+ fout.println("ownerUid: " + mOwnerUid);
+ fout.println("ownerPkg: " + mOwnerPackageName);
fout.println("blobHandle:");
fout.increaseIndent();
- blobHandle.dump(fout);
+ mBlobHandle.dump(fout, dumpArgs.shouldDumpFull());
fout.decreaseIndent();
fout.println("accessMode:");
@@ -452,12 +476,12 @@
void writeToXml(@NonNull XmlSerializer out) throws IOException {
synchronized (mSessionLock) {
- XmlUtils.writeLongAttribute(out, ATTR_ID, sessionId);
- XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, ownerPackageName);
- XmlUtils.writeIntAttribute(out, ATTR_UID, ownerUid);
+ XmlUtils.writeLongAttribute(out, ATTR_ID, mSessionId);
+ XmlUtils.writeStringAttribute(out, ATTR_PACKAGE, mOwnerPackageName);
+ XmlUtils.writeIntAttribute(out, ATTR_UID, mOwnerUid);
out.startTag(null, TAG_BLOB_HANDLE);
- blobHandle.writeToXml(out);
+ mBlobHandle.writeToXml(out);
out.endTag(null, TAG_BLOB_HANDLE);
out.startTag(null, TAG_ACCESS_MODE);
diff --git a/apex/statsd/Android.bp b/apex/statsd/Android.bp
index 09ca1d2..1f9f18c 100644
--- a/apex/statsd/Android.bp
+++ b/apex/statsd/Android.bp
@@ -19,8 +19,9 @@
}
apex_defaults {
- // libc.so and libcutils.so are included in the apex
- // native_shared_libs: ["libc", "libcutils"],
+ native_shared_libs: [
+ "libstats_jni",
+ ],
// binaries: ["vold"],
java_libs: [
"framework-statsd",
@@ -44,3 +45,33 @@
// com.android.os.statsd.pk8 (the private key)
certificate: "com.android.os.statsd",
}
+
+
+// JNI library for StatsLog.write
+cc_library_shared {
+ name: "libstats_jni",
+ srcs: ["jni/**/*.cpp"],
+ shared_libs: [
+ "libnativehelper", // Has stable abi - should not be copied into apex.
+ "liblog", // Has a stable abi - should not be copied into apex.
+ ],
+ static_libs: [
+ //TODO: make shared - need libstatssocket to also live in the apex.
+ "libstatssocket",
+ "libcutils", // TODO: remove - needed by libstatssocket
+ ],
+ //TODO: is libc++_static correct?
+ stl: "libc++_static",
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+ apex_available: [
+ "com.android.os.statsd",
+ "test_com.android.os.statsd",
+ //TODO (b/148620413): remove platform.
+ "//apex_available:platform",
+ ],
+}
\ No newline at end of file
diff --git a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
index bdd1da7..b94928f 100644
--- a/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
+++ b/apex/statsd/aidl/android/os/IStatsCompanionService.aidl
@@ -61,4 +61,11 @@
/** Tells StatsCompaionService to grab the uid map snapshot and send it to statsd. */
oneway void triggerUidSnapshot();
+
+ /**
+ * Ask StatsCompanionService if the given permission is allowed for a particular process
+ * and user ID. statsd is incapable of doing this check itself because checkCallingPermission
+ * is not currently supported by libbinder_ndk.
+ */
+ boolean checkPermission(String permission, int pid, int uid);
}
diff --git a/core/jni/android_util_StatsLog.cpp b/apex/statsd/jni/android_util_StatsLog.cpp
similarity index 71%
rename from core/jni/android_util_StatsLog.cpp
rename to apex/statsd/jni/android_util_StatsLog.cpp
index 9225fc2..9d410eb 100644
--- a/core/jni/android_util_StatsLog.cpp
+++ b/apex/statsd/jni/android_util_StatsLog.cpp
@@ -17,12 +17,9 @@
#define LOG_NAMESPACE "StatsLog.tag."
#define LOG_TAG "StatsLog_println"
-#include <assert.h>
-
#include "jni.h"
+#include <log/log.h>
#include <nativehelper/JNIHelp.h>
-#include "utils/misc.h"
-#include "core_jni_helpers.h"
#include "stats_buffer_writer.h"
namespace android {
@@ -57,7 +54,27 @@
int register_android_util_StatsLog(JNIEnv* env)
{
- return RegisterMethodsOrDie(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
+ return jniRegisterNativeMethods(env, "android/util/StatsLog", gMethods, NELEM(gMethods));
}
-
}; // namespace android
+
+/*
+ * JNI Initialization
+ */
+jint JNI_OnLoad(JavaVM* jvm, void* reserved) {
+ JNIEnv* e;
+ int status;
+
+ ALOGV("statsd : loading JNI\n");
+ // Check JNI version
+ if (jvm->GetEnv((void**)&e, JNI_VERSION_1_4)) {
+ ALOGE("JNI version mismatch error");
+ return JNI_ERR;
+ }
+ status = android::register_android_util_StatsLog(e);
+ if (status < 0) {
+ ALOGE("jni statsd registration failure, status: %d", status);
+ return JNI_ERR;
+ }
+ return JNI_VERSION_1_4;
+}
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 1e92826..3e9a488 100644
--- a/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
+++ b/apex/statsd/service/java/com/android/server/stats/StatsCompanionService.java
@@ -516,6 +516,11 @@
}
}
+ @Override // Binder call
+ public boolean checkPermission(String permission, int pid, int uid) {
+ StatsCompanion.enforceStatsCompanionPermission(mContext);
+ return mContext.checkPermission(permission, pid, uid) == PackageManager.PERMISSION_GRANTED;
+ }
// Statsd related code
diff --git a/api/current.txt b/api/current.txt
index 510db01..2416493f 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2875,9 +2875,17 @@
method public boolean takeScreenshot(int, @NonNull java.util.concurrent.Executor, @NonNull java.util.function.Consumer<android.graphics.Bitmap>);
field public static final int GESTURE_2_FINGER_DOUBLE_TAP = 20; // 0x14
field public static final int GESTURE_2_FINGER_SINGLE_TAP = 19; // 0x13
+ field public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26; // 0x1a
+ field public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27; // 0x1b
+ field public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28; // 0x1c
+ field public static final int GESTURE_2_FINGER_SWIPE_UP = 25; // 0x19
field public static final int GESTURE_2_FINGER_TRIPLE_TAP = 21; // 0x15
field public static final int GESTURE_3_FINGER_DOUBLE_TAP = 23; // 0x17
field public static final int GESTURE_3_FINGER_SINGLE_TAP = 22; // 0x16
+ field public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30; // 0x1e
+ field public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31; // 0x1f
+ field public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32; // 0x20
+ field public static final int GESTURE_3_FINGER_SWIPE_UP = 29; // 0x1d
field public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24; // 0x18
field public static final int GESTURE_DOUBLE_TAP = 17; // 0x11
field public static final int GESTURE_DOUBLE_TAP_AND_HOLD = 18; // 0x12
@@ -8631,7 +8639,7 @@
field public static final String ACTION_ACL_CONNECTED = "android.bluetooth.device.action.ACL_CONNECTED";
field public static final String ACTION_ACL_DISCONNECTED = "android.bluetooth.device.action.ACL_DISCONNECTED";
field public static final String ACTION_ACL_DISCONNECT_REQUESTED = "android.bluetooth.device.action.ACL_DISCONNECT_REQUESTED";
- field public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.action.ALIAS_CHANGED";
+ field public static final String ACTION_ALIAS_CHANGED = "android.bluetooth.device.action.ALIAS_CHANGED";
field public static final String ACTION_BOND_STATE_CHANGED = "android.bluetooth.device.action.BOND_STATE_CHANGED";
field public static final String ACTION_CLASS_CHANGED = "android.bluetooth.device.action.CLASS_CHANGED";
field public static final String ACTION_FOUND = "android.bluetooth.device.action.FOUND";
@@ -9990,7 +9998,7 @@
method public abstract android.content.Context createDisplayContext(@NonNull android.view.Display);
method @NonNull public android.content.Context createFeatureContext(@Nullable String);
method public abstract android.content.Context createPackageContext(String, int) throws android.content.pm.PackageManager.NameNotFoundException;
- method @NonNull public android.content.Context createWindowContext(int);
+ method @NonNull public android.content.Context createWindowContext(int, @Nullable android.os.Bundle);
method public abstract String[] databaseList();
method public abstract boolean deleteDatabase(String);
method public abstract boolean deleteFile(String);
@@ -14852,10 +14860,11 @@
method public void offset(int, int);
method public void set(@NonNull android.graphics.Outline);
method public void setAlpha(@FloatRange(from=0.0, to=1.0) float);
- method public void setConvexPath(@NonNull android.graphics.Path);
+ method @Deprecated public void setConvexPath(@NonNull android.graphics.Path);
method public void setEmpty();
method public void setOval(int, int, int, int);
method public void setOval(@NonNull android.graphics.Rect);
+ method public void setPath(@NonNull android.graphics.Path);
method public void setRect(int, int, int, int);
method public void setRect(@NonNull android.graphics.Rect);
method public void setRoundRect(int, int, int, int, float);
@@ -26729,6 +26738,7 @@
method public int getVolume();
method public int getVolumeHandling();
method public int getVolumeMax();
+ method public boolean isSystemRoute();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int CONNECTION_STATE_CONNECTED = 2; // 0x2
field public static final int CONNECTION_STATE_CONNECTING = 1; // 0x1
@@ -31129,11 +31139,6 @@
field @Deprecated public static final String[] strings;
}
- @Deprecated public static class WifiConfiguration.SuiteBCipher {
- field @Deprecated public static final int ECDHE_ECDSA = 0; // 0x0
- field @Deprecated public static final int ECDHE_RSA = 1; // 0x1
- }
-
public class WifiEnterpriseConfig implements android.os.Parcelable {
ctor public WifiEnterpriseConfig();
ctor public WifiEnterpriseConfig(android.net.wifi.WifiEnterpriseConfig);
@@ -31616,6 +31621,7 @@
method public android.net.wifi.hotspot2.pps.Credential getCredential();
method public android.net.wifi.hotspot2.pps.HomeSp getHomeSp();
method public long getSubscriptionExpirationTimeInMillis();
+ method @NonNull public String getUniqueId() throws java.lang.IllegalStateException;
method public boolean isOsuProvisioned();
method public void setCredential(android.net.wifi.hotspot2.pps.Credential);
method public void setHomeSp(android.net.wifi.hotspot2.pps.HomeSp);
@@ -31796,8 +31802,8 @@
method public boolean isGroupOwner();
method public void writeToParcel(android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.net.wifi.p2p.WifiP2pGroup> CREATOR;
- field public static final int PERSISTENT_NET_ID = -2; // 0xfffffffe
- field public static final int TEMPORARY_NET_ID = -1; // 0xffffffff
+ field public static final int NETWORK_ID_PERSISTENT = -2; // 0xfffffffe
+ field public static final int NETWORK_ID_TEMPORARY = -1; // 0xffffffff
}
public class WifiP2pInfo implements android.os.Parcelable {
@@ -36944,7 +36950,7 @@
ctor public VibrationAttributes.Builder();
ctor public VibrationAttributes.Builder(@Nullable android.os.VibrationAttributes);
method @NonNull public android.os.VibrationAttributes build();
- method @NonNull public android.os.VibrationAttributes.Builder replaceFlags(int);
+ method @NonNull public android.os.VibrationAttributes.Builder setFlags(int, int);
method @NonNull public android.os.VibrationAttributes.Builder setUsage(int);
}
@@ -46381,7 +46387,6 @@
public final class BarringInfo implements android.os.Parcelable {
method public int describeContents();
method @NonNull public android.telephony.BarringInfo.BarringServiceInfo getBarringServiceInfo(int);
- method public boolean isServiceBarred(int);
method public void writeToParcel(@NonNull android.os.Parcel, int);
field public static final int BARRING_SERVICE_TYPE_CS_FALLBACK = 5; // 0x5
field public static final int BARRING_SERVICE_TYPE_CS_SERVICE = 0; // 0x0
@@ -54811,7 +54816,6 @@
method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
method public boolean requestFeature(int);
method @NonNull public final <T extends android.view.View> T requireViewById(@IdRes int);
- method public void resetOnContentApplyWindowInsetsListener();
method public abstract void restoreHierarchyState(android.os.Bundle);
method public abstract android.os.Bundle saveHierarchyState();
method public void setAllowEnterTransitionOverlap(boolean);
@@ -54829,6 +54833,7 @@
method public abstract void setContentView(android.view.View);
method public abstract void setContentView(android.view.View, android.view.ViewGroup.LayoutParams);
method public abstract void setDecorCaptionShade(int);
+ method public void setDecorFitsSystemWindows(boolean);
method protected void setDefaultWindowFormat(int);
method public void setDimAmount(float);
method public void setElevation(float);
@@ -54850,7 +54855,6 @@
method public abstract void setNavigationBarColor(@ColorInt int);
method public void setNavigationBarContrastEnforced(boolean);
method public void setNavigationBarDividerColor(@ColorInt int);
- method public void setOnContentApplyWindowInsetsListener(@Nullable android.view.Window.OnContentApplyWindowInsetsListener);
method public void setPreferMinimalPostProcessing(boolean);
method public void setReenterTransition(android.transition.Transition);
method public abstract void setResizingCaptionDrawable(android.graphics.drawable.Drawable);
@@ -54945,10 +54949,6 @@
method @Nullable public android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
}
- public static interface Window.OnContentApplyWindowInsetsListener {
- method @NonNull public android.util.Pair<android.graphics.Insets,android.view.WindowInsets> onContentApplyWindowInsets(@NonNull android.view.WindowInsets);
- }
-
public static interface Window.OnFrameMetricsAvailableListener {
method public void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
}
@@ -55099,16 +55099,13 @@
}
public interface WindowInsetsController {
- method public default void controlInputMethodAnimation(long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public void controlWindowInsetsAnimation(int, long, @Nullable android.view.animation.Interpolator, @NonNull android.view.WindowInsetsAnimationControlListener);
method public int getSystemBarsAppearance();
method public int getSystemBarsBehavior();
method public void hide(int);
- method public default void hideInputMethod();
method public void setSystemBarsAppearance(int, int);
method public void setSystemBarsBehavior(int);
method public void show(int);
- method public default void showInputMethod();
field public static final int APPEARANCE_LIGHT_NAVIGATION_BARS = 16; // 0x10
field public static final int APPEARANCE_LIGHT_STATUS_BARS = 8; // 0x8
field public static final int BEHAVIOR_SHOW_BARS_BY_SWIPE = 1; // 0x1
diff --git a/api/module-app-current.txt b/api/module-app-current.txt
index dadbd79..d802177 100644
--- a/api/module-app-current.txt
+++ b/api/module-app-current.txt
@@ -1,21 +1 @@
// Signature format: 2.0
-package android.app {
-
- public final class NotificationChannel implements android.os.Parcelable {
- method public void setBlockableSystem(boolean);
- }
-
-}
-
-package android.provider {
-
- public final class DocumentsContract {
- method @NonNull public static android.net.Uri buildDocumentUriAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
- }
-
- public static final class Settings.Global extends android.provider.Settings.NameValueTable {
- field public static final String COMMON_CRITERIA_MODE = "common_criteria_mode";
- }
-
-}
-
diff --git a/api/module-lib-current.txt b/api/module-lib-current.txt
index 1a2cb74..d11801b 100644
--- a/api/module-lib-current.txt
+++ b/api/module-lib-current.txt
@@ -6,7 +6,7 @@
method public void addDebugInfo(@NonNull java.util.List<java.lang.String>);
method public int describeContents();
method @NonNull public java.util.List<java.lang.String> getDebugInfo();
- method public int getPhoneId();
+ method public int getSlotIndex();
method @Nullable public android.os.TimestampedValue<java.lang.Long> getUtcTime();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.timedetector.PhoneTimeSuggestion> CREATOR;
@@ -34,8 +34,8 @@
method public int describeContents();
method @NonNull public java.util.List<java.lang.String> getDebugInfo();
method public int getMatchType();
- method public int getPhoneId();
method public int getQuality();
+ method public int getSlotIndex();
method @Nullable public String getZoneId();
method public void writeToParcel(@NonNull android.os.Parcel, int);
field @NonNull public static final android.os.Parcelable.Creator<android.app.timezonedetector.PhoneTimeZoneSuggestion> CREATOR;
diff --git a/api/system-current.txt b/api/system-current.txt
index 0930f68..3548b6c 100755
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -665,6 +665,7 @@
method public int getUserLockedFields();
method public boolean isDeleted();
method public void populateFromXml(org.xmlpull.v1.XmlPullParser);
+ method public void setBlockableSystem(boolean);
method public org.json.JSONObject toJson() throws org.json.JSONException;
method public void writeXml(org.xmlpull.v1.XmlSerializer) throws java.io.IOException;
field public static final int USER_LOCKED_SOUND = 32; // 0x20
@@ -1482,8 +1483,9 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public long getDiscoveryEndMillis();
method public boolean isBleScanAlwaysAvailable();
method public boolean isLeEnabled();
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeActiveDevice(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean removeOnMetadataChangedListener(@NonNull android.bluetooth.BluetoothDevice, @NonNull android.bluetooth.BluetoothAdapter.OnMetadataChangedListener);
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setActiveDevice(@Nullable android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setActiveDevice(@NonNull android.bluetooth.BluetoothDevice, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int, int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setScanMode(int);
field public static final String ACTION_BLE_STATE_CHANGED = "android.bluetooth.adapter.action.BLE_STATE_CHANGED";
@@ -1556,7 +1558,7 @@
method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean isEncrypted();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean isInSilenceMode();
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean removeBond();
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH) public boolean setAlias(@NonNull String);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setAlias(@NonNull String);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMessageAccessPermission(int);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setMetadata(int, @NonNull byte[]);
method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setPhonebookAccessPermission(int);
@@ -1604,7 +1606,7 @@
}
public final class BluetoothHidDevice implements android.bluetooth.BluetoothProfile {
- method @RequiresPermission(android.Manifest.permission.BLUETOOTH_ADMIN) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
+ method @RequiresPermission(android.Manifest.permission.BLUETOOTH_PRIVILEGED) public boolean setConnectionPolicy(@NonNull android.bluetooth.BluetoothDevice, int);
}
public final class BluetoothHidHost implements android.bluetooth.BluetoothProfile {
@@ -4104,7 +4106,6 @@
public class Location implements android.os.Parcelable {
method public boolean isComplete();
method public void makeComplete();
- method public void setExtraLocation(@Nullable String, @Nullable android.location.Location);
method public void setIsFromMockProvider(boolean);
field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
}
@@ -6233,7 +6234,7 @@
}
public abstract class NetworkAgent {
- ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, int, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
+ ctor public NetworkAgent(@NonNull android.content.Context, @NonNull android.os.Looper, @NonNull String, @NonNull android.net.NetworkCapabilities, @NonNull android.net.LinkProperties, @NonNull android.net.NetworkScore, @NonNull android.net.NetworkAgentConfig, @Nullable android.net.NetworkProvider);
method @Nullable public android.net.Network getNetwork();
method public void onAddKeepalivePacketFilter(int, @NonNull android.net.KeepalivePacketData);
method public void onAutomaticReconnectDisabled();
@@ -6248,7 +6249,7 @@
method @NonNull public android.net.Network register();
method public void sendLinkProperties(@NonNull android.net.LinkProperties);
method public void sendNetworkCapabilities(@NonNull android.net.NetworkCapabilities);
- method public void sendNetworkScore(int);
+ method public void sendNetworkScore(@NonNull android.net.NetworkScore);
method public void sendSocketKeepaliveEvent(int, int);
method public void setConnected();
method @Deprecated public void setLegacyExtraInfo(@Nullable String);
@@ -6351,6 +6352,55 @@
method @NonNull @RequiresPermission(android.Manifest.permission.NETWORK_SIGNAL_STRENGTH_WAKEUP) public android.net.NetworkRequest.Builder setSignalStrength(int);
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.NetworkScore.Metrics getEndToEndMetrics();
+ method @NonNull public android.net.NetworkScore.Metrics getLinkLayerMetrics();
+ method public int getRange();
+ method @IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) public int getSignalStrength();
+ method public boolean hasPolicy(int);
+ method public boolean isExiting();
+ method @NonNull public android.net.NetworkScore withExiting(boolean);
+ method @NonNull public android.net.NetworkScore withSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH) int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ field public static final int MAX_SIGNAL_STRENGTH = 1000; // 0x3e8
+ field public static final int MIN_SIGNAL_STRENGTH = 0; // 0x0
+ field public static final int POLICY_DEFAULT_SUBSCRIPTION = 8; // 0x8
+ field public static final int POLICY_IGNORE_ON_WIFI = 4; // 0x4
+ field public static final int POLICY_LOCKDOWN_VPN = 1; // 0x1
+ field public static final int POLICY_VPN = 2; // 0x2
+ field public static final int RANGE_CLOSE = 1; // 0x1
+ field public static final int RANGE_LONG = 4; // 0x4
+ field public static final int RANGE_MEDIUM = 3; // 0x3
+ field public static final int RANGE_SHORT = 2; // 0x2
+ field public static final int RANGE_UNKNOWN = 0; // 0x0
+ field public static final int UNKNOWN_SIGNAL_STRENGTH = -1; // 0xffffffff
+ }
+
+ public static class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore.Builder addPolicy(int);
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder clearPolicy(int);
+ method @NonNull public android.net.NetworkScore.Builder setEndToEndMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
+ method @NonNull public android.net.NetworkScore.Builder setLegacyScore(int);
+ method @NonNull public android.net.NetworkScore.Builder setLinkLayerMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setRange(int);
+ method @NonNull public android.net.NetworkScore.Builder setSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) int);
+ }
+
+ public static class NetworkScore.Metrics {
+ ctor public NetworkScore.Metrics(@IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int);
+ field public static final int BANDWIDTH_UNKNOWN = -1; // 0xffffffff
+ field @NonNull public static final android.net.NetworkScore.Metrics EMPTY;
+ field public static final int LATENCY_UNKNOWN = -1; // 0xffffffff
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int downlinkBandwidthKBps;
+ field @IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) public final int latencyMs;
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int uplinkBandwidthKBps;
+ }
+
public class NetworkScoreManager {
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public boolean clearScores() throws java.lang.SecurityException;
method @RequiresPermission(anyOf={android.Manifest.permission.SCORE_NETWORKS, android.Manifest.permission.REQUEST_NETWORK_SCORES}) public void disableScoring() throws java.lang.SecurityException;
@@ -7465,6 +7515,7 @@
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus getNetworkSelectionStatus();
method @Deprecated @NonNull public String getPrintableSsid();
method @Deprecated @NonNull public android.net.IpConfiguration.ProxySettings getProxySettings();
+ method @Deprecated public int getRecentFailureReason();
method @Deprecated @Nullable public android.net.StaticIpConfiguration getStaticIpConfiguration();
method @Deprecated public boolean hasNoInternetAccess();
method @Deprecated public boolean isEphemeral();
@@ -7482,6 +7533,8 @@
field @Deprecated public static final int METERED_OVERRIDE_NOT_METERED = 2; // 0x2
field @Deprecated public static final int RANDOMIZATION_NONE = 0; // 0x0
field @Deprecated public static final int RANDOMIZATION_PERSISTENT = 1; // 0x1
+ field @Deprecated public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
+ field @Deprecated public static final int RECENT_FAILURE_NONE = 0; // 0x0
field @Deprecated public boolean allowAutojoin;
field @Deprecated public int apBand;
field @Deprecated public int carrierId;
@@ -7497,7 +7550,6 @@
field @Deprecated public int numAssociation;
field @Deprecated public int numScorerOverride;
field @Deprecated public int numScorerOverrideAndSwitchedNetwork;
- field @Deprecated @NonNull public final android.net.wifi.WifiConfiguration.RecentFailure recentFailure;
field @Deprecated public boolean requirePMF;
field @Deprecated @Nullable public String saePasswordId;
field @Deprecated public boolean shared;
@@ -7543,12 +7595,6 @@
method @Deprecated @NonNull public android.net.wifi.WifiConfiguration.NetworkSelectionStatus.Builder setNetworkSelectionStatus(int);
}
- @Deprecated public static class WifiConfiguration.RecentFailure {
- method @Deprecated public int getAssociationStatus();
- field @Deprecated public static final int NONE = 0; // 0x0
- field @Deprecated public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17; // 0x11
- }
-
public class WifiEnterpriseConfig implements android.os.Parcelable {
method @Nullable public String[] getCaCertificateAliases();
method @NonNull public String getCaPath();
@@ -9124,7 +9170,12 @@
method @WorkerThread public void allocateBytes(java.io.FileDescriptor, long, @RequiresPermission int) throws java.io.IOException;
method @WorkerThread public long getAllocatableBytes(@NonNull java.util.UUID, @RequiresPermission int) throws java.io.IOException;
method public static boolean hasIsolatedStorage();
+ method public void updateExternalStorageFileQuotaType(@NonNull java.io.File, int) throws java.io.IOException;
field @RequiresPermission(android.Manifest.permission.ALLOCATE_AGGRESSIVE) public static final int FLAG_ALLOCATE_AGGRESSIVE = 1; // 0x1
+ field public static final int QUOTA_TYPE_MEDIA_AUDIO = 2; // 0x2
+ field public static final int QUOTA_TYPE_MEDIA_IMAGE = 1; // 0x1
+ field public static final int QUOTA_TYPE_MEDIA_NONE = 0; // 0x0
+ field public static final int QUOTA_TYPE_MEDIA_VIDEO = 3; // 0x3
}
public final class StorageVolume implements android.os.Parcelable {
@@ -9410,6 +9461,7 @@
}
public final class DocumentsContract {
+ method @NonNull public static android.net.Uri buildDocumentUriAsUser(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
method public static boolean isManageMode(@NonNull android.net.Uri);
method @NonNull public static android.net.Uri setManageMode(@NonNull android.net.Uri);
field public static final String ACTION_DOCUMENT_ROOT_SETTINGS = "android.provider.action.DOCUMENT_ROOT_SETTINGS";
@@ -9570,6 +9622,7 @@
field public static final String AUTOFILL_COMPAT_MODE_ALLOWED_PACKAGES = "autofill_compat_mode_allowed_packages";
field public static final String CARRIER_APP_NAMES = "carrier_app_names";
field public static final String CARRIER_APP_WHITELIST = "carrier_app_whitelist";
+ field public static final String COMMON_CRITERIA_MODE = "common_criteria_mode";
field public static final String DEFAULT_SM_DP_PLUS = "default_sm_dp_plus";
field public static final String DEVICE_DEMO_MODE = "device_demo_mode";
field public static final String DEVICE_PROVISIONING_MOBILE_DATA_ENABLED = "device_provisioning_mobile_data";
@@ -10062,6 +10115,7 @@
ctor public AugmentedAutofillService();
method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]);
+ method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
method public void onConnected();
method public void onDisconnected();
method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback);
@@ -10091,6 +10145,7 @@
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.augmented.FillResponse build();
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
}
diff --git a/api/test-current.txt b/api/test-current.txt
index e0b5b34..fda3ab4 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -1271,7 +1271,6 @@
public class Location implements android.os.Parcelable {
method public void makeComplete();
- method public void setExtraLocation(@Nullable String, @Nullable android.location.Location);
field public static final String EXTRA_NO_GPS_LOCATION = "noGPSLocation";
}
@@ -1387,6 +1386,10 @@
method public int getMaxMacroBlocks();
}
+ public final class MediaRoute2Info implements android.os.Parcelable {
+ method @NonNull public String getOriginalId();
+ }
+
public final class PlaybackParams implements android.os.Parcelable {
method public int getAudioStretchMode();
method public android.media.PlaybackParams setAudioStretchMode(int);
@@ -1688,6 +1691,55 @@
field public static final int TRANSPORT_TEST = 7; // 0x7
}
+ public final class NetworkScore implements android.os.Parcelable {
+ method public int describeContents();
+ method @NonNull public android.net.NetworkScore.Metrics getEndToEndMetrics();
+ method @NonNull public android.net.NetworkScore.Metrics getLinkLayerMetrics();
+ method public int getRange();
+ method @IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) public int getSignalStrength();
+ method public boolean hasPolicy(int);
+ method public boolean isExiting();
+ method @NonNull public android.net.NetworkScore withExiting(boolean);
+ method @NonNull public android.net.NetworkScore withSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH) int);
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.net.NetworkScore> CREATOR;
+ field public static final int MAX_SIGNAL_STRENGTH = 1000; // 0x3e8
+ field public static final int MIN_SIGNAL_STRENGTH = 0; // 0x0
+ field public static final int POLICY_DEFAULT_SUBSCRIPTION = 8; // 0x8
+ field public static final int POLICY_IGNORE_ON_WIFI = 4; // 0x4
+ field public static final int POLICY_LOCKDOWN_VPN = 1; // 0x1
+ field public static final int POLICY_VPN = 2; // 0x2
+ field public static final int RANGE_CLOSE = 1; // 0x1
+ field public static final int RANGE_LONG = 4; // 0x4
+ field public static final int RANGE_MEDIUM = 3; // 0x3
+ field public static final int RANGE_SHORT = 2; // 0x2
+ field public static final int RANGE_UNKNOWN = 0; // 0x0
+ field public static final int UNKNOWN_SIGNAL_STRENGTH = -1; // 0xffffffff
+ }
+
+ public static class NetworkScore.Builder {
+ ctor public NetworkScore.Builder();
+ method @NonNull public android.net.NetworkScore.Builder addPolicy(int);
+ method @NonNull public android.net.NetworkScore build();
+ method @NonNull public android.net.NetworkScore.Builder clearPolicy(int);
+ method @NonNull public android.net.NetworkScore.Builder setEndToEndMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setExiting(boolean);
+ method @NonNull public android.net.NetworkScore.Builder setLegacyScore(int);
+ method @NonNull public android.net.NetworkScore.Builder setLinkLayerMetrics(@NonNull android.net.NetworkScore.Metrics);
+ method @NonNull public android.net.NetworkScore.Builder setRange(int);
+ method @NonNull public android.net.NetworkScore.Builder setSignalStrength(@IntRange(from=android.net.NetworkScore.UNKNOWN_SIGNAL_STRENGTH, to=android.net.NetworkScore.MAX_SIGNAL_STRENGTH) int);
+ }
+
+ public static class NetworkScore.Metrics {
+ ctor public NetworkScore.Metrics(@IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int, @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) int);
+ field public static final int BANDWIDTH_UNKNOWN = -1; // 0xffffffff
+ field @NonNull public static final android.net.NetworkScore.Metrics EMPTY;
+ field public static final int LATENCY_UNKNOWN = -1; // 0xffffffff
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int downlinkBandwidthKBps;
+ field @IntRange(from=android.net.NetworkScore.Metrics.LATENCY_UNKNOWN) public final int latencyMs;
+ field @IntRange(from=android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN) public final int uplinkBandwidthKBps;
+ }
+
public class NetworkStack {
field public static final String PERMISSION_MAINLINE_NETWORK_STACK = "android.permission.MAINLINE_NETWORK_STACK";
}
@@ -3052,6 +3104,7 @@
ctor public AugmentedAutofillService();
method protected final void dump(java.io.FileDescriptor, java.io.PrintWriter, String[]);
method protected void dump(@NonNull java.io.PrintWriter, @NonNull String[]);
+ method @Nullable public final android.service.autofill.FillEventHistory getFillEventHistory();
method public void onConnected();
method public void onDisconnected();
method public void onFillRequest(@NonNull android.service.autofill.augmented.FillRequest, @NonNull android.os.CancellationSignal, @NonNull android.service.autofill.augmented.FillController, @NonNull android.service.autofill.augmented.FillCallback);
@@ -3081,6 +3134,7 @@
public static final class FillResponse.Builder {
ctor public FillResponse.Builder();
method @NonNull public android.service.autofill.augmented.FillResponse build();
+ method @NonNull public android.service.autofill.augmented.FillResponse.Builder setClientState(@Nullable android.os.Bundle);
method @NonNull public android.service.autofill.augmented.FillResponse.Builder setFillWindow(@Nullable android.service.autofill.augmented.FillWindow);
method @NonNull public android.service.autofill.augmented.FillResponse.Builder setInlineSuggestions(@Nullable java.util.List<android.service.autofill.Dataset>);
}
diff --git a/cmds/statsd/Android.bp b/cmds/statsd/Android.bp
index fdc7fce..2237bf2 100644
--- a/cmds/statsd/Android.bp
+++ b/cmds/statsd/Android.bp
@@ -66,13 +66,11 @@
"src/config/ConfigManager.cpp",
"src/external/GpuStatsPuller.cpp",
"src/external/Perfetto.cpp",
- "src/external/PowerStatsPuller.cpp",
"src/external/PullResultReceiver.cpp",
"src/external/puller_util.cpp",
"src/external/StatsCallbackPuller.cpp",
"src/external/StatsPuller.cpp",
"src/external/StatsPullerManager.cpp",
- "src/external/SubsystemSleepStatePuller.cpp",
"src/external/TrainInfoPuller.cpp",
"src/FieldValue.cpp",
"src/guardrail/StatsdStats.cpp",
@@ -121,13 +119,9 @@
static_libs: [
"android.frameworks.stats@1.0",
- "android.hardware.power.stats@1.0",
- "android.hardware.power@1.0",
- "android.hardware.power@1.1",
"libbase",
"libcutils",
"liblog",
- "libplatformprotos",
"libprotoutil",
"libstatslog",
"libstatssocket",
diff --git a/cmds/statsd/benchmark/log_event_benchmark.cpp b/cmds/statsd/benchmark/log_event_benchmark.cpp
index bdfdb2e..30dfe32 100644
--- a/cmds/statsd/benchmark/log_event_benchmark.cpp
+++ b/cmds/statsd/benchmark/log_event_benchmark.cpp
@@ -39,7 +39,7 @@
uint8_t msg[LOGGER_ENTRY_MAX_PAYLOAD];
size_t size = createAndParseStatsEvent(msg);
while (state.KeepRunning()) {
- benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000));
+ benchmark::DoNotOptimize(LogEvent(msg, size, /*uid=*/ 1000, /*pid=*/ 1001));
}
}
BENCHMARK(BM_LogEventCreation);
diff --git a/cmds/statsd/src/HashableDimensionKey.cpp b/cmds/statsd/src/HashableDimensionKey.cpp
index 109785f..5b75b97 100644
--- a/cmds/statsd/src/HashableDimensionKey.cpp
+++ b/cmds/statsd/src/HashableDimensionKey.cpp
@@ -16,8 +16,6 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include <mutex>
-
#include "HashableDimensionKey.h"
#include "FieldValue.h"
diff --git a/cmds/statsd/src/StatsLogProcessor.cpp b/cmds/statsd/src/StatsLogProcessor.cpp
index 3481814..879b3c3 100644
--- a/cmds/statsd/src/StatsLogProcessor.cpp
+++ b/cmds/statsd/src/StatsLogProcessor.cpp
@@ -20,11 +20,7 @@
#include "StatsLogProcessor.h"
#include <android-base/file.h>
-#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
-#include <log/log_event_list.h>
-#include <utils/Errors.h>
-#include <utils/SystemClock.h>
#include "android-base/stringprintf.h"
#include "atoms_info.h"
@@ -47,8 +43,6 @@
using android::util::FIELD_TYPE_MESSAGE;
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
-using std::make_unique;
-using std::unique_ptr;
using std::vector;
namespace android {
diff --git a/cmds/statsd/src/StatsService.cpp b/cmds/statsd/src/StatsService.cpp
index c1a8d69..8a8c1e6 100644
--- a/cmds/statsd/src/StatsService.cpp
+++ b/cmds/statsd/src/StatsService.cpp
@@ -27,13 +27,10 @@
#include "subscriber/SubscriberReporter.h"
#include <android-base/file.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <binder/IPCThreadState.h>
-#include <binder/IServiceManager.h>
#include <binder/PermissionController.h>
#include <cutils/multiuser.h>
-#include <dirent.h>
#include <frameworks/base/cmds/statsd/src/statsd_config.pb.h>
#include <frameworks/base/cmds/statsd/src/uid_data.pb.h>
#include <private/android_filesystem_config.h>
@@ -42,17 +39,13 @@
#include <stdlib.h>
#include <sys/system_properties.h>
#include <unistd.h>
-#include <utils/Looper.h>
#include <utils/String16.h>
-#include <chrono>
using namespace android;
using android::base::StringPrintf;
using android::util::FIELD_COUNT_REPEATED;
-using android::util::FIELD_TYPE_INT64;
using android::util::FIELD_TYPE_MESSAGE;
-using android::util::ProtoReader;
namespace android {
namespace os {
@@ -77,6 +70,25 @@
return binder::Status::fromExceptionCode(code, String8(msg.c_str()));
}
+
+static bool checkPermission(const char* permission) {
+ sp<IStatsCompanionService> scs = getStatsCompanionService();
+ if (scs == nullptr) {
+ return false;
+ }
+
+ bool success;
+ pid_t pid = IPCThreadState::self()->getCallingPid();
+ uid_t uid = IPCThreadState::self()->getCallingUid();
+
+ binder::Status status = scs->checkPermission(String16(permission), pid, uid, &success);
+ if (!status.isOk()) {
+ return false;
+ }
+ return success;
+}
+
+
binder::Status checkUid(uid_t expectedUid) {
uid_t uid = IPCThreadState::self()->getCallingUid();
if (uid == expectedUid || uid == AID_ROOT) {
@@ -97,11 +109,11 @@
}
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, kPermissionUsage));
}
@@ -285,7 +297,7 @@
* TODO: Come up with a more robust method of enacting <serviceutils/PriorityDumper.h>.
*/
status_t StatsService::dump(int fd, const Vector<String16>& args) {
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return PERMISSION_DENIED;
}
int lastArg = args.size() - 1;
@@ -914,7 +926,7 @@
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_clear_puller_cache with Pid %i, Uid %i",
ipc->getCallingPid(), ipc->getCallingUid());
- if (checkCallingPermission(String16(kPermissionDump))) {
+ if (checkPermission(kPermissionDump)) {
int cleared = mPullerManager->ForceClearPullerCache();
dprintf(out, "Puller removed %d cached data!\n", cleared);
return NO_ERROR;
@@ -927,7 +939,7 @@
IPCThreadState* ipc = IPCThreadState::self();
VLOG("StatsService::cmd_print_logs with Pid %i, Uid %i", ipc->getCallingPid(),
ipc->getCallingUid());
- if (checkCallingPermission(String16(kPermissionDump))) {
+ if (checkPermission(kPermissionDump)) {
bool enabled = true;
if (args.size() >= 2) {
enabled = atoi(args[1].c_str()) != 0;
@@ -1314,12 +1326,12 @@
// Root, system, and shell always have access
if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionUsage));
@@ -1410,12 +1422,12 @@
// Root, system, and shell always have access
if (uid != AID_ROOT && uid != AID_SYSTEM && uid != AID_SHELL) {
// Caller must be granted these permissions
- if (!checkCallingPermission(String16(kPermissionDump))) {
+ if (!checkPermission(kPermissionDump)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionDump));
}
- if (!checkCallingPermission(String16(kPermissionUsage))) {
+ if (!checkPermission(kPermissionUsage)) {
return exception(binder::Status::EX_SECURITY,
StringPrintf("UID %d / PID %d lacks permission %s", uid, pid,
kPermissionUsage));
diff --git a/cmds/statsd/src/StatsService.h b/cmds/statsd/src/StatsService.h
index f2079d9..3bfaa98 100644
--- a/cmds/statsd/src/StatsService.h
+++ b/cmds/statsd/src/StatsService.h
@@ -37,11 +37,9 @@
#include <binder/ParcelFileDescriptor.h>
#include <utils/Looper.h>
-#include <deque>
#include <mutex>
using namespace android;
-using namespace android::base;
using namespace android::binder;
using namespace android::frameworks::stats::V1_0;
using namespace android::os;
diff --git a/cmds/statsd/src/anomaly/AlarmMonitor.h b/cmds/statsd/src/anomaly/AlarmMonitor.h
index bca858e..219695e 100644
--- a/cmds/statsd/src/anomaly/AlarmMonitor.h
+++ b/cmds/statsd/src/anomaly/AlarmMonitor.h
@@ -21,8 +21,6 @@
#include <android/os/IStatsCompanionService.h>
#include <utils/RefBase.h>
-#include <queue>
-#include <set>
#include <unordered_set>
#include <vector>
diff --git a/cmds/statsd/src/anomaly/AnomalyTracker.h b/cmds/statsd/src/anomaly/AnomalyTracker.h
index e941473..794ee98 100644
--- a/cmds/statsd/src/anomaly/AnomalyTracker.h
+++ b/cmds/statsd/src/anomaly/AnomalyTracker.h
@@ -16,8 +16,6 @@
#pragma once
-#include <memory> // unique_ptr
-
#include <stdlib.h>
#include <gtest/gtest_prod.h>
diff --git a/cmds/statsd/src/anomaly/subscriber_util.cpp b/cmds/statsd/src/anomaly/subscriber_util.cpp
index 4c30c4c..5a4a41d 100644
--- a/cmds/statsd/src/anomaly/subscriber_util.cpp
+++ b/cmds/statsd/src/anomaly/subscriber_util.cpp
@@ -17,10 +17,6 @@
#define DEBUG false // STOPSHIP if true
#include "Log.h"
-#include <android/os/IIncidentManager.h>
-#include <android/os/IncidentReportArgs.h>
-#include <binder/IServiceManager.h>
-
#include "external/Perfetto.h"
#include "subscriber/IncidentdReporter.h"
#include "subscriber/SubscriberReporter.h"
diff --git a/cmds/statsd/src/atoms.proto b/cmds/statsd/src/atoms.proto
index d065401..12058ca 100644
--- a/cmds/statsd/src/atoms.proto
+++ b/cmds/statsd/src/atoms.proto
@@ -232,8 +232,8 @@
NfcCardemulationOccurred nfc_cardemulation_occurred = 137 [(module) = "nfc"];
NfcTagOccurred nfc_tag_occurred = 138 [(module) = "nfc"];
NfcHceTransactionOccurred nfc_hce_transaction_occurred = 139 [(module) = "nfc"];
- SeStateChanged se_state_changed = 140;
- SeOmapiReported se_omapi_reported = 141;
+ SeStateChanged se_state_changed = 140 [(module) = "secure_element"];
+ SeOmapiReported se_omapi_reported = 141 [(module) = "secure_element"];
BroadcastDispatchLatencyReported broadcast_dispatch_latency_reported =
142 [(module) = "framework"];
AttentionManagerServiceResultReported attention_manager_service_result_reported =
@@ -387,6 +387,9 @@
249 [(module) = "cellbroadcast"];
CellBroadcastMessageError cb_message_error =
250 [(module) = "cellbroadcast"];
+ WifiHealthStatReported wifi_health_stat_reported = 251 [(module) = "wifi"];
+ WifiFailureStatReported wifi_failure_stat_reported = 252 [(module) = "wifi"];
+ WifiConnectionResultReported wifi_connection_result_reported = 253 [(module) = "wifi"];
}
// Pulled events will start at field 10000.
@@ -658,6 +661,81 @@
}
/**
+ * Logs the change in wifi health.
+ *
+ * Logged from:
+ * frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiDataStall.java
+ */
+message WifiHealthStatReported {
+ // duration this stat is obtained over in milliseconds
+ optional int32 duration_millis = 1;
+ // whether wifi is classified as sufficient for the user's data traffic, determined
+ // by whether the calculated throughput exceeds the average demand within |duration_millis|
+ optional bool is_sufficient = 2;
+ // whether the calculated throughput is exceeds the minimum required for typical usage
+ optional bool is_throughput_good = 3;
+ // whether cellular data is available
+ optional bool is_cell_data_available = 4;
+ // the WLAN channel the connected network is on (ie. 2412)
+ optional int32 frequency = 5;
+}
+
+/**
+ * Logged when wifi detects a significant change in connection failure rate.
+ *
+ * Logged from: frameworks/opt/net/wifi/service/java/com/android/server/wifi/WifiHealthMonitor.java
+ *
+ */
+message WifiFailureStatReported {
+ enum AbnormalityType {
+ UNKNOWN = 0;
+ SIGNIFICANT_INCREASE = 1;
+ SIGNIFICANT_DECREASE = 2;
+ SIMPLY_HIGH = 3;
+ }
+ enum FailureType {
+ FAILURE_UNKNOWN = 0;
+ FAILURE_CONNECTION = 1;
+ FAILURE_ASSOCIATION_REJECTION = 2;
+ FAILURE_ASSOCIATION_TIMEOUT = 3;
+ FAILURE_AUTHENTICATION = 4;
+ FAILURE_NON_LOCAL_DISCONNECTION = 5;
+ FAILURE_SHORT_CONNECTION_DUE_TO_NON_LOCAL_DISCONNECTION = 6;
+ }
+ // Reason for uploading this stat
+ optional AbnormalityType abnormality_type = 1;
+ // The particular type of failure
+ optional FailureType failure_type = 2;
+ // How many times we have encountered this combination of AbnormalityType and FailureType
+ optional int32 failure_count = 3;
+}
+
+/**
+ * Logs whether a wifi connection is successful and reasons for failure if it isn't.
+ *
+ * Logged from:
+ * frameworks/opt/net/wifi/service/java/com/android/server/wifi/ClientModeImpl.java
+ */
+message WifiConnectionResultReported {
+ enum FailureCode {
+ FAILURE_UNKNOWN = 0;
+ FAILURE_ASSOCIATION_TIMEOUT = 1;
+ FAILURE_ASSOCIATION_REJECTION = 2;
+ FAILURE_AUTHENTICATION_GENERAL = 3;
+ FAILURE_AUTHENTICATION_EAP = 4;
+ FAILURE_DHCP = 5;
+ FAILURE_NETWORK_DISCONNECTION = 6;
+ FAILURE_ROAM_TIMEOUT = 7;
+ }
+ // true represents a successful connection
+ optional bool connection_result = 1;
+ // reason for the connection failure
+ optional FailureCode failure_code = 2;
+ // scan rssi before the connection attempt
+ optional int32 rssi = 3;
+}
+
+/**
* Logs when memory stats of a process is reported.
*
* Logged from:
diff --git a/cmds/statsd/src/condition/CombinationConditionTracker.cpp b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
index 69aae3d..2d7f912 100644
--- a/cmds/statsd/src/condition/CombinationConditionTracker.cpp
+++ b/cmds/statsd/src/condition/CombinationConditionTracker.cpp
@@ -18,15 +18,10 @@
#include "Log.h"
#include "CombinationConditionTracker.h"
-#include <log/logprint.h>
-
namespace android {
namespace os {
namespace statsd {
-using std::map;
-using std::string;
-using std::unique_ptr;
using std::unordered_map;
using std::vector;
diff --git a/cmds/statsd/src/condition/ConditionTracker.h b/cmds/statsd/src/condition/ConditionTracker.h
index e94ea65..26de888 100644
--- a/cmds/statsd/src/condition/ConditionTracker.h
+++ b/cmds/statsd/src/condition/ConditionTracker.h
@@ -21,10 +21,8 @@
#include "matchers/LogMatchingTracker.h"
#include "matchers/matcher_util.h"
-#include <log/logprint.h>
#include <utils/RefBase.h>
-#include <unordered_set>
#include <unordered_map>
namespace android {
diff --git a/cmds/statsd/src/condition/ConditionWizard.cpp b/cmds/statsd/src/condition/ConditionWizard.cpp
index 4f44a69..c542032 100644
--- a/cmds/statsd/src/condition/ConditionWizard.cpp
+++ b/cmds/statsd/src/condition/ConditionWizard.cpp
@@ -14,14 +14,11 @@
* limitations under the License.
*/
#include "ConditionWizard.h"
-#include <unordered_set>
namespace android {
namespace os {
namespace statsd {
-using std::map;
-using std::string;
using std::vector;
ConditionState ConditionWizard::query(const int index, const ConditionKey& parameters,
diff --git a/cmds/statsd/src/condition/SimpleConditionTracker.cpp b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
index 0c92149..61760f3 100644
--- a/cmds/statsd/src/condition/SimpleConditionTracker.cpp
+++ b/cmds/statsd/src/condition/SimpleConditionTracker.cpp
@@ -24,11 +24,7 @@
namespace os {
namespace statsd {
-using std::map;
-using std::string;
-using std::unique_ptr;
using std::unordered_map;
-using std::vector;
SimpleConditionTracker::SimpleConditionTracker(
const ConfigKey& key, const int64_t& id, const int index,
diff --git a/cmds/statsd/src/condition/StateConditionTracker.cpp b/cmds/statsd/src/condition/StateConditionTracker.cpp
index 7f3eedd..d19a176 100644
--- a/cmds/statsd/src/condition/StateConditionTracker.cpp
+++ b/cmds/statsd/src/condition/StateConditionTracker.cpp
@@ -23,8 +23,6 @@
namespace os {
namespace statsd {
-using std::string;
-using std::unordered_set;
using std::vector;
StateConditionTracker::StateConditionTracker(const ConfigKey& key, const int64_t& id, const int index,
diff --git a/cmds/statsd/src/condition/condition_util.cpp b/cmds/statsd/src/condition/condition_util.cpp
index 35e03e4..60b8c53 100644
--- a/cmds/statsd/src/condition/condition_util.cpp
+++ b/cmds/statsd/src/condition/condition_util.cpp
@@ -18,11 +18,6 @@
#include "condition_util.h"
-#include <log/event_tag_map.h>
-#include <log/log_event_list.h>
-#include <log/logprint.h>
-#include <utils/Errors.h>
-#include <unordered_map>
#include "../matchers/matcher_util.h"
#include "ConditionTracker.h"
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
@@ -32,9 +27,6 @@
namespace os {
namespace statsd {
-using std::set;
-using std::string;
-using std::unordered_map;
using std::vector;
diff --git a/cmds/statsd/src/config/ConfigListener.h b/cmds/statsd/src/config/ConfigListener.h
index 54e7770..dcd5e52 100644
--- a/cmds/statsd/src/config/ConfigListener.h
+++ b/cmds/statsd/src/config/ConfigListener.h
@@ -19,14 +19,12 @@
#include "config/ConfigKey.h"
#include <utils/RefBase.h>
-#include <string>
namespace android {
namespace os {
namespace statsd {
using android::RefBase;
-using std::string;
/**
* Callback for different subsystems inside statsd to implement to find out
diff --git a/cmds/statsd/src/config/ConfigManager.cpp b/cmds/statsd/src/config/ConfigManager.cpp
index 972adf7..986955b 100644
--- a/cmds/statsd/src/config/ConfigManager.cpp
+++ b/cmds/statsd/src/config/ConfigManager.cpp
@@ -25,8 +25,6 @@
#include "stats_util.h"
#include "stats_log_util.h"
-#include <android-base/file.h>
-#include <dirent.h>
#include <stdio.h>
#include <vector>
#include "android-base/stringprintf.h"
@@ -35,9 +33,7 @@
namespace os {
namespace statsd {
-using std::map;
using std::pair;
-using std::set;
using std::string;
using std::vector;
diff --git a/cmds/statsd/src/config/ConfigManager.h b/cmds/statsd/src/config/ConfigManager.h
index 88e864a..2095173 100644
--- a/cmds/statsd/src/config/ConfigManager.h
+++ b/cmds/statsd/src/config/ConfigManager.h
@@ -20,9 +20,7 @@
#include "config/ConfigListener.h"
#include <android/os/IPendingIntentRef.h>
-#include <map>
#include <mutex>
-#include <set>
#include <string>
#include <stdio.h>
diff --git a/cmds/statsd/src/external/Perfetto.cpp b/cmds/statsd/src/external/Perfetto.cpp
index 0c4c330..85b660e 100644
--- a/cmds/statsd/src/external/Perfetto.cpp
+++ b/cmds/statsd/src/external/Perfetto.cpp
@@ -21,12 +21,8 @@
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h" // Alert
#include <android-base/unique_fd.h>
-#include <errno.h>
-#include <fcntl.h>
#include <inttypes.h>
-#include <sys/types.h>
#include <sys/wait.h>
-#include <unistd.h>
#include <string>
diff --git a/cmds/statsd/src/external/PowerStatsPuller.cpp b/cmds/statsd/src/external/PowerStatsPuller.cpp
deleted file mode 100644
index dc69b78..0000000
--- a/cmds/statsd/src/external/PowerStatsPuller.cpp
+++ /dev/null
@@ -1,170 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <android/hardware/power/stats/1.0/IPowerStats.h>
-
-#include <vector>
-
-#include "PowerStatsPuller.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using android::hardware::hidl_vec;
-using android::hardware::power::stats::V1_0::IPowerStats;
-using android::hardware::power::stats::V1_0::EnergyData;
-using android::hardware::power::stats::V1_0::RailInfo;
-using android::hardware::power::stats::V1_0::Status;
-using android::hardware::Return;
-using android::hardware::Void;
-
-using std::make_shared;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
-static std::mutex gPowerStatsHalMutex;
-static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
-static std::vector<RailInfo> gRailInfo;
-
-struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override {
- // The HAL just died. Reset all handles to HAL services.
- std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
- gPowerStatsHal = nullptr;
- }
-};
-
-static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
-
-static bool getPowerStatsHalLocked() {
- if (gPowerStatsHal == nullptr && gPowerStatsExist) {
- gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
- if (gPowerStatsHal == nullptr) {
- ALOGW("Couldn't load power.stats HAL service");
- gPowerStatsExist = false;
- } else {
- // Link death recipient to power.stats service handle
- hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power.stats HAL death: %s",
- linked.description().c_str());
- gPowerStatsHal = nullptr;
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power.stats HAL death notifications");
- // We should still continue even though linking failed
- }
- }
- }
- return gPowerStatsHal != nullptr;
-}
-
-PowerStatsPuller::PowerStatsPuller() : StatsPuller(android::util::ON_DEVICE_POWER_MEASUREMENT) {
-}
-
-bool PowerStatsPuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
-
- if (!getPowerStatsHalLocked()) {
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
-
- data->clear();
-
- // Pull getRailInfo if necessary
- if (gRailInfo.empty()) {
- bool resultSuccess = true;
- Return<void> ret = gPowerStatsHal->getRailInfo(
- [&resultSuccess](const hidl_vec<RailInfo> &list, Status status) {
- resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
- if (status != Status::SUCCESS) return;
-
- gRailInfo.reserve(list.size());
- for (size_t i = 0; i < list.size(); ++i) {
- gRailInfo.push_back(list[i]);
- }
- });
- if (!resultSuccess || !ret.isOk()) {
- ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
- gPowerStatsHal = nullptr;
- return false;
- }
- // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
- if (gRailInfo.empty()) {
- ALOGE("power.stats has no rail information");
- gPowerStatsExist = false; // No rail info, so never try again.
- gPowerStatsHal = nullptr;
- return false;
- }
- }
-
- // Pull getEnergyData and write the data out
- const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
- bool resultSuccess = true;
- Return<void> ret = gPowerStatsHal->getEnergyData(desiredRailIndices,
- [&data, wallClockTimestampNs, elapsedTimestampNs, &resultSuccess]
- (hidl_vec<EnergyData> energyDataList, Status status) {
- resultSuccess = (status == Status::SUCCESS);
- if (!resultSuccess) return;
-
- for (size_t i = 0; i < energyDataList.size(); i++) {
- const EnergyData& energyData = energyDataList[i];
-
- if (energyData.index >= gRailInfo.size()) {
- ALOGE("power.stats getEnergyData() returned an invalid rail index %u.",
- energyData.index);
- resultSuccess = false;
- return;
- }
- const RailInfo& rail = gRailInfo[energyData.index];
-
- auto ptr = make_shared<LogEvent>(android::util::ON_DEVICE_POWER_MEASUREMENT,
- wallClockTimestampNs, elapsedTimestampNs);
- ptr->write(rail.subsysName);
- ptr->write(rail.railName);
- ptr->write(energyData.timestamp);
- ptr->write(energyData.energy);
- ptr->init();
- data->push_back(ptr);
-
- VLOG("power.stat: %s.%s: %llu, %llu",
- rail.subsysName.c_str(),
- rail.railName.c_str(),
- (unsigned long long)energyData.timestamp,
- (unsigned long long)energyData.energy);
- }
- });
- if (!resultSuccess || !ret.isOk()) {
- ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
- gPowerStatsHal = nullptr;
- return false;
- }
- return true;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/external/PullDataReceiver.h b/cmds/statsd/src/external/PullDataReceiver.h
index d2193f4..dd5c0cf 100644
--- a/cmds/statsd/src/external/PullDataReceiver.h
+++ b/cmds/statsd/src/external/PullDataReceiver.h
@@ -15,8 +15,6 @@
*/
#pragma once
-#include <utils/String16.h>
-#include <unordered_map>
#include <utils/RefBase.h>
#include "StatsPuller.h"
#include "logd/LogEvent.h"
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.cpp b/cmds/statsd/src/external/StatsCallbackPuller.cpp
index 6257771..1a11f0e 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.cpp
+++ b/cmds/statsd/src/external/StatsCallbackPuller.cpp
@@ -68,7 +68,7 @@
for (const StatsEventParcel& parcel: output) {
shared_ptr<LogEvent> event = make_shared<LogEvent>(
const_cast<uint8_t*>(parcel.buffer.data()), parcel.buffer.size(),
- /*uid=*/-1, /*useNewSchema=*/true);
+ /*uid=*/-1, /*pid=*/-1, /*useNewSchema=*/true);
sharedData->push_back(event);
}
*pullSuccess = success;
diff --git a/cmds/statsd/src/external/StatsCallbackPuller.h b/cmds/statsd/src/external/StatsCallbackPuller.h
index ac88524..fe6af19 100644
--- a/cmds/statsd/src/external/StatsCallbackPuller.h
+++ b/cmds/statsd/src/external/StatsCallbackPuller.h
@@ -17,7 +17,6 @@
#pragma once
#include <android/os/IPullAtomCallback.h>
-#include <utils/String16.h>
#include "StatsPuller.h"
diff --git a/cmds/statsd/src/external/StatsPullerManager.cpp b/cmds/statsd/src/external/StatsPullerManager.cpp
index 668c11e..988a53f 100644
--- a/cmds/statsd/src/external/StatsPullerManager.cpp
+++ b/cmds/statsd/src/external/StatsPullerManager.cpp
@@ -33,18 +33,12 @@
#include "../stats_log_util.h"
#include "../statscompanion_util.h"
#include "GpuStatsPuller.h"
-#include "PowerStatsPuller.h"
#include "StatsCallbackPuller.h"
-#include "SubsystemSleepStatePuller.h"
#include "TrainInfoPuller.h"
#include "statslog.h"
-using std::make_shared;
-using std::map;
using std::shared_ptr;
-using std::string;
using std::vector;
-using std::list;
namespace android {
namespace os {
@@ -55,12 +49,6 @@
StatsPullerManager::StatsPullerManager()
: kAllPullAtomInfo({
- // subsystem_sleep_state
- {{.atomTag = android::util::SUBSYSTEM_SLEEP_STATE}, new SubsystemSleepStatePuller()},
-
- // on_device_power_measurement
- {{.atomTag = android::util::ON_DEVICE_POWER_MEASUREMENT}, new PowerStatsPuller()},
-
// TrainInfo.
{{.atomTag = android::util::TRAIN_INFO}, new TrainInfoPuller()},
diff --git a/cmds/statsd/src/external/StatsPullerManager.h b/cmds/statsd/src/external/StatsPullerManager.h
index f5d6057..aef16dc 100644
--- a/cmds/statsd/src/external/StatsPullerManager.h
+++ b/cmds/statsd/src/external/StatsPullerManager.h
@@ -23,8 +23,6 @@
#include <utils/threads.h>
#include <list>
-#include <string>
-#include <unordered_map>
#include <vector>
#include "PullDataReceiver.h"
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp b/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
deleted file mode 100644
index f6a4aea..0000000
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.cpp
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * 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.
- */
-
-#define DEBUG false // STOPSHIP if true
-#include "Log.h"
-
-#include <android/hardware/power/1.0/IPower.h>
-#include <android/hardware/power/1.1/IPower.h>
-#include <android/hardware/power/stats/1.0/IPowerStats.h>
-
-#include <fcntl.h>
-#include <hardware/power.h>
-#include <hardware_legacy/power.h>
-#include <inttypes.h>
-#include <semaphore.h>
-#include <stddef.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include "external/SubsystemSleepStatePuller.h"
-#include "external/StatsPuller.h"
-
-#include "SubsystemSleepStatePuller.h"
-#include "logd/LogEvent.h"
-#include "statslog.h"
-#include "stats_log_util.h"
-
-using android::hardware::hidl_vec;
-using android::hardware::power::V1_0::IPower;
-using android::hardware::power::V1_0::PowerStatePlatformSleepState;
-using android::hardware::power::V1_0::PowerStateVoter;
-using android::hardware::power::V1_1::PowerStateSubsystem;
-using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
-using android::hardware::power::stats::V1_0::PowerEntityInfo;
-using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
-using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
-
-using android::hardware::Return;
-using android::hardware::Void;
-
-using std::make_shared;
-using std::shared_ptr;
-
-namespace android {
-namespace os {
-namespace statsd {
-
-static std::function<bool(vector<shared_ptr<LogEvent>>* data)> gPuller = {};
-
-static sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
-static sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
-static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
-
-static std::unordered_map<uint32_t, std::string> gEntityNames = {};
-static std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
-
-static std::mutex gPowerHalMutex;
-
-// The caller must be holding gPowerHalMutex.
-static void deinitPowerStatsLocked() {
- gPowerHalV1_0 = nullptr;
- gPowerHalV1_1 = nullptr;
- gPowerStatsHalV1_0 = nullptr;
-}
-
-struct SubsystemSleepStatePullerDeathRecipient : virtual public hardware::hidl_death_recipient {
- virtual void serviceDied(uint64_t cookie,
- const wp<android::hidl::base::V1_0::IBase>& who) override {
-
- // The HAL just died. Reset all handles to HAL services.
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
- deinitPowerStatsLocked();
- }
-};
-
-static sp<SubsystemSleepStatePullerDeathRecipient> gDeathRecipient =
- new SubsystemSleepStatePullerDeathRecipient();
-
-SubsystemSleepStatePuller::SubsystemSleepStatePuller() :
- StatsPuller(android::util::SUBSYSTEM_SLEEP_STATE) {
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool checkResultLocked(const Return<void> &ret, const char* function) {
- if (!ret.isOk()) {
- ALOGE("%s failed: requested HAL service not available. Description: %s",
- function, ret.description().c_str());
- if (ret.isDeadObject()) {
- deinitPowerStatsLocked();
- }
- return false;
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-// gPowerStatsHalV1_0 must not be null
-static bool initializePowerStats() {
- using android::hardware::power::stats::V1_0::Status;
-
- // Clear out previous content if we are re-initializing
- gEntityNames.clear();
- gStateNames.clear();
-
- Return<void> ret;
- ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
- if (status != Status::SUCCESS) {
- ALOGE("Error getting power entity info");
- return;
- }
-
- // construct lookup table of powerEntityId to power entity name
- for (auto info : infos) {
- gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return false;
- }
-
- ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
- if (status != Status::SUCCESS) {
- ALOGE("Error getting state info");
- return;
- }
-
- // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
- for (auto stateSpace : stateSpaces) {
- std::unordered_map<uint32_t, std::string> stateNames = {};
- for (auto state : stateSpace.states) {
- stateNames.emplace(state.powerEntityStateId,
- state.powerEntityStateName);
- }
- gStateNames.emplace(stateSpace.powerEntityId, stateNames);
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return false;
- }
-
- return (!gEntityNames.empty()) && (!gStateNames.empty());
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getPowerStatsHalLocked() {
- if(gPowerStatsHalV1_0 == nullptr) {
- gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
- if (gPowerStatsHalV1_0 == nullptr) {
- ALOGE("Unable to get power.stats HAL service.");
- return false;
- }
-
- // Link death recipient to power.stats service handle
- hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power.stats HAL death: %s",
- linked.description().c_str());
- deinitPowerStatsLocked();
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power.stats HAL death notifications");
- // We should still continue even though linking failed
- }
- return initializePowerStats();
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getIPowerStatsDataLocked(vector<shared_ptr<LogEvent>>* data) {
- using android::hardware::power::stats::V1_0::Status;
-
- if(!getPowerStatsHalLocked()) {
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
-
- // Get power entity state residency data
- bool success = false;
- Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData({},
- [&data, &success, wallClockTimestampNs, elapsedTimestampNs]
- (auto results, auto status) {
- if (status == Status::NOT_SUPPORTED) {
- ALOGW("getPowerEntityStateResidencyData is not supported");
- success = false;
- return;
- }
-
- for(auto result : results) {
- for(auto stateResidency : result.stateResidencyData) {
- auto statePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE,
- wallClockTimestampNs, elapsedTimestampNs);
- statePtr->write(gEntityNames.at(result.powerEntityId));
- statePtr->write(gStateNames.at(result.powerEntityId)
- .at(stateResidency.powerEntityStateId));
- statePtr->write(stateResidency.totalStateEntryCount);
- statePtr->write(stateResidency.totalTimeInStateMs);
- statePtr->init();
- data->emplace_back(statePtr);
- }
- }
- success = true;
- });
- // Intentionally not returning early here.
- // bool success determines if this succeeded or not.
- checkResultLocked(ret, __func__);
-
- return success;
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getPowerHalLocked() {
- if(gPowerHalV1_0 == nullptr) {
- gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
- if(gPowerHalV1_0 == nullptr) {
- ALOGE("Unable to get power HAL service.");
- return false;
- }
- gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
-
- // Link death recipient to power service handle
- hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
- if (!linked.isOk()) {
- ALOGE("Transaction error in linking to power HAL death: %s",
- linked.description().c_str());
- gPowerHalV1_0 = nullptr;
- return false;
- } else if (!linked) {
- ALOGW("Unable to link to power. death notifications");
- // We should still continue even though linking failed
- }
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-static bool getIPowerDataLocked(vector<shared_ptr<LogEvent>>* data) {
- using android::hardware::power::V1_0::Status;
-
- if(!getPowerHalLocked()) {
- return false;
- }
-
- int64_t wallClockTimestampNs = getWallClockNs();
- int64_t elapsedTimestampNs = getElapsedRealtimeNs();
- Return<void> ret;
- ret = gPowerHalV1_0->getPlatformLowPowerStats(
- [&data, wallClockTimestampNs, elapsedTimestampNs]
- (hidl_vec<PowerStatePlatformSleepState> states, Status status) {
- if (status != Status::SUCCESS) return;
-
- for (size_t i = 0; i < states.size(); i++) {
- const PowerStatePlatformSleepState& state = states[i];
-
- auto statePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE,
- wallClockTimestampNs, elapsedTimestampNs);
- statePtr->write(state.name);
- statePtr->write("");
- statePtr->write(state.totalTransitions);
- statePtr->write(state.residencyInMsecSinceBoot);
- statePtr->init();
- data->push_back(statePtr);
- VLOG("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
- (long long)state.residencyInMsecSinceBoot,
- (long long)state.totalTransitions,
- state.supportedOnlyInSuspend ? 1 : 0);
- for (const auto& voter : state.voters) {
- auto voterPtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE,
- wallClockTimestampNs, elapsedTimestampNs);
- voterPtr->write(state.name);
- voterPtr->write(voter.name);
- voterPtr->write(voter.totalNumberOfTimesVotedSinceBoot);
- voterPtr->write(voter.totalTimeInMsecVotedForSinceBoot);
- voterPtr->init();
- data->push_back(voterPtr);
- VLOG("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
- voter.name.c_str(),
- (long long)voter.totalTimeInMsecVotedForSinceBoot,
- (long long)voter.totalNumberOfTimesVotedSinceBoot);
- }
- }
- });
- if (!checkResultLocked(ret, __func__)) {
- return false;
- }
-
- // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
- sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
- android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
- if (gPowerHal_1_1 != nullptr) {
- ret = gPowerHal_1_1->getSubsystemLowPowerStats(
- [&data, wallClockTimestampNs, elapsedTimestampNs]
- (hidl_vec<PowerStateSubsystem> subsystems, Status status) {
- if (status != Status::SUCCESS) return;
-
- if (subsystems.size() > 0) {
- for (size_t i = 0; i < subsystems.size(); i++) {
- const PowerStateSubsystem& subsystem = subsystems[i];
- for (size_t j = 0; j < subsystem.states.size(); j++) {
- const PowerStateSubsystemSleepState& state =
- subsystem.states[j];
- auto subsystemStatePtr = make_shared<LogEvent>(
- android::util::SUBSYSTEM_SLEEP_STATE,
- wallClockTimestampNs, elapsedTimestampNs);
- subsystemStatePtr->write(subsystem.name);
- subsystemStatePtr->write(state.name);
- subsystemStatePtr->write(state.totalTransitions);
- subsystemStatePtr->write(state.residencyInMsecSinceBoot);
- subsystemStatePtr->init();
- data->push_back(subsystemStatePtr);
- VLOG("subsystemstate: %s, %s, %lld, %lld, %lld",
- subsystem.name.c_str(), state.name.c_str(),
- (long long)state.residencyInMsecSinceBoot,
- (long long)state.totalTransitions,
- (long long)state.lastEntryTimestampMs);
- }
- }
- }
- });
- }
- return true;
-}
-
-// The caller must be holding gPowerHalMutex.
-std::function<bool(vector<shared_ptr<LogEvent>>* data)> getPullerLocked() {
- std::function<bool(vector<shared_ptr<LogEvent>>* data)> ret = {};
-
- // First see if power.stats HAL is available. Fall back to power HAL if
- // power.stats HAL is unavailable.
- if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
- ALOGI("Using power.stats HAL");
- ret = getIPowerStatsDataLocked;
- } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
- ALOGI("Using power HAL");
- ret = getIPowerDataLocked;
- }
-
- return ret;
-}
-
-bool SubsystemSleepStatePuller::PullInternal(vector<shared_ptr<LogEvent>>* data) {
- std::lock_guard<std::mutex> lock(gPowerHalMutex);
-
- if(!gPuller) {
- gPuller = getPullerLocked();
- }
-
- if(gPuller) {
- return gPuller(data);
- }
-
- ALOGE("Unable to load Power Hal or power.stats HAL");
- return false;
-}
-
-} // namespace statsd
-} // namespace os
-} // namespace android
diff --git a/cmds/statsd/src/guardrail/StatsdStats.cpp b/cmds/statsd/src/guardrail/StatsdStats.cpp
index a836bd1..3054b6d 100644
--- a/cmds/statsd/src/guardrail/StatsdStats.cpp
+++ b/cmds/statsd/src/guardrail/StatsdStats.cpp
@@ -36,7 +36,6 @@
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
using std::lock_guard;
-using std::map;
using std::shared_ptr;
using std::string;
using std::vector;
diff --git a/cmds/statsd/src/logd/LogEvent.cpp b/cmds/statsd/src/logd/LogEvent.cpp
index 3827b9e..9a0693a 100644
--- a/cmds/statsd/src/logd/LogEvent.cpp
+++ b/cmds/statsd/src/logd/LogEvent.cpp
@@ -37,11 +37,12 @@
// Msg is expected to begin at the start of the serialized atom -- it should not
// include the android_log_header_t or the StatsEventTag.
-LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid)
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid)
: mBuf(msg),
mRemainingLen(len),
mLogdTimestampNs(time(nullptr)),
- mLogUid(uid)
+ mLogUid(uid),
+ mLogPid(pid)
{
#ifdef NEW_ENCODING_SCHEME
initNew();
@@ -52,8 +53,13 @@
#endif
}
-LogEvent::LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema)
- : mBuf(msg), mRemainingLen(len), mLogdTimestampNs(time(nullptr)), mLogUid(uid) {
+LogEvent::LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid, bool useNewSchema)
+ : mBuf(msg),
+ mRemainingLen(len),
+ mLogdTimestampNs(time(nullptr)),
+ mLogUid(uid),
+ mLogPid(pid)
+{
if (useNewSchema) {
initNew();
} else {
@@ -66,6 +72,7 @@
LogEvent::LogEvent(const LogEvent& event) {
mTagId = event.mTagId;
mLogUid = event.mLogUid;
+ mLogPid = event.mLogPid;
mElapsedTimestampNs = event.mElapsedTimestampNs;
mLogdTimestampNs = event.mLogdTimestampNs;
mValues = event.mValues;
@@ -146,6 +153,7 @@
mElapsedTimestampNs = getElapsedRealtimeNs();
mTagId = android::util::BINARY_PUSH_STATE_CHANGED;
mLogUid = android::IPCThreadState::self()->getCallingUid();
+ mLogPid = android::IPCThreadState::self()->getCallingPid();
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(1)), Value(trainName)));
mValues.push_back(FieldValue(Field(mTagId, getSimpleField(2)), Value(trainVersionCode)));
diff --git a/cmds/statsd/src/logd/LogEvent.h b/cmds/statsd/src/logd/LogEvent.h
index 463a1b6..3db2676 100644
--- a/cmds/statsd/src/logd/LogEvent.h
+++ b/cmds/statsd/src/logd/LogEvent.h
@@ -20,11 +20,9 @@
#include <android/frameworks/stats/1.0/types.h>
#include <android/util/ProtoOutputStream.h>
-#include <log/log_read.h>
#include <private/android_logger.h>
#include <stats_event_list.h>
#include <stats_event.h>
-#include <utils/Errors.h>
#include <string>
#include <vector>
@@ -71,12 +69,12 @@
/**
* Read a LogEvent from the socket
*/
- explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid);
+ explicit LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid);
/**
* Temp constructor to use for pulled atoms until we flip the socket schema.
*/
- explicit LogEvent(uint8_t* msg, uint32_t len, uint32_t uid, bool useNewSchema);
+ explicit LogEvent(uint8_t* msg, uint32_t len, int32_t uid, int32_t pid, bool useNewSchema);
/**
* Constructs a LogEvent with synthetic data for testing. Must call init() before reading.
@@ -123,9 +121,17 @@
*/
inline int GetTagId() const { return mTagId; }
- inline uint32_t GetUid() const {
- return mLogUid;
- }
+ /**
+ * Get the uid of the logging client.
+ * Returns -1 if the uid is unknown/has not been set.
+ */
+ inline int32_t GetUid() const { return mLogUid; }
+
+ /**
+ * Get the pid of the logging client.
+ * Returns -1 if the pid is unknown/has not been set.
+ */
+ inline int32_t GetPid() const { return mLogPid; }
/**
* Get the nth value, starting at 1.
@@ -305,9 +311,14 @@
// The elapsed timestamp set by statsd log writer.
int64_t mElapsedTimestampNs;
+ // The atom tag of the event.
int mTagId;
- uint32_t mLogUid;
+ // The uid of the logging client (defaults to -1).
+ int32_t mLogUid = -1;
+
+ // The pid of the logging client (defaults to -1).
+ int32_t mLogPid = -1;
};
void writeExperimentIdsToProto(const std::vector<int64_t>& experimentIds, std::vector<uint8_t>* protoOut);
diff --git a/cmds/statsd/src/logd/LogEventQueue.h b/cmds/statsd/src/logd/LogEventQueue.h
index b4fd63f..9dda3d2 100644
--- a/cmds/statsd/src/logd/LogEventQueue.h
+++ b/cmds/statsd/src/logd/LogEventQueue.h
@@ -19,10 +19,8 @@
#include "LogEvent.h"
#include <condition_variable>
-#include <memory>
#include <mutex>
#include <queue>
-#include <thread>
namespace android {
namespace os {
diff --git a/cmds/statsd/src/main.cpp b/cmds/statsd/src/main.cpp
index 7d446a9..58bfeb3 100644
--- a/cmds/statsd/src/main.cpp
+++ b/cmds/statsd/src/main.cpp
@@ -20,16 +20,11 @@
#include "StatsService.h"
#include "socket/StatsSocketListener.h"
-#include <binder/IInterface.h>
#include <binder/IPCThreadState.h>
#include <binder/IServiceManager.h>
#include <binder/ProcessState.h>
-#include <binder/Status.h>
#include <hidl/HidlTransportSupport.h>
#include <utils/Looper.h>
-#include <utils/StrongPointer.h>
-
-#include <memory>
#include <stdio.h>
#include <sys/stat.h>
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
index 15c067e..b94a957 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.cpp
@@ -24,8 +24,6 @@
namespace statsd {
using std::set;
-using std::string;
-using std::unique_ptr;
using std::unordered_map;
using std::vector;
diff --git a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
index 2a3f08d..55bc4605 100644
--- a/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/CombinationLogMatchingTracker.h
@@ -16,9 +16,6 @@
#ifndef COMBINATION_LOG_MATCHING_TRACKER_H
#define COMBINATION_LOG_MATCHING_TRACKER_H
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <set>
#include <unordered_map>
#include <vector>
#include "LogMatchingTracker.h"
diff --git a/cmds/statsd/src/matchers/EventMatcherWizard.cpp b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
index 8418e98..025c9a8 100644
--- a/cmds/statsd/src/matchers/EventMatcherWizard.cpp
+++ b/cmds/statsd/src/matchers/EventMatcherWizard.cpp
@@ -14,14 +14,11 @@
* limitations under the License.
*/
#include "EventMatcherWizard.h"
-#include <unordered_set>
namespace android {
namespace os {
namespace statsd {
-using std::map;
-using std::string;
using std::vector;
MatchingState EventMatcherWizard::matchLogEvent(const LogEvent& event, int matcher_index) {
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
index 31b3db5..082daf5a 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.cpp
@@ -23,8 +23,6 @@
namespace os {
namespace statsd {
-using std::string;
-using std::unique_ptr;
using std::unordered_map;
using std::vector;
diff --git a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
index 28b339c..a0f6a88 100644
--- a/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
+++ b/cmds/statsd/src/matchers/SimpleLogMatchingTracker.h
@@ -17,9 +17,6 @@
#ifndef SIMPLE_LOG_MATCHING_TRACKER_H
#define SIMPLE_LOG_MATCHING_TRACKER_H
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <set>
#include <unordered_map>
#include <vector>
#include "LogMatchingTracker.h"
diff --git a/cmds/statsd/src/matchers/matcher_util.cpp b/cmds/statsd/src/matchers/matcher_util.cpp
index 476fae3..1f8bbd7 100644
--- a/cmds/statsd/src/matchers/matcher_util.cpp
+++ b/cmds/statsd/src/matchers/matcher_util.cpp
@@ -23,7 +23,6 @@
using std::set;
using std::string;
-using std::unordered_map;
using std::vector;
namespace android {
diff --git a/cmds/statsd/src/matchers/matcher_util.h b/cmds/statsd/src/matchers/matcher_util.h
index 15b4a97..1ab3e87 100644
--- a/cmds/statsd/src/matchers/matcher_util.h
+++ b/cmds/statsd/src/matchers/matcher_util.h
@@ -18,11 +18,6 @@
#include "logd/LogEvent.h"
-#include <log/log_read.h>
-#include <log/logprint.h>
-#include <set>
-#include <string>
-#include <unordered_map>
#include <vector>
#include "frameworks/base/cmds/statsd/src/statsd_config.pb.h"
#include "packages/UidMap.h"
diff --git a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
index 4ab6fd4..83983e8 100644
--- a/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/GaugeMetricProducer.cpp
@@ -21,8 +21,6 @@
#include "GaugeMetricProducer.h"
#include "../stats_log_util.h"
-#include <cutils/log.h>
-
using android::util::FIELD_COUNT_REPEATED;
using android::util::FIELD_TYPE_BOOL;
using android::util::FIELD_TYPE_FLOAT;
diff --git a/cmds/statsd/src/metrics/MetricProducer.cpp b/cmds/statsd/src/metrics/MetricProducer.cpp
index 5c29cb3..be754e2 100644
--- a/cmds/statsd/src/metrics/MetricProducer.cpp
+++ b/cmds/statsd/src/metrics/MetricProducer.cpp
@@ -33,7 +33,6 @@
namespace os {
namespace statsd {
-using std::map;
// for ActiveMetric
const int FIELD_ID_ACTIVE_METRIC_ID = 1;
diff --git a/cmds/statsd/src/metrics/MetricProducer.h b/cmds/statsd/src/metrics/MetricProducer.h
index 99f0c64..d721514 100644
--- a/cmds/statsd/src/metrics/MetricProducer.h
+++ b/cmds/statsd/src/metrics/MetricProducer.h
@@ -18,7 +18,6 @@
#define METRIC_PRODUCER_H
#include <frameworks/base/cmds/statsd/src/active_config_list.pb.h>
-#include <log/logprint.h>
#include <utils/RefBase.h>
#include <unordered_map>
diff --git a/cmds/statsd/src/metrics/MetricsManager.cpp b/cmds/statsd/src/metrics/MetricsManager.cpp
index 088f607..536700f 100644
--- a/cmds/statsd/src/metrics/MetricsManager.cpp
+++ b/cmds/statsd/src/metrics/MetricsManager.cpp
@@ -18,9 +18,7 @@
#include "MetricsManager.h"
-#include <log/logprint.h>
#include <private/android_filesystem_config.h>
-#include <utils/SystemClock.h>
#include "CountMetricProducer.h"
#include "atoms_info.h"
@@ -42,10 +40,8 @@
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
-using std::make_unique;
using std::set;
using std::string;
-using std::unordered_map;
using std::vector;
namespace android {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.cpp b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
index d2db6e9..2a5b530 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.cpp
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.cpp
@@ -21,7 +21,6 @@
#include "../guardrail/StatsdStats.h"
#include "../stats_log_util.h"
-#include <cutils/log.h>
#include <limits.h>
#include <stdlib.h>
@@ -33,12 +32,8 @@
using android::util::FIELD_TYPE_MESSAGE;
using android::util::FIELD_TYPE_STRING;
using android::util::ProtoOutputStream;
-using std::list;
-using std::make_pair;
-using std::make_shared;
using std::map;
using std::shared_ptr;
-using std::unique_ptr;
using std::unordered_map;
namespace android {
diff --git a/cmds/statsd/src/metrics/ValueMetricProducer.h b/cmds/statsd/src/metrics/ValueMetricProducer.h
index 19fb694..50317b3 100644
--- a/cmds/statsd/src/metrics/ValueMetricProducer.h
+++ b/cmds/statsd/src/metrics/ValueMetricProducer.h
@@ -17,8 +17,6 @@
#pragma once
#include <gtest/gtest_prod.h>
-#include <utils/threads.h>
-#include <list>
#include "anomaly/AnomalyTracker.h"
#include "condition/ConditionTimer.h"
#include "condition/ConditionTracker.h"
diff --git a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
index c3aad66..f44e327 100644
--- a/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
+++ b/cmds/statsd/src/metrics/duration_helper/OringDurationTracker.h
@@ -19,7 +19,6 @@
#include "DurationTracker.h"
-#include <set>
namespace android {
namespace os {
namespace statsd {
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.cpp b/cmds/statsd/src/metrics/metrics_manager_util.cpp
index 17f62b0..40a313a 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.cpp
+++ b/cmds/statsd/src/metrics/metrics_manager_util.cpp
@@ -40,7 +40,6 @@
#include "stats_util.h"
using std::set;
-using std::string;
using std::unordered_map;
using std::vector;
diff --git a/cmds/statsd/src/metrics/metrics_manager_util.h b/cmds/statsd/src/metrics/metrics_manager_util.h
index 95b2ab8..5ebb232 100644
--- a/cmds/statsd/src/metrics/metrics_manager_util.h
+++ b/cmds/statsd/src/metrics/metrics_manager_util.h
@@ -16,7 +16,6 @@
#pragma once
-#include <memory>
#include <set>
#include <unordered_map>
#include <vector>
diff --git a/cmds/statsd/src/packages/PackageInfoListener.h b/cmds/statsd/src/packages/PackageInfoListener.h
index fcdbe69..6c50a8c 100644
--- a/cmds/statsd/src/packages/PackageInfoListener.h
+++ b/cmds/statsd/src/packages/PackageInfoListener.h
@@ -17,7 +17,6 @@
#ifndef STATSD_PACKAGE_INFO_LISTENER_H
#define STATSD_PACKAGE_INFO_LISTENER_H
-#include <utils/RefBase.h>
#include <string>
namespace android {
diff --git a/cmds/statsd/src/packages/UidMap.cpp b/cmds/statsd/src/packages/UidMap.cpp
index 7e63bbf..ab0e86e 100644
--- a/cmds/statsd/src/packages/UidMap.cpp
+++ b/cmds/statsd/src/packages/UidMap.cpp
@@ -21,10 +21,6 @@
#include "guardrail/StatsdStats.h"
#include "packages/UidMap.h"
-#include <android/os/IStatsCompanionService.h>
-#include <binder/IServiceManager.h>
-#include <utils/Errors.h>
-
#include <inttypes.h>
using namespace android;
diff --git a/cmds/statsd/src/packages/UidMap.h b/cmds/statsd/src/packages/UidMap.h
index 2d3f6ee..bfac6e3 100644
--- a/cmds/statsd/src/packages/UidMap.h
+++ b/cmds/statsd/src/packages/UidMap.h
@@ -21,10 +21,8 @@
#include "packages/PackageInfoListener.h"
#include "stats_util.h"
-#include <binder/IResultReceiver.h>
#include <binder/IShellCallback.h>
#include <gtest/gtest_prod.h>
-#include <log/logprint.h>
#include <stdio.h>
#include <utils/RefBase.h>
#include <list>
diff --git a/cmds/statsd/src/shell/ShellSubscriber.cpp b/cmds/statsd/src/shell/ShellSubscriber.cpp
index f7e32d4..d6a0433 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.cpp
+++ b/cmds/statsd/src/shell/ShellSubscriber.cpp
@@ -18,7 +18,6 @@
#include "ShellSubscriber.h"
-#include <android-base/file.h>
#include "matchers/matcher_util.h"
#include "stats_log_util.h"
diff --git a/cmds/statsd/src/shell/ShellSubscriber.h b/cmds/statsd/src/shell/ShellSubscriber.h
index 8e54a8b..86d8590 100644
--- a/cmds/statsd/src/shell/ShellSubscriber.h
+++ b/cmds/statsd/src/shell/ShellSubscriber.h
@@ -22,7 +22,6 @@
#include <binder/IResultReceiver.h>
#include <condition_variable>
#include <mutex>
-#include <string>
#include <thread>
#include "external/StatsPullerManager.h"
#include "frameworks/base/cmds/statsd/src/shell/shell_config.pb.h"
diff --git a/cmds/statsd/src/socket/StatsSocketListener.cpp b/cmds/statsd/src/socket/StatsSocketListener.cpp
index 4308a110..8f0f480 100755
--- a/cmds/statsd/src/socket/StatsSocketListener.cpp
+++ b/cmds/statsd/src/socket/StatsSocketListener.cpp
@@ -27,9 +27,6 @@
#include <unistd.h>
#include <cutils/sockets.h>
-#include <private/android_filesystem_config.h>
-#include <private/android_logger.h>
-#include <unordered_map>
#include "StatsSocketListener.h"
#include "guardrail/StatsdStats.h"
@@ -126,9 +123,10 @@
uint8_t* msg = ptr + sizeof(uint32_t);
uint32_t len = n - sizeof(uint32_t);
uint32_t uid = cred->uid;
+ uint32_t pid = cred->pid;
int64_t oldestTimestamp;
- if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid), &oldestTimestamp)) {
+ if (!mQueue->push(std::make_unique<LogEvent>(msg, len, uid, pid), &oldestTimestamp)) {
StatsdStats::getInstance().noteEventQueueOverflow(oldestTimestamp);
}
diff --git a/cmds/statsd/src/state/StateManager.h b/cmds/statsd/src/state/StateManager.h
index 8bc2461..8b3a421 100644
--- a/cmds/statsd/src/state/StateManager.h
+++ b/cmds/statsd/src/state/StateManager.h
@@ -15,7 +15,6 @@
*/
#pragma once
-#include <gtest/gtest_prod.h>
#include <inttypes.h>
#include <utils/RefBase.h>
diff --git a/cmds/statsd/src/stats_log_util.cpp b/cmds/statsd/src/stats_log_util.cpp
index 76c1936..8e0c628 100644
--- a/cmds/statsd/src/stats_log_util.cpp
+++ b/cmds/statsd/src/stats_log_util.cpp
@@ -17,12 +17,8 @@
#include "hash.h"
#include "stats_log_util.h"
-#include <logd/LogEvent.h>
#include <private/android_filesystem_config.h>
-#include <utils/Log.h>
#include <set>
-#include <stack>
-#include <utils/Log.h>
#include <utils/SystemClock.h>
using android::util::AtomsInfo;
diff --git a/cmds/statsd/src/statscompanion_util.h b/cmds/statsd/src/statscompanion_util.h
index ff702f2..dc4f283 100644
--- a/cmds/statsd/src/statscompanion_util.h
+++ b/cmds/statsd/src/statscompanion_util.h
@@ -18,12 +18,6 @@
#include "StatsLogProcessor.h"
-using namespace android;
-using namespace android::base;
-using namespace android::binder;
-using namespace android::os;
-using namespace std;
-
namespace android {
namespace os {
namespace statsd {
diff --git a/cmds/statsd/src/storage/StorageManager.cpp b/cmds/statsd/src/storage/StorageManager.cpp
index 9b48a02..507297c 100644
--- a/cmds/statsd/src/storage/StorageManager.cpp
+++ b/cmds/statsd/src/storage/StorageManager.cpp
@@ -23,10 +23,8 @@
#include "stats_log_util.h"
#include <android-base/file.h>
-#include <dirent.h>
#include <private/android_filesystem_config.h>
#include <fstream>
-#include <iostream>
namespace android {
namespace os {
diff --git a/cmds/statsd/src/subscriber/IncidentdReporter.cpp b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
index f1320c2..d86e291 100644
--- a/cmds/statsd/src/subscriber/IncidentdReporter.cpp
+++ b/cmds/statsd/src/subscriber/IncidentdReporter.cpp
@@ -24,7 +24,6 @@
#include <android/os/IIncidentManager.h>
#include <android/os/IncidentReportArgs.h>
#include <android/util/ProtoOutputStream.h>
-#include <binder/IBinder.h>
#include <binder/IServiceManager.h>
#include <vector>
diff --git a/cmds/statsd/src/subscriber/SubscriberReporter.cpp b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
index a37cad1..160b57e 100644
--- a/cmds/statsd/src/subscriber/SubscriberReporter.cpp
+++ b/cmds/statsd/src/subscriber/SubscriberReporter.cpp
@@ -20,7 +20,6 @@
#include "SubscriberReporter.h"
using std::lock_guard;
-using std::unordered_map;
namespace android {
namespace os {
diff --git a/cmds/statsd/tests/LogEvent_test.cpp b/cmds/statsd/tests/LogEvent_test.cpp
index 1cf9fb6..35b0396 100644
--- a/cmds/statsd/tests/LogEvent_test.cpp
+++ b/cmds/statsd/tests/LogEvent_test.cpp
@@ -57,9 +57,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(4, values.size());
@@ -103,9 +105,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(2, values.size());
@@ -136,9 +140,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(1, values.size());
@@ -162,9 +168,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(1, values.size());
@@ -196,9 +204,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(8, values.size()); // 2 FieldValues per key-value pair
@@ -260,9 +270,11 @@
size_t size;
uint8_t* buf = stats_event_get_buffer(event, &size);
- LogEvent logEvent(buf, size, /*uid=*/ 1000);
+ LogEvent logEvent(buf, size, /*uid=*/ 1000, /*pid=*/ 1001);
EXPECT_TRUE(logEvent.isValid());
EXPECT_EQ(100, logEvent.GetTagId());
+ EXPECT_EQ(1000, logEvent.GetUid());
+ EXPECT_EQ(1001, logEvent.GetPid());
const vector<FieldValue>& values = logEvent.getValues();
EXPECT_EQ(4, values.size()); // 2 per attribution node
diff --git a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
index 47fc7e1..9cf1de9 100644
--- a/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
+++ b/core/java/android/accessibilityservice/AccessibilityGestureEvent.java
@@ -19,9 +19,17 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
@@ -89,7 +97,15 @@
GESTURE_SWIPE_RIGHT,
GESTURE_SWIPE_RIGHT_AND_UP,
GESTURE_SWIPE_RIGHT_AND_LEFT,
- GESTURE_SWIPE_RIGHT_AND_DOWN
+ GESTURE_SWIPE_RIGHT_AND_DOWN,
+ GESTURE_2_FINGER_SWIPE_DOWN,
+ GESTURE_2_FINGER_SWIPE_LEFT,
+ GESTURE_2_FINGER_SWIPE_RIGHT,
+ GESTURE_2_FINGER_SWIPE_UP,
+ GESTURE_3_FINGER_SWIPE_DOWN,
+ GESTURE_3_FINGER_SWIPE_LEFT,
+ GESTURE_3_FINGER_SWIPE_RIGHT,
+ GESTURE_3_FINGER_SWIPE_UP
})
@Retention(RetentionPolicy.SOURCE)
public @interface GestureId {}
@@ -167,6 +183,14 @@
case GESTURE_SWIPE_UP_AND_LEFT: return "GESTURE_SWIPE_UP_AND_LEFT";
case GESTURE_SWIPE_UP_AND_DOWN: return "GESTURE_SWIPE_UP_AND_DOWN";
case GESTURE_SWIPE_UP_AND_RIGHT: return "GESTURE_SWIPE_UP_AND_RIGHT";
+ case GESTURE_2_FINGER_SWIPE_DOWN: return "GESTURE_2_FINGER_SWIPE_DOWN";
+ case GESTURE_2_FINGER_SWIPE_LEFT: return "GESTURE_2_FINGER_SWIPE_LEFT";
+ case GESTURE_2_FINGER_SWIPE_RIGHT: return "GESTURE_2_FINGER_SWIPE_RIGHT";
+ case GESTURE_2_FINGER_SWIPE_UP: return "GESTURE_2_FINGER_SWIPE_UP";
+ case GESTURE_3_FINGER_SWIPE_DOWN: return "GESTURE_3_FINGER_SWIPE_DOWN";
+ case GESTURE_3_FINGER_SWIPE_LEFT: return "GESTURE_3_FINGER_SWIPE_LEFT";
+ case GESTURE_3_FINGER_SWIPE_RIGHT: return "GESTURE_3_FINGER_SWIPE_RIGHT";
+ case GESTURE_3_FINGER_SWIPE_UP: return "GESTURE_3_FINGER_SWIPE_UP";
default: return Integer.toHexString(eventType);
}
}
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index 27cd285..2165fb3 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -349,6 +349,46 @@
public static final int GESTURE_3_FINGER_TRIPLE_TAP = 24;
/**
+ * The user has performed a two-finger swipe up gesture on the touch screen.
+ */
+ public static final int GESTURE_2_FINGER_SWIPE_UP = 25;
+
+ /**
+ * The user has performed a two-finger swipe down gesture on the touch screen.
+ */
+ public static final int GESTURE_2_FINGER_SWIPE_DOWN = 26;
+
+ /**
+ * The user has performed a two-finger swipe left gesture on the touch screen.
+ */
+ public static final int GESTURE_2_FINGER_SWIPE_LEFT = 27;
+
+ /**
+ * The user has performed a two-finger swipe right gesture on the touch screen.
+ */
+ public static final int GESTURE_2_FINGER_SWIPE_RIGHT = 28;
+
+ /**
+ * The user has performed a three-finger swipe up gesture on the touch screen.
+ */
+ public static final int GESTURE_3_FINGER_SWIPE_UP = 29;
+
+ /**
+ * The user has performed a three-finger swipe down gesture on the touch screen.
+ */
+ public static final int GESTURE_3_FINGER_SWIPE_DOWN = 30;
+
+ /**
+ * The user has performed a three-finger swipe left gesture on the touch screen.
+ */
+ public static final int GESTURE_3_FINGER_SWIPE_LEFT = 31;
+
+ /**
+ * The user has performed a three-finger swipe right gesture on the touch screen.
+ */
+ public static final int GESTURE_3_FINGER_SWIPE_RIGHT = 32;
+
+ /**
* The {@link Intent} that must be declared as handled by the service.
*/
public static final String SERVICE_INTERFACE =
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index dd9a2bc..58bff7f 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -158,6 +158,24 @@
}
};
+ /** @hide */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+ public static ITaskOrganizerController getTaskOrganizerController() {
+ return ITaskOrganizerControllerSingleton.get();
+ }
+
+ private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
+ new Singleton<ITaskOrganizerController>() {
+ @Override
+ protected ITaskOrganizerController create() {
+ try {
+ return getService().getTaskOrganizerController();
+ } catch (RemoteException e) {
+ return null;
+ }
+ }
+ };
+
/**
* Sets the windowing mode for a specific task. Only works on tasks of type
* {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}
diff --git a/core/java/android/app/AppCompatCallbacks.java b/core/java/android/app/AppCompatCallbacks.java
index 19d158d..28a21f7 100644
--- a/core/java/android/app/AppCompatCallbacks.java
+++ b/core/java/android/app/AppCompatCallbacks.java
@@ -18,7 +18,6 @@
import android.compat.Compatibility;
import android.os.Process;
-import android.util.StatsLog;
import com.android.internal.compat.ChangeReporter;
@@ -46,20 +45,20 @@
mDisabledChanges = Arrays.copyOf(disabledChanges, disabledChanges.length);
Arrays.sort(mDisabledChanges);
mChangeReporter = new ChangeReporter(
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS);
+ ChangeReporter.SOURCE_APP_PROCESS);
}
protected void reportChange(long changeId) {
- reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
+ reportChange(changeId, ChangeReporter.STATE_LOGGED);
}
protected boolean isChangeEnabled(long changeId) {
if (Arrays.binarySearch(mDisabledChanges, changeId) < 0) {
// Not present in the disabled array
- reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
+ reportChange(changeId, ChangeReporter.STATE_ENABLED);
return true;
}
- reportChange(changeId, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED);
+ reportChange(changeId, ChangeReporter.STATE_DISABLED);
return false;
}
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index c09aa1f..71cb4a4 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -618,36 +618,22 @@
return hasSystemFeature(name, 0);
}
- private boolean hasSystemFeatureUncached(String name, int version) {
- try {
- return mPM.hasSystemFeature(name, version);
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- // Make this cache relatively large. There are many system features and
- // none are ever invalidated. MPTS tests suggests that the cache should
- // hold at least 150 entries.
- private static final int SYS_FEATURE_CACHE_SIZE = 256;
- private static final String CACHE_KEY_SYS_FEATURE_PROPERTY = "cache_key.has_system_feature";
-
- private class SystemFeatureQuery {
+ private class HasSystemFeatureQuery {
public final String name;
public final int version;
- public SystemFeatureQuery(String n, int v) {
+ public HasSystemFeatureQuery(String n, int v) {
name = n;
version = v;
}
@Override
public String toString() {
- return String.format("SystemFeatureQuery(name=\"%s\", version=%d)",
+ return String.format("HasSystemFeatureQuery(name=\"%s\", version=%d)",
name, version);
}
@Override
public boolean equals(Object o) {
- if (o instanceof SystemFeatureQuery) {
- SystemFeatureQuery r = (SystemFeatureQuery) o;
+ if (o instanceof HasSystemFeatureQuery) {
+ HasSystemFeatureQuery r = (HasSystemFeatureQuery) o;
return Objects.equals(name, r.name) && version == r.version;
} else {
return false;
@@ -655,33 +641,41 @@
}
@Override
public int hashCode() {
- return Objects.hashCode(name) + version;
+ return Objects.hashCode(name) * 13 + version;
}
}
- private final PropertyInvalidatedCache<SystemFeatureQuery, Boolean> mSysFeatureCache =
- new PropertyInvalidatedCache<SystemFeatureQuery, Boolean>(
- SYS_FEATURE_CACHE_SIZE,
- CACHE_KEY_SYS_FEATURE_PROPERTY) {
+ // Make this cache relatively large. There are many system features and
+ // none are ever invalidated. MPTS tests suggests that the cache should
+ // hold at least 150 entries.
+ private final static PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>
+ mHasSystemFeatureCache =
+ new PropertyInvalidatedCache<HasSystemFeatureQuery, Boolean>(
+ 256, "cache_key.has_system_feature") {
@Override
- protected Boolean recompute(SystemFeatureQuery query) {
- return hasSystemFeatureUncached(query.name, query.version);
+ protected Boolean recompute(HasSystemFeatureQuery query) {
+ try {
+ return ActivityThread.currentActivityThread().getPackageManager().
+ hasSystemFeature(query.name, query.version);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
}
};
@Override
public boolean hasSystemFeature(String name, int version) {
- return mSysFeatureCache.query(new SystemFeatureQuery(name, version)).booleanValue();
+ return mHasSystemFeatureCache.query(new HasSystemFeatureQuery(name, version));
}
/** @hide */
- public void disableSysFeatureCache() {
- mSysFeatureCache.disableLocal();
+ public void disableHasSystemFeatureCache() {
+ mHasSystemFeatureCache.disableLocal();
}
/** @hide */
- public static void invalidateSysFeatureCache() {
- PropertyInvalidatedCache.invalidateCache(CACHE_KEY_SYS_FEATURE_PROPERTY);
+ public static void invalidateHasSystemFeatureCache() {
+ mHasSystemFeatureCache.invalidateCache();
}
@Override
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 7285da6..57cd894 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -750,7 +750,7 @@
if (type != null) {
dirs = Environment.buildPaths(dirs, type);
}
- return ensureExternalDirsExistOrFilter(dirs);
+ return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
}
}
@@ -765,7 +765,7 @@
public File[] getObbDirs() {
synchronized (mSync) {
File[] dirs = Environment.buildExternalStorageAppObbDirs(getPackageName());
- return ensureExternalDirsExistOrFilter(dirs);
+ return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
}
}
@@ -809,7 +809,10 @@
public File[] getExternalCacheDirs() {
synchronized (mSync) {
File[] dirs = Environment.buildExternalStorageAppCacheDirs(getPackageName());
- return ensureExternalDirsExistOrFilter(dirs);
+ // We don't try to create cache directories in-process, because they need special
+ // setup for accurate quota tracking. This ensures the cache dirs are always
+ // created through StorageManagerService.
+ return ensureExternalDirsExistOrFilter(dirs, false /* tryCreateInProcess */);
}
}
@@ -817,7 +820,7 @@
public File[] getExternalMediaDirs() {
synchronized (mSync) {
File[] dirs = Environment.buildExternalStorageAppMediaDirs(getPackageName());
- return ensureExternalDirsExistOrFilter(dirs);
+ return ensureExternalDirsExistOrFilter(dirs, true /* tryCreateInProcess */);
}
}
@@ -2373,13 +2376,13 @@
}
@Override
- public @NonNull WindowContext createWindowContext(int type) {
+ public @NonNull WindowContext createWindowContext(int type, Bundle options) {
if (getDisplay() == null) {
throw new UnsupportedOperationException("WindowContext can only be created from "
+ "other visual contexts, such as Activity or one created with "
+ "Context#createDisplayContext(Display)");
}
- return new WindowContext(this, null /* token */, type);
+ return new WindowContext(this, null /* token */, type, options);
}
ContextImpl createBaseWindowContext(IBinder token) {
@@ -2804,24 +2807,24 @@
* Ensure that given directories exist, trying to create them if missing. If
* unable to create, they are filtered by replacing with {@code null}.
*/
- private File[] ensureExternalDirsExistOrFilter(File[] dirs) {
+ private File[] ensureExternalDirsExistOrFilter(File[] dirs, boolean tryCreateInProcess) {
final StorageManager sm = getSystemService(StorageManager.class);
final File[] result = new File[dirs.length];
for (int i = 0; i < dirs.length; i++) {
File dir = dirs[i];
if (!dir.exists()) {
- if (!dir.mkdirs()) {
- // recheck existence in case of cross-process race
- if (!dir.exists()) {
- // Failing to mkdir() may be okay, since we might not have
- // enough permissions; ask vold to create on our behalf.
- try {
+ try {
+ if (!tryCreateInProcess || !dir.mkdirs()) {
+ // recheck existence in case of cross-process race
+ if (!dir.exists()) {
+ // Failing to mkdir() may be okay, since we might not have
+ // enough permissions; ask vold to create on our behalf.
sm.mkdirs(dir);
- } catch (Exception e) {
- Log.w(TAG, "Failed to ensure " + dir + ": " + e);
- dir = null;
}
}
+ } catch (Exception e) {
+ Log.w(TAG, "Failed to ensure " + dir + ": " + e);
+ dir = null;
}
}
result[i] = dir;
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 85fa7c1..503f5c5 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -29,6 +29,7 @@
import android.app.IRequestFinishCallback;
import android.app.IServiceConnection;
import android.app.IStopUserCallback;
+import android.app.ITaskOrganizerController;
import android.app.ITaskStackListener;
import android.app.IUiAutomationConnection;
import android.app.IUidObserver;
@@ -71,7 +72,6 @@
import android.view.ITaskOrganizer;
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationAdapter;
-import android.view.WindowContainerTransaction;
import com.android.internal.app.IVoiceInteractor;
import com.android.internal.os.IResultReceiver;
import com.android.internal.policy.IKeyguardDismissCallback;
@@ -123,8 +123,6 @@
int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
- void registerTaskOrganizer(in ITaskOrganizer organizer, int windowingMode);
-
boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
int userId);
@@ -224,7 +222,6 @@
void setTaskResizeable(int taskId, int resizeableMode);
void toggleFreeformWindowingMode(in IBinder token);
void resizeTask(int taskId, in Rect bounds, int resizeMode);
- void applyContainerTransaction(in WindowContainerTransaction t);
void moveStackToDisplay(int stackId, int displayId);
void removeStack(int stackId);
@@ -364,6 +361,11 @@
in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
/**
+ * Returns an interface enabling the management of task organizers.
+ */
+ ITaskOrganizerController getTaskOrganizerController();
+
+ /**
* Sets whether we are currently in an interactive split screen resize operation where we
* are changing the docked stack size.
*/
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
new file mode 100644
index 0000000..168f782
--- /dev/null
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -0,0 +1,51 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.app;
+
+import android.app.ActivityManager;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+
+/** @hide */
+interface ITaskOrganizerController {
+
+ /**
+ * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
+ * If there was already a TaskOrganizer for this windowing mode it will be evicted
+ * and receive taskVanished callbacks in the process.
+ */
+ void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
+
+ /** Apply multiple WindowContainer operations at once. */
+ void applyContainerTransaction(in WindowContainerTransaction t);
+
+ /** Creates a persistent root task in WM for a particular windowing-mode. */
+ ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
+
+ /** Deletes a persistent root task in WM */
+ boolean deleteRootTask(IWindowContainer task);
+
+ /** Get the root task which contains the current ime target */
+ IWindowContainer getImeTarget(int display);
+
+ /**
+ * Set's the root task to launch new tasks into on a display. {@code null} means no launch root
+ * and thus new tasks just end up directly on the display.
+ */
+ void setLaunchRoot(int displayId, in IWindowContainer root);
+}
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 5a4622e..4b24e09 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -15,8 +15,6 @@
*/
package android.app;
-import static android.annotation.SystemApi.Client.MODULE_APPS;
-
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
@@ -362,7 +360,7 @@
* @param blockableSystem if {@code true}, allows users to block notifications on this channel.
* @hide
*/
- @SystemApi(client = MODULE_APPS)
+ @SystemApi
@TestApi
public void setBlockableSystem(boolean blockableSystem) {
mBlockableSystem = blockableSystem;
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 59c17192..65a5f6b 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -365,11 +365,9 @@
registerService(Context.TETHERING_SERVICE, TetheringManager.class,
new CachedServiceFetcher<TetheringManager>() {
@Override
- public TetheringManager createService(ContextImpl ctx) throws ServiceNotFoundException {
- IBinder b = ServiceManager.getService(Context.TETHERING_SERVICE);
- if (b == null) return null;
-
- return new TetheringManager(ctx, b);
+ public TetheringManager createService(ContextImpl ctx) {
+ return new TetheringManager(
+ ctx, () -> ServiceManager.getService(Context.TETHERING_SERVICE));
}});
diff --git a/core/java/android/app/TaskEmbedder.java b/core/java/android/app/TaskEmbedder.java
index 93b1ea8..761b225 100644
--- a/core/java/android/app/TaskEmbedder.java
+++ b/core/java/android/app/TaskEmbedder.java
@@ -48,7 +48,6 @@
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.WindowManagerGlobal;
import android.view.inputmethod.InputMethodManager;
@@ -131,6 +130,7 @@
private TaskStackListener mTaskStackListener;
private Listener mListener;
private boolean mOpened; // Protected by mGuard.
+ private DisplayMetrics mTmpDisplayMetrics;
private final CloseGuard mGuard = CloseGuard.get();
@@ -594,10 +594,11 @@
/** Get density of the hosting display. */
private int getBaseDisplayDensity() {
- final WindowManager wm = mContext.getSystemService(WindowManager.class);
- final DisplayMetrics metrics = new DisplayMetrics();
- wm.getDefaultDisplay().getMetrics(metrics);
- return metrics.densityDpi;
+ if (mTmpDisplayMetrics == null) {
+ mTmpDisplayMetrics = new DisplayMetrics();
+ }
+ mContext.getDisplay().getMetrics(mTmpDisplayMetrics);
+ return mTmpDisplayMetrics.densityDpi;
}
/**
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index fe9c640..662ca6e 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -16,6 +16,8 @@
package android.app;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -25,6 +27,7 @@
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Log;
+import android.view.IWindowContainer;
/**
* Stores information about a particular Task.
@@ -138,6 +141,19 @@
@UnsupportedAppUsage
public final Configuration configuration = new Configuration();
+ /**
+ * Used as an opaque identifier for this task.
+ * @hide
+ */
+ @NonNull
+ public IWindowContainer token;
+
+ /**
+ * The activity type of the top activity in this task.
+ * @hide
+ */
+ public @WindowConfiguration.ActivityType int topActivityType;
+
TaskInfo() {
// Do nothing
}
@@ -160,6 +176,11 @@
}
}
+ /** @hide */
+ public boolean isResizable() {
+ return resizeMode != RESIZE_MODE_UNRESIZEABLE;
+ }
+
/**
* Reads the TaskInfo from a parcel.
*/
@@ -186,6 +207,8 @@
supportsSplitScreenMultiWindow = source.readBoolean();
resizeMode = source.readInt();
configuration.readFromParcel(source);
+ token = IWindowContainer.Stub.asInterface(source.readStrongBinder());
+ topActivityType = source.readInt();
}
/**
@@ -221,6 +244,8 @@
dest.writeBoolean(supportsSplitScreenMultiWindow);
dest.writeInt(resizeMode);
configuration.writeToParcel(dest, flags);
+ dest.writeStrongInterface(token);
+ dest.writeInt(topActivityType);
}
@Override
@@ -234,6 +259,8 @@
+ " numActivities=" + numActivities
+ " lastActiveTime=" + lastActiveTime
+ " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
- + " resizeMode=" + resizeMode;
+ + " resizeMode=" + resizeMode
+ + " token=" + token
+ + " topActivityType=" + topActivityType;
}
}
diff --git a/core/java/android/app/WindowContext.java b/core/java/android/app/WindowContext.java
index 22cc14b..36ae450 100644
--- a/core/java/android/app/WindowContext.java
+++ b/core/java/android/app/WindowContext.java
@@ -32,7 +32,7 @@
* windows. Its resources and configuration are adjusted to the area of the display that will be
* used when a new window is added via {@link android.view.WindowManager.addView}.
*
- * @see Context#createWindowContext(int)
+ * @see Context#createWindowContext(int, Bundle)
* @hide
*/
// TODO(b/128338354): Handle config/display changes from server side.
@@ -53,7 +53,7 @@
* @param type Window type to be used with this context.
* @hide
*/
- public WindowContext(Context base, IBinder token, int type) {
+ public WindowContext(Context base, IBinder token, int type, Bundle options) {
super(null /* base */);
mWms = WindowManagerGlobal.getWindowManagerService();
@@ -76,7 +76,7 @@
return;
}
try {
- mWms.addWindowContextToken(mToken, type, mDisplayId, getPackageName());
+ mWms.addWindowTokenWithOptions(mToken, type, mDisplayId, options, getPackageName());
// TODO(window-context): remove token with a DeathObserver
} catch (RemoteException e) {
mOwnsToken = false;
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index f71d78b..3676a9b 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -328,7 +328,7 @@
* modified by the user and the only way of resetting the device is via factory reset.
*
* <p>From version {@link android.os.Build.VERSION_CODES#Q}, the admin app can choose
- * whether to set up a fully managed device or a work profile. For the admin app to support
+ * whether to set up a fully managed device or a managed profile. For the admin app to support
* this, it must have an activity with intent filter {@link #ACTION_GET_PROVISIONING_MODE} and
* another one with intent filter {@link #ACTION_ADMIN_POLICY_COMPLIANCE}. For example:
* <pre>
@@ -1781,12 +1781,13 @@
/**
* Grants access to selection of KeyChain certificates on behalf of requesting apps.
* Once granted the app will start receiving
- * DelegatedAdminReceiver.onChoosePrivateKeyAlias. The caller (PO/DO) will
+ * {@link DelegatedAdminReceiver#onChoosePrivateKeyAlias}. The caller (PO/DO) will
* no longer receive {@link DeviceAdminReceiver#onChoosePrivateKeyAlias}.
* There can be at most one app that has this delegation.
* If another app already had delegated certificate selection access,
* it will lose the delegation when a new app is delegated.
- *
+ * <p> The delegaetd app can also call {@link #grantKeyPairToApp} and
+ * {@link #revokeKeyPairFromApp} to directly grant KeyCain keys to other apps.
* <p> Can be granted by Device Owner or Profile Owner.
*/
public static final String DELEGATION_CERT_SELECTION = "delegation-cert-selection";
@@ -4313,7 +4314,7 @@
* additionally call this method on the parent instance.
* Calling this method on the parent {@link DevicePolicyManager} instance would wipe the
* entire device, while calling it on the current profile instance would relinquish the device
- * for personal use, removing the work profile and all policies set by the profile owner.
+ * for personal use, removing the managed profile and all policies set by the profile owner.
*
* @param flags Bit mask of additional options: currently supported flags are
* {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA},
@@ -4339,7 +4340,7 @@
* additionally call this method on the parent instance.
* Calling this method on the parent {@link DevicePolicyManager} instance would wipe the
* entire device, while calling it on the current profile instance would relinquish the device
- * for personal use, removing the work profile and all policies set by the profile owner.
+ * for personal use, removing the managed profile and all policies set by the profile owner.
*
* @param flags Bit mask of additional options: currently supported flags are
* {@link #WIPE_EXTERNAL_STORAGE}, {@link #WIPE_RESET_PROTECTION_DATA} and
@@ -11584,12 +11585,14 @@
* #setCrossProfilePackages(ComponentName, Set)}.</li>
* <li>The default package names set by the OEM that are allowed to request user consent for
* cross-profile communication without being explicitly enabled by the admin, via
- * {@link com.android.internal.R.array#cross_profile_apps}</li>
+ * {@link com.android.internal.R.array#cross_profile_apps} and
+ * {@link com.android.internal.R.array#vendor_cross_profile_apps}.</li>
* </ul>
*
* @return the combined set of whitelisted package names set via
- * {@link #setCrossProfilePackages(ComponentName, Set)} and
- * {@link com.android.internal.R.array#cross_profile_apps}
+ * {@link #setCrossProfilePackages(ComponentName, Set)},
+ * {@link com.android.internal.R.array#cross_profile_apps},
+ * and {@link com.android.internal.R.array#vendor_cross_profile_apps}.
*
* @hide
*/
@@ -11599,7 +11602,7 @@
permission.INTERACT_ACROSS_PROFILES
})
public @NonNull Set<String> getAllCrossProfilePackages() {
- throwIfParentInstance("getDefaultCrossProfilePackages");
+ throwIfParentInstance("getAllCrossProfilePackages");
if (mService != null) {
try {
return new ArraySet<>(mService.getAllCrossProfilePackages());
@@ -11611,6 +11614,26 @@
}
/**
+ * Returns the default package names set by the OEM that are allowed to request user consent for
+ * cross-profile communication without being explicitly enabled by the admin, via
+ * {@link com.android.internal.R.array#cross_profile_apps} and
+ * {@link com.android.internal.R.array#vendor_cross_profile_apps}.
+ *
+ * @hide
+ */
+ public @NonNull Set<String> getDefaultCrossProfilePackages() {
+ throwIfParentInstance("getDefaultCrossProfilePackages");
+ if (mService != null) {
+ try {
+ return new ArraySet<>(mService.getDefaultCrossProfilePackages());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ return Collections.emptySet();
+ }
+
+ /**
* Returns whether the device is being used as a managed kiosk. These requirements are as
* follows:
* <ul>
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 7fd0ae4..d2672eb 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -457,6 +457,7 @@
List<String> getCrossProfilePackages(in ComponentName admin);
List<String> getAllCrossProfilePackages();
+ List<String> getDefaultCrossProfilePackages();
boolean isManagedKiosk();
boolean isUnattendedManagedKiosk();
diff --git a/core/java/android/app/timedetector/ManualTimeSuggestion.java b/core/java/android/app/timedetector/ManualTimeSuggestion.java
index 50de7385..da51ce2 100644
--- a/core/java/android/app/timedetector/ManualTimeSuggestion.java
+++ b/core/java/android/app/timedetector/ManualTimeSuggestion.java
@@ -29,10 +29,18 @@
import java.util.Objects;
/**
- * A time signal from a manual (user provided) source. The value consists of the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
- * clock when that number was established. The elapsed realtime clock is considered accurate but
- * volatile, so time signals must not be persisted across device resets.
+ * A time signal from a manual (user provided) source.
+ *
+ * <p>{@code utcTime} is the suggested time. The {@code utcTime.value} is the number of milliseconds
+ * elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the value of the
+ * elapsed realtime clock when the {@code utcTime.value} was established.
+ * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
+ * suggestions cannot be persisted across device resets.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was entered. This information exists only to aid in
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection
+ * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
*
* @hide
*/
@@ -49,10 +57,8 @@
}
};
- @NonNull
- private final TimestampedValue<Long> mUtcTime;
- @Nullable
- private ArrayList<String> mDebugInfo;
+ @NonNull private final TimestampedValue<Long> mUtcTime;
+ @Nullable private ArrayList<String> mDebugInfo;
public ManualTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
mUtcTime = Objects.requireNonNull(utcTime);
diff --git a/core/java/android/app/timedetector/NetworkTimeSuggestion.java b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
index 17e9c5a..89fd6f31 100644
--- a/core/java/android/app/timedetector/NetworkTimeSuggestion.java
+++ b/core/java/android/app/timedetector/NetworkTimeSuggestion.java
@@ -29,10 +29,18 @@
import java.util.Objects;
/**
- * A time signal from a network time source like NTP. The value consists of the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
- * clock when that number was established. The elapsed realtime clock is considered accurate but
- * volatile, so time signals must not be persisted across device resets.
+ * A time signal from a network time source like NTP.
+ *
+ * <p>{@code utcTime} contains the suggested time. The {@code utcTime.value} is the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the
+ * value of the elapsed realtime clock when the {@code utcTime.value} was established.
+ * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
+ * suggestions cannot be persisted across device resets.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was determined. This information exists only to aid
+ * in debugging and therefore is used by {@link #toString()}, but it is not for use in detection
+ * logic and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
*
* @hide
*/
@@ -49,10 +57,8 @@
}
};
- @NonNull
- private final TimestampedValue<Long> mUtcTime;
- @Nullable
- private ArrayList<String> mDebugInfo;
+ @NonNull private final TimestampedValue<Long> mUtcTime;
+ @Nullable private ArrayList<String> mDebugInfo;
public NetworkTimeSuggestion(@NonNull TimestampedValue<Long> utcTime) {
mUtcTime = Objects.requireNonNull(utcTime);
diff --git a/core/java/android/app/timedetector/PhoneTimeSuggestion.java b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
index bd649f8..16288e8 100644
--- a/core/java/android/app/timedetector/PhoneTimeSuggestion.java
+++ b/core/java/android/app/timedetector/PhoneTimeSuggestion.java
@@ -32,12 +32,22 @@
* A time suggestion from an identified telephony source. e.g. from NITZ information from a specific
* radio.
*
- * <p>The time value can be {@code null} to indicate that the telephony source has entered an
- * "un-opinionated" state and any previous suggestions from the source are being withdrawn. When not
- * {@code null}, the value consists of the number of milliseconds elapsed since 1/1/1970 00:00:00
- * UTC and the time according to the elapsed realtime clock when that number was established. The
- * elapsed realtime clock is considered accurate but volatile, so time suggestions must not be
- * persisted across device resets.
+ * <p>{@code slotIndex} identifies the suggestion source. This enables detection logic to identify
+ * suggestions from the same source when there are several in use.
+ *
+ * <p>{@code utcTime}. When not {@code null}, the {@code utcTime.value} is the number of
+ * milliseconds elapsed since 1/1/1970 00:00:00 UTC. The {@code utcTime.referenceTimeMillis} is the
+ * value of the elapsed realtime clock when the {@code utcTime.value} was established.
+ * Note that the elapsed realtime clock is considered accurate but it is volatile, so time
+ * suggestions cannot be persisted across device resets. {@code utcTime} can be {@code null} to
+ * indicate that the telephony source has entered an "un-opinionated" state and any previous
+ * suggestion from the source is being withdrawn.
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists, e.g. what triggered it to be made and what heuristic was used
+ * to determine the time or its absence. This information exists only to aid in debugging and
+ * therefore is used by {@link #toString()}, but it is not for use in detection logic and is not
+ * considered in {@link #hashCode()} or {@link #equals(Object)}.
*
* @hide
*/
@@ -57,19 +67,19 @@
}
};
- private final int mPhoneId;
+ private final int mSlotIndex;
@Nullable private final TimestampedValue<Long> mUtcTime;
@Nullable private ArrayList<String> mDebugInfo;
private PhoneTimeSuggestion(Builder builder) {
- mPhoneId = builder.mPhoneId;
+ mSlotIndex = builder.mSlotIndex;
mUtcTime = builder.mUtcTime;
mDebugInfo = builder.mDebugInfo != null ? new ArrayList<>(builder.mDebugInfo) : null;
}
private static PhoneTimeSuggestion createFromParcel(Parcel in) {
- int phoneId = in.readInt();
- PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(phoneId)
+ int slotIndex = in.readInt();
+ PhoneTimeSuggestion suggestion = new PhoneTimeSuggestion.Builder(slotIndex)
.setUtcTime(in.readParcelable(null /* classLoader */))
.build();
@SuppressWarnings("unchecked")
@@ -87,22 +97,24 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mPhoneId);
+ dest.writeInt(mSlotIndex);
dest.writeParcelable(mUtcTime, 0);
dest.writeList(mDebugInfo);
}
/**
- * Returns an identifier for the source of this suggestion. When a device has several "phones",
- * i.e. sim slots or equivalent, it is used to identify which one.
+ * Returns an identifier for the source of this suggestion.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}.
*/
- public int getPhoneId() {
- return mPhoneId;
+ public int getSlotIndex() {
+ return mSlotIndex;
}
/**
- * Returns the suggestion. {@code null} means that the caller is no longer sure what time it
- * is.
+ * Returns the suggested time or {@code null} if there isn't one.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}.
*/
@Nullable
public TimestampedValue<Long> getUtcTime() {
@@ -110,8 +122,9 @@
}
/**
- * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
- * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+ * Returns debug metadata for the suggestion.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public List<String> getDebugInfo() {
@@ -120,9 +133,9 @@
}
/**
- * Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
@@ -132,9 +145,9 @@
}
/**
- * Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull List<String> debugInfo) {
if (mDebugInfo == null) {
@@ -152,19 +165,19 @@
return false;
}
PhoneTimeSuggestion that = (PhoneTimeSuggestion) o;
- return mPhoneId == that.mPhoneId
+ return mSlotIndex == that.mSlotIndex
&& Objects.equals(mUtcTime, that.mUtcTime);
}
@Override
public int hashCode() {
- return Objects.hash(mPhoneId, mUtcTime);
+ return Objects.hash(mSlotIndex, mUtcTime);
}
@Override
public String toString() {
return "PhoneTimeSuggestion{"
- + "mPhoneId='" + mPhoneId + '\''
+ + "mSlotIndex='" + mSlotIndex + '\''
+ ", mUtcTime=" + mUtcTime
+ ", mDebugInfo=" + mDebugInfo
+ '}';
@@ -177,16 +190,24 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final class Builder {
- private final int mPhoneId;
+ private final int mSlotIndex;
@Nullable private TimestampedValue<Long> mUtcTime;
@Nullable private List<String> mDebugInfo;
- /** Creates a builder with the specified {@code phoneId}. */
- public Builder(int phoneId) {
- mPhoneId = phoneId;
+ /**
+ * Creates a builder with the specified {@code slotIndex}.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code slotIndex}.
+ */
+ public Builder(int slotIndex) {
+ mSlotIndex = slotIndex;
}
- /** Returns the builder for call chaining. */
+ /**
+ * Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code utcTime}.
+ */
@NonNull
public Builder setUtcTime(@Nullable TimestampedValue<Long> utcTime) {
if (utcTime != null) {
@@ -198,7 +219,11 @@
return this;
}
- /** Returns the builder for call chaining. */
+ /**
+ * Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeSuggestion} for more information about {@code debugInfo}.
+ */
@NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
diff --git a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
index a6b953b..3a9adc7 100644
--- a/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/ManualTimeZoneSuggestion.java
@@ -28,10 +28,14 @@
import java.util.Objects;
/**
- * A time signal from a manual (user provided) source. The value consists of the number of
- * milliseconds elapsed since 1/1/1970 00:00:00 UTC and the time according to the elapsed realtime
- * clock when that number was established. The elapsed realtime clock is considered accurate but
- * volatile, so time signals must not be persisted across device resets.
+ * A time signal from a manual (user provided) source.
+ *
+ * <p>{@code zoneId} contains the suggested time zone ID, e.g. "America/Los_Angeles".
+ *
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists and how it was entered. This information exists only to aid in
+ * debugging and therefore is used by {@link #toString()}, but it is not for use in detection logic
+ * and is not considered in {@link #hashCode()} or {@link #equals(Object)}.
*
* @hide
*/
@@ -48,10 +52,8 @@
}
};
- @NonNull
- private final String mZoneId;
- @Nullable
- private ArrayList<String> mDebugInfo;
+ @NonNull private final String mZoneId;
+ @Nullable private ArrayList<String> mDebugInfo;
public ManualTimeZoneSuggestion(@NonNull String zoneId) {
mZoneId = Objects.requireNonNull(zoneId);
diff --git a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
index d71ffcb..0544ccd 100644
--- a/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
+++ b/core/java/android/app/timezonedetector/PhoneTimeZoneSuggestion.java
@@ -34,10 +34,14 @@
* A time zone suggestion from an identified telephony source, e.g. from MCC and NITZ information
* associated with a specific radio.
*
- * <p>The time zone ID can be {@code null} to indicate that the telephony source has entered an
- * "un-opinionated" state and any previous suggestions from that source are being withdrawn.
- * When not {@code null}, the value consists of a suggested time zone ID and metadata that can be
- * used to judge quality / certainty of the suggestion.
+ * <p>{@code slotIndex} identifies the suggestion source. This enables detection logic to identify
+ * suggestions from the same source when there are several in use.
+ *
+ * <p>{@code zoneId}. When not {@code null}, {@code zoneId} contains the suggested time zone ID,
+ * e.g. "America/Los_Angeles". Suggestion metadata like {@code matchType} and {@code quality} can be
+ * used to judge quality / certainty of the suggestion. {@code zoneId} can be {@code null} to
+ * indicate that the telephony source has entered an "un-opinionated" state and any previous
+ * suggestion from the same source is being withdrawn.
*
* <p>{@code matchType} must be set to {@link #MATCH_TYPE_NA} when {@code zoneId} is {@code null},
* and one of the other {@code MATCH_TYPE_} values when it is not {@code null}.
@@ -45,6 +49,12 @@
* <p>{@code quality} must be set to {@link #QUALITY_NA} when {@code zoneId} is {@code null},
* and one of the other {@code QUALITY_} values when it is not {@code null}.
*
+ * <p>{@code debugInfo} contains debugging metadata associated with the suggestion. This is used to
+ * record why the suggestion exists, e.g. what triggered it to be made and what heuristic was used
+ * to determine the time zone or its absence. This information exists only to aid in debugging and
+ * therefore is used by {@link #toString()}, but it is not for use in detection logic and is not
+ * considered in {@link #hashCode()} or {@link #equals(Object)}.
+ *
* @hide
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
@@ -66,12 +76,12 @@
/**
* Creates an empty time zone suggestion, i.e. one that will cancel previous suggestions with
- * the same {@code phoneId}.
+ * the same {@code slotIndex}.
*/
@NonNull
public static PhoneTimeZoneSuggestion createEmptySuggestion(
- int phoneId, @NonNull String debugInfo) {
- return new Builder(phoneId).addDebugInfo(debugInfo).build();
+ int slotIndex, @NonNull String debugInfo) {
+ return new Builder(slotIndex).addDebugInfo(debugInfo).build();
}
/** @hide */
@@ -131,41 +141,14 @@
*/
public static final int QUALITY_MULTIPLE_ZONES_WITH_DIFFERENT_OFFSETS = 3;
- /**
- * The ID of the phone this suggestion is associated with. For multiple-sim devices this
- * helps to establish source so filtering / stickiness can be implemented.
- */
- private final int mPhoneId;
-
- /**
- * The suggestion. {@code null} means there is no current suggestion and any previous suggestion
- * should be forgotten.
- */
- @Nullable
- private final String mZoneId;
-
- /**
- * The type of "match" used to establish the time zone.
- */
- @MatchType
- private final int mMatchType;
-
- /**
- * A measure of the quality of the time zone suggestion, i.e. how confident one could be in
- * it.
- */
- @Quality
- private final int mQuality;
-
- /**
- * Free-form debug information about how the suggestion was derived. Used for debug only,
- * intentionally not used in equals(), etc.
- */
- @Nullable
- private List<String> mDebugInfo;
+ private final int mSlotIndex;
+ @Nullable private final String mZoneId;
+ @MatchType private final int mMatchType;
+ @Quality private final int mQuality;
+ @Nullable private List<String> mDebugInfo;
private PhoneTimeZoneSuggestion(Builder builder) {
- mPhoneId = builder.mPhoneId;
+ mSlotIndex = builder.mSlotIndex;
mZoneId = builder.mZoneId;
mMatchType = builder.mMatchType;
mQuality = builder.mQuality;
@@ -175,8 +158,8 @@
@SuppressWarnings("unchecked")
private static PhoneTimeZoneSuggestion createFromParcel(Parcel in) {
// Use the Builder so we get validation during build().
- int phoneId = in.readInt();
- PhoneTimeZoneSuggestion suggestion = new Builder(phoneId)
+ int slotIndex = in.readInt();
+ PhoneTimeZoneSuggestion suggestion = new Builder(slotIndex)
.setZoneId(in.readString())
.setMatchType(in.readInt())
.setQuality(in.readInt())
@@ -190,7 +173,7 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- dest.writeInt(mPhoneId);
+ dest.writeInt(mSlotIndex);
dest.writeString(mZoneId);
dest.writeInt(mMatchType);
dest.writeInt(mQuality);
@@ -203,17 +186,19 @@
}
/**
- * Returns an identifier for the source of this suggestion. When a device has several "phones",
- * i.e. sim slots or equivalent, it is used to identify which one.
+ * Returns an identifier for the source of this suggestion.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}.
*/
- public int getPhoneId() {
- return mPhoneId;
+ public int getSlotIndex() {
+ return mSlotIndex;
}
/**
* Returns the suggested time zone Olson ID, e.g. "America/Los_Angeles". {@code null} means that
- * the caller is no longer sure what the current time zone is. See
- * {@link PhoneTimeZoneSuggestion} for the associated {@code matchType} / {@code quality} rules.
+ * the caller is no longer sure what the current time zone is.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}.
*/
@Nullable
public String getZoneId() {
@@ -222,8 +207,9 @@
/**
* Returns information about how the suggestion was determined which could be used to rank
- * suggestions when several are available from different sources. See
- * {@link PhoneTimeZoneSuggestion} for the associated rules.
+ * suggestions when several are available from different sources.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}.
*/
@MatchType
public int getMatchType() {
@@ -231,8 +217,9 @@
}
/**
- * Returns information about the likelihood of the suggested zone being correct. See
- * {@link PhoneTimeZoneSuggestion} for the associated rules.
+ * Returns information about the likelihood of the suggested zone being correct.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}.
*/
@Quality
public int getQuality() {
@@ -240,8 +227,9 @@
}
/**
- * Returns debug metadata for the suggestion. The information is present in {@link #toString()}
- * but is not considered for {@link #equals(Object)} and {@link #hashCode()}.
+ * Returns debug metadata for the suggestion.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
@NonNull
public List<String> getDebugInfo() {
@@ -250,9 +238,9 @@
}
/**
- * Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
@@ -262,9 +250,9 @@
}
/**
- * Associates information with the instance that can be useful for debugging / logging. The
- * information is present in {@link #toString()} but is not considered for
- * {@link #equals(Object)} and {@link #hashCode()}.
+ * Associates information with the instance that can be useful for debugging / logging.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
*/
public void addDebugInfo(@NonNull List<String> debugInfo) {
if (mDebugInfo == null) {
@@ -282,7 +270,7 @@
return false;
}
PhoneTimeZoneSuggestion that = (PhoneTimeZoneSuggestion) o;
- return mPhoneId == that.mPhoneId
+ return mSlotIndex == that.mSlotIndex
&& mMatchType == that.mMatchType
&& mQuality == that.mQuality
&& Objects.equals(mZoneId, that.mZoneId);
@@ -290,13 +278,13 @@
@Override
public int hashCode() {
- return Objects.hash(mPhoneId, mZoneId, mMatchType, mQuality);
+ return Objects.hash(mSlotIndex, mZoneId, mMatchType, mQuality);
}
@Override
public String toString() {
return "PhoneTimeZoneSuggestion{"
- + "mPhoneId=" + mPhoneId
+ + "mSlotIndex=" + mSlotIndex
+ ", mZoneId='" + mZoneId + '\''
+ ", mMatchType=" + mMatchType
+ ", mQuality=" + mQuality
@@ -311,18 +299,25 @@
*/
@SystemApi(client = SystemApi.Client.MODULE_LIBRARIES)
public static final class Builder {
- private final int mPhoneId;
+ private final int mSlotIndex;
@Nullable private String mZoneId;
@MatchType private int mMatchType;
@Quality private int mQuality;
@Nullable private List<String> mDebugInfo;
- public Builder(int phoneId) {
- mPhoneId = phoneId;
+ /**
+ * Creates a builder with the specified {@code slotIndex}.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code slotIndex}.
+ */
+ public Builder(int slotIndex) {
+ mSlotIndex = slotIndex;
}
/**
* Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code zoneId}.
*/
@NonNull
public Builder setZoneId(@Nullable String zoneId) {
@@ -330,21 +325,33 @@
return this;
}
- /** Returns the builder for call chaining. */
+ /**
+ * Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code matchType}.
+ */
@NonNull
public Builder setMatchType(@MatchType int matchType) {
mMatchType = matchType;
return this;
}
- /** Returns the builder for call chaining. */
+ /**
+ * Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code quality}.
+ */
@NonNull
public Builder setQuality(@Quality int quality) {
mQuality = quality;
return this;
}
- /** Returns the builder for call chaining. */
+ /**
+ * Returns the builder for call chaining.
+ *
+ * <p>See {@link PhoneTimeZoneSuggestion} for more information about {@code debugInfo}.
+ */
@NonNull
public Builder addDebugInfo(@NonNull String debugInfo) {
if (mDebugInfo == null) {
diff --git a/core/java/android/bluetooth/BluetoothAdapter.java b/core/java/android/bluetooth/BluetoothAdapter.java
index e24b040..b73d311 100644
--- a/core/java/android/bluetooth/BluetoothAdapter.java
+++ b/core/java/android/bluetooth/BluetoothAdapter.java
@@ -1766,6 +1766,45 @@
}
/**
+ * Removes the active device for the grouping of @ActiveDeviceUse specified
+ *
+ * @param profiles represents the purpose for which we are setting this as the active device.
+ * Possible values are:
+ * {@link BluetoothAdapter#ACTIVE_DEVICE_AUDIO},
+ * {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
+ * {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
+ * @return false on immediate error, true otherwise
+ * @throws IllegalArgumentException if device is null or profiles is not one of
+ * {@link ActiveDeviceUse}
+ * @hide
+ */
+ @SystemApi
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean removeActiveDevice(@ActiveDeviceUse int profiles) {
+ if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
+ && profiles != ACTIVE_DEVICE_ALL) {
+ Log.e(TAG, "Invalid profiles param value in removeActiveDevice");
+ throw new IllegalArgumentException("Profiles must be one of "
+ + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
+ + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
+ + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.removeActiveDevice(profiles);
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+
+ return false;
+ }
+
+ /**
+ * Sets device as the active devices for the profiles passed into the function
*
* @param device is the remote bluetooth device
* @param profiles represents the purpose for which we are setting this as the active device.
@@ -1774,18 +1813,26 @@
* {@link BluetoothAdapter#ACTIVE_DEVICE_PHONE_CALL},
* {@link BluetoothAdapter#ACTIVE_DEVICE_ALL}
* @return false on immediate error, true otherwise
+ * @throws IllegalArgumentException if device is null or profiles is not one of
+ * {@link ActiveDeviceUse}
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
- public boolean setActiveDevice(@Nullable BluetoothDevice device,
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
+ public boolean setActiveDevice(@NonNull BluetoothDevice device,
@ActiveDeviceUse int profiles) {
+ if (device == null) {
+ Log.e(TAG, "setActiveDevice: Null device passed as parameter");
+ throw new IllegalArgumentException("device cannot be null");
+ }
if (profiles != ACTIVE_DEVICE_AUDIO && profiles != ACTIVE_DEVICE_PHONE_CALL
&& profiles != ACTIVE_DEVICE_ALL) {
Log.e(TAG, "Invalid profiles param value in setActiveDevice");
- return false;
+ throw new IllegalArgumentException("Profiles must be one of "
+ + "BluetoothAdapter.ACTIVE_DEVICE_AUDIO, "
+ + "BluetoothAdapter.ACTIVE_DEVICE_PHONE_CALL, or "
+ + "BluetoothAdapter.ACTIVE_DEVICE_ALL");
}
-
try {
mServiceLock.readLock().lock();
if (mService != null) {
@@ -2162,6 +2209,33 @@
}
/**
+ * Fetches a list of the most recently connected bluetooth devices ordered by how recently they
+ * were connected with most recently first and least recently last
+ *
+ * @return {@link List} of bonded {@link BluetoothDevice} ordered by how recently they were
+ * connected
+ *
+ * @hide
+ */
+ @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ public @NonNull List<BluetoothDevice> getMostRecentlyConnectedDevices() {
+ if (getState() != STATE_ON) {
+ return new ArrayList<>();
+ }
+ try {
+ mServiceLock.readLock().lock();
+ if (mService != null) {
+ return mService.getMostRecentlyConnectedDevices();
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "", e);
+ } finally {
+ mServiceLock.readLock().unlock();
+ }
+ return new ArrayList<>();
+ }
+
+ /**
* Return the set of {@link BluetoothDevice} objects that are bonded
* (paired) to the local adapter.
* <p>If Bluetooth state is not {@link #STATE_ON}, this API
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index 12dc814c..5b60b85 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -23,6 +23,7 @@
import android.annotation.RequiresPermission;
import android.annotation.SdkConstant;
import android.annotation.SdkConstant.SdkConstantType;
+import android.annotation.SuppressLint;
import android.annotation.SystemApi;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
@@ -179,9 +180,10 @@
* <p>Always contains the extra field {@link #EXTRA_DEVICE}.
* <p>Requires {@link android.Manifest.permission#BLUETOOTH} to receive.
*/
+ @SuppressLint("ActionValue")
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
public static final String ACTION_ALIAS_CHANGED =
- "android.bluetooth.action.ALIAS_CHANGED";
+ "android.bluetooth.device.action.ALIAS_CHANGED";
/**
* Broadcast Action: Indicates a change in the bond state of a remote
@@ -1091,7 +1093,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setAlias(@NonNull String alias) {
final IBluetooth service = sService;
if (service == null) {
diff --git a/core/java/android/bluetooth/BluetoothHidDevice.java b/core/java/android/bluetooth/BluetoothHidDevice.java
index a923be6..b5959c0 100644
--- a/core/java/android/bluetooth/BluetoothHidDevice.java
+++ b/core/java/android/bluetooth/BluetoothHidDevice.java
@@ -706,7 +706,7 @@
* @hide
*/
@SystemApi
- @RequiresPermission(Manifest.permission.BLUETOOTH_ADMIN)
+ @RequiresPermission(Manifest.permission.BLUETOOTH_PRIVILEGED)
public boolean setConnectionPolicy(@NonNull BluetoothDevice device,
@ConnectionPolicy int connectionPolicy) {
log("setConnectionPolicy(" + device + ", " + connectionPolicy + ")");
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index dfa4fb7..ec40b7e 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -5728,14 +5728,13 @@
* shared, however common state (ClassLoader, other Resources for the
* same configuration) may be so the Context itself can be fairly lightweight.
*
- * The returned display Context provides a {@link WindowManager}
- * (see {@link #getSystemService(String)}) that is configured to show windows
- * on the given display. The WindowManager's {@link WindowManager#getDefaultDisplay}
- * method can be used to retrieve the Display from the returned Context.
+ * To obtain an instance of a {@link WindowManager} (see {@link #getSystemService(String)}) that
+ * is configured to show windows on the given display call
+ * {@link #createWindowContext(int, Bundle)} on the returned display Context or use an
+ * {@link android.app.Activity}.
*
- * @param display A {@link Display} object specifying the display
- * for whose metrics the Context's resources should be tailored and upon which
- * new windows should be shown.
+ * @param display A {@link Display} object specifying the display for whose metrics the
+ * Context's resources should be tailored.
*
* @return A {@link Context} for the display.
*/
@@ -5763,7 +5762,7 @@
* final DisplayManager dm = anyContext.getSystemService(DisplayManager.class);
* final Display primaryDisplay = dm.getDisplay(DEFAULT_DISPLAY);
* final Context windowContext = anyContext.createDisplayContext(primaryDisplay)
- * .createWindowContext(TYPE_APPLICATION_OVERLAY);
+ * .createWindowContext(TYPE_APPLICATION_OVERLAY, null);
* final View overlayView = Inflater.from(windowContext).inflate(someLayoutXml, null);
*
* // WindowManager.LayoutParams initialization
@@ -5783,6 +5782,7 @@
* </p>
*
* @param type Window type in {@link WindowManager.LayoutParams}
+ * @param options Bundle used to pass window-related options.
* @return A {@link Context} that can be used to create windows.
* @throws UnsupportedOperationException if this is called on a non-UI context, such as
* {@link android.app.Application Application} or {@link android.app.Service Service}.
@@ -5794,7 +5794,7 @@
* @see #WALLPAPER_SERVICE
* @throws IllegalArgumentException if token is invalid
*/
- public @NonNull Context createWindowContext(int type) {
+ public @NonNull Context createWindowContext(int type, @Nullable Bundle options) {
throw new RuntimeException("Not implemented. Must override in a subclass.");
}
diff --git a/core/java/android/content/ContextWrapper.java b/core/java/android/content/ContextWrapper.java
index b2b7988..f6515e8 100644
--- a/core/java/android/content/ContextWrapper.java
+++ b/core/java/android/content/ContextWrapper.java
@@ -978,8 +978,8 @@
@Override
@NonNull
- public Context createWindowContext(int type) {
- return mBase.createWindowContext(type);
+ public Context createWindowContext(int type, @Nullable Bundle options) {
+ return mBase.createWindowContext(type, options);
}
@Override
diff --git a/core/java/android/hardware/camera2/CameraManager.java b/core/java/android/hardware/camera2/CameraManager.java
index 9ee56a9..c5b9a43 100644
--- a/core/java/android/hardware/camera2/CameraManager.java
+++ b/core/java/android/hardware/camera2/CameraManager.java
@@ -316,6 +316,7 @@
CameraManagerGlobal.get().unregisterTorchCallback(callback);
}
+ // TODO(b/147726300): Investigate how to support foldables/multi-display devices.
private Size getDisplaySize() {
Size ret = new Size(0, 0);
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index a385771..7615b87c 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -91,7 +91,7 @@
private boolean mIdle = true;
/** map request IDs to callback/request data */
- private final SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
+ private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
new SparseArray<CaptureCallbackHolder>();
private int mRepeatingRequestId = REQUEST_ID_NONE;
@@ -123,7 +123,7 @@
* An object tracking received frame numbers.
* Updated when receiving callbacks from ICameraDeviceCallbacks.
*/
- private final FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
+ private FrameNumberTracker mFrameNumberTracker = new FrameNumberTracker();
private CameraCaptureSessionCore mCurrentSession;
private int mNextSessionId = 0;
@@ -892,6 +892,7 @@
HashSet<Integer> offlineStreamIds = new HashSet<Integer>();
SparseArray<OutputConfiguration> offlineConfiguredOutputs =
new SparseArray<OutputConfiguration>();
+ CameraOfflineSession ret;
synchronized(mInterfaceLock) {
if (mOfflineSessionImpl != null) {
@@ -919,15 +920,20 @@
offlineStreamIds.add(streamId);
}
+ stopRepeating();
mOfflineSessionImpl = new CameraOfflineSessionImpl(mCameraId,
mCharacteristics, executor, listener, offlineConfiguredOutputs,
- mConfiguredInput, mFrameNumberTracker, mCaptureCallbackMap,
+ mConfiguredInput, mConfiguredOutputs, mFrameNumberTracker, mCaptureCallbackMap,
mRequestLastFrameNumbersList);
+ ret = mOfflineSessionImpl;
mOfflineSwitchService = Executors.newSingleThreadExecutor();
mConfiguredOutputs.clear();
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
+ mIdle = true;
+ mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
+ mFrameNumberTracker = new FrameNumberTracker();
mCurrentSession.closeWithoutDraining();
mCurrentSession = null;
@@ -949,11 +955,13 @@
mOfflineSessionImpl.setRemoteSession(remoteOfflineSession);
} catch (CameraAccessException e) {
mOfflineSessionImpl.notifyFailedSwitch();
+ } finally {
+ mOfflineSessionImpl = null;
}
}
});
- return mOfflineSessionImpl;
+ return ret;
}
public boolean supportsOfflineProcessing(Surface surface) {
diff --git a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
index 1db377a..1d9d644 100644
--- a/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraOfflineSessionImpl.java
@@ -63,6 +63,7 @@
private SimpleEntry<Integer, InputConfiguration> mOfflineInput =
new SimpleEntry<>(REQUEST_ID_NONE, null);
private SparseArray<OutputConfiguration> mOfflineOutputs = new SparseArray<>();
+ private SparseArray<OutputConfiguration> mConfiguredOutputs = new SparseArray<>();
final Object mInterfaceLock = new Object(); // access from this class and Session only!
@@ -96,6 +97,7 @@
Executor offlineExecutor, CameraOfflineSessionCallback offlineCallback,
SparseArray<OutputConfiguration> offlineOutputs,
SimpleEntry<Integer, InputConfiguration> offlineInput,
+ SparseArray<OutputConfiguration> configuredOutputs,
FrameNumberTracker frameNumberTracker, SparseArray<CaptureCallbackHolder> callbackMap,
List<RequestLastFrameNumbersHolder> frameNumberList) {
if ((cameraId == null) || (characteristics == null)) {
@@ -117,6 +119,7 @@
mOfflineRequestLastFrameNumbersList.addAll(frameNumberList);
mFrameNumberTracker = frameNumberTracker;
mCaptureCallbackMap = callbackMap;
+ mConfiguredOutputs = configuredOutputs;
mOfflineOutputs = offlineOutputs;
mOfflineInput = offlineInput;
mOfflineExecutor = checkNotNull(offlineExecutor, "offline executor must not be null");
@@ -137,9 +140,6 @@
@Override
public void onDeviceError(final int errorCode, CaptureResultExtras resultExtras) {
synchronized(mInterfaceLock) {
- if (mRemoteSession == null) {
- return; // Camera already closed
- }
switch (errorCode) {
case CameraDeviceCallbacks.ERROR_CAMERA_REQUEST:
@@ -177,6 +177,11 @@
@Override
public void onDeviceIdle() {
synchronized(mInterfaceLock) {
+ if (mRemoteSession == null) {
+ Log.v(TAG, "Ignoring idle state notifications during offline switches");
+ return;
+ }
+
Runnable idleDispatch = new Runnable() {
@Override
public void run() {
@@ -203,8 +208,6 @@
final CaptureCallbackHolder holder;
synchronized(mInterfaceLock) {
- if (mRemoteSession == null) return; // Camera already closed
-
// Get the callback for this frame ID, if there is one
holder = CameraOfflineSessionImpl.this.mCaptureCallbackMap.get(requestId);
@@ -269,8 +272,6 @@
long frameNumber = resultExtras.getFrameNumber();
synchronized(mInterfaceLock) {
- if (mRemoteSession == null) return; // Camera already closed
-
// TODO: Handle CameraCharacteristics access from CaptureResult correctly.
result.set(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE,
mCharacteristics.get(CameraCharacteristics.LENS_INFO_SHADING_MAP_SIZE));
@@ -445,8 +446,12 @@
if (errorCode == ERROR_CAMERA_BUFFER) {
// Because 1 stream id could map to multiple surfaces, we need to specify both
// streamId and surfaceId.
- OutputConfiguration config = mOfflineOutputs.get(
- resultExtras.getErrorStreamId());
+ OutputConfiguration config;
+ if ((mRemoteSession == null) && !isClosed()) {
+ config = mConfiguredOutputs.get(resultExtras.getErrorStreamId());
+ } else {
+ config = mOfflineOutputs.get(resultExtras.getErrorStreamId());
+ }
if (config == null) {
Log.v(TAG, String.format(
"Stream %d has been removed. Skipping buffer lost callback",
@@ -538,11 +543,6 @@
final Executor executor;
final CameraCaptureSession.CaptureCallback callback;
synchronized(mInterfaceLock) {
- if (mRemoteSession == null) {
- Log.w(TAG, "Camera closed while checking sequences");
- return;
- }
-
int index = mCaptureCallbackMap.indexOfKey(requestId);
holder = (index >= 0) ?
mCaptureCallbackMap.valueAt(index) : null;
@@ -575,7 +575,7 @@
}
// Call onCaptureSequenceCompleted
- if ((sequenceCompleted) && (callback != null) && (executor == null)) {
+ if ((sequenceCompleted) && (callback != null) && (executor != null)) {
Runnable resultDispatch = new Runnable() {
@Override
public void run() {
@@ -592,7 +592,12 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
+
+ if (mCaptureCallbackMap.size() == 0) {
+ getCallbacks().onDeviceIdle();
+ }
}
+
}
}
@@ -686,9 +691,7 @@
Runnable closeDispatch = new Runnable() {
@Override
public void run() {
- if (!isClosed()) {
- mOfflineCallback.onClosed(CameraOfflineSessionImpl.this);
- }
+ mOfflineCallback.onClosed(CameraOfflineSessionImpl.this);
}
};
diff --git a/core/java/android/hardware/display/AmbientDisplayConfiguration.java b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
index 3e995b6..ece5c28 100644
--- a/core/java/android/hardware/display/AmbientDisplayConfiguration.java
+++ b/core/java/android/hardware/display/AmbientDisplayConfiguration.java
@@ -194,6 +194,11 @@
return !TextUtils.isEmpty(ambientDisplayComponent());
}
+ /** {@hide} */
+ public boolean dozeSuppressed(int user) {
+ return boolSettingDefaultOff(Settings.Secure.SUPPRESS_DOZE, user);
+ }
+
private boolean alwaysOnDisplayAvailable() {
return mContext.getResources().getBoolean(R.bool.config_dozeAlwaysOnDisplayAvailable);
}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 92047dc..49e1d5e 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -16,7 +16,6 @@
package android.inputmethodservice;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
@@ -39,6 +38,7 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.content.ComponentName;
import android.content.Context;
+import android.content.pm.PackageManager;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.content.res.TypedArray;
@@ -52,7 +52,6 @@
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
-import android.os.Process;
import android.os.RemoteException;
import android.os.ResultReceiver;
import android.os.SystemClock;
@@ -64,6 +63,7 @@
import android.util.Log;
import android.util.PrintWriterPrinter;
import android.util.Printer;
+import android.util.Size;
import android.view.Gravity;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
@@ -452,6 +452,9 @@
@Nullable
private InlineSuggestionsRequestInfo mInlineSuggestionsRequestInfo = null;
+ private boolean mAutomotiveHideNavBarForKeyboard;
+ private boolean mIsAutomotive;
+
/**
* An opaque {@link Binder} token of window requesting {@link InputMethodImpl#showSoftInput}
* The original app window token is passed from client app window.
@@ -560,12 +563,10 @@
@Override
public void updateInputMethodDisplay(int displayId) {
// Update display for adding IME window to the right display.
- if (displayId != DEFAULT_DISPLAY) {
- // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
- // for update resources & configuration correctly when show soft input
- // in non-default display.
- updateDisplay(displayId);
- }
+ // TODO(b/111364446) Need to address context lifecycle issue if need to re-create
+ // for update resources & configuration correctly when show soft input
+ // in non-default display.
+ updateDisplay(displayId);
}
/**
@@ -1233,6 +1234,11 @@
super.onCreate();
mImm = (InputMethodManager)getSystemService(INPUT_METHOD_SERVICE);
mSettingsObserver = SettingsObserver.createAndRegister(this);
+
+ mIsAutomotive = isAutomotive();
+ mAutomotiveHideNavBarForKeyboard = getApplicationContext().getResources().getBoolean(
+ com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
+
// TODO(b/111364446) Need to address context lifecycle issue if need to re-create
// for update resources & configuration correctly when show soft input
// in non-default display.
@@ -1242,12 +1248,16 @@
WindowManager.LayoutParams.TYPE_INPUT_METHOD, Gravity.BOTTOM, false);
mWindow.getWindow().getAttributes().setFitInsetsTypes(WindowInsets.Type.statusBars());
- // IME layout should always be inset by navigation bar, no matter it's current visibility.
+ // IME layout should always be inset by navigation bar, no matter its current visibility,
+ // unless automotive requests it, since automotive may hide the navigation bar.
mWindow.getWindow().getDecorView().setOnApplyWindowInsetsListener(
(v, insets) -> v.onApplyWindowInsets(
new WindowInsets.Builder(insets).setInsets(
navigationBars(),
- insets.getInsetsIgnoringVisibility(navigationBars()))
+ mIsAutomotive && mAutomotiveHideNavBarForKeyboard
+ ? android.graphics.Insets.NONE
+ : insets.getInsetsIgnoringVisibility(navigationBars())
+ )
.build()));
// For ColorView in DecorView to work, FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS needs to be set
@@ -1466,8 +1476,9 @@
* screen orientation changes.
*/
public int getMaxWidth() {
- WindowManager wm = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
- return wm.getDefaultDisplay().getWidth();
+ final WindowManager windowManager = getSystemService(WindowManager.class);
+ final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
+ return windowSize.getWidth();
}
/**
@@ -3286,6 +3297,11 @@
: IME_VISIBLE) : 0);
}
+ private boolean isAutomotive() {
+ return getApplicationContext().getPackageManager().hasSystemFeature(
+ PackageManager.FEATURE_AUTOMOTIVE);
+ }
+
/**
* Performs a dump of the InputMethodService's internal state. Override
* to add your own information to the dump.
diff --git a/core/java/android/inputmethodservice/SoftInputWindow.java b/core/java/android/inputmethodservice/SoftInputWindow.java
index 356b344..0513fee 100644
--- a/core/java/android/inputmethodservice/SoftInputWindow.java
+++ b/core/java/android/inputmethodservice/SoftInputWindow.java
@@ -21,7 +21,6 @@
import android.annotation.IntDef;
import android.app.Dialog;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.graphics.Rect;
import android.os.Debug;
import android.os.IBinder;
@@ -51,7 +50,6 @@
final int mWindowType;
final int mGravity;
final boolean mTakesFocus;
- final boolean mAutomotiveHideNavBarForKeyboard;
private final Rect mBounds = new Rect();
@Retention(SOURCE)
@@ -136,8 +134,6 @@
mWindowType = windowType;
mGravity = gravity;
mTakesFocus = takesFocus;
- mAutomotiveHideNavBarForKeyboard = context.getResources().getBoolean(
- com.android.internal.R.bool.config_automotiveHideNavBarForKeyboard);
initDockWindow();
}
@@ -251,11 +247,6 @@
windowModFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
}
- if (isAutomotive() && mAutomotiveHideNavBarForKeyboard) {
- windowSetFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
- windowModFlags |= WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
- }
-
getWindow().setFlags(windowSetFlags, windowModFlags);
}
@@ -347,10 +338,6 @@
mWindowState = newState;
}
- private boolean isAutomotive() {
- return getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
- }
-
private static String stateToString(@SoftInputWindowState int state) {
switch (state) {
case SoftInputWindowState.TOKEN_PENDING:
diff --git a/core/java/android/net/ConnectivityDiagnosticsManager.java b/core/java/android/net/ConnectivityDiagnosticsManager.java
index b13e4b7..140363c 100644
--- a/core/java/android/net/ConnectivityDiagnosticsManager.java
+++ b/core/java/android/net/ConnectivityDiagnosticsManager.java
@@ -25,13 +25,16 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PersistableBundle;
+import android.os.RemoteException;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.Preconditions;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
/**
@@ -57,6 +60,11 @@
* </ul>
*/
public class ConnectivityDiagnosticsManager {
+ /** @hide */
+ @VisibleForTesting
+ public static final Map<ConnectivityDiagnosticsCallback, ConnectivityDiagnosticsBinder>
+ sCallbacks = new ConcurrentHashMap<>();
+
private final Context mContext;
private final IConnectivityManager mService;
@@ -631,8 +639,9 @@
/**
* Registers a ConnectivityDiagnosticsCallback with the System.
*
- * <p>Only apps that offer network connectivity to the user are allowed to register callbacks.
- * This includes:
+ * <p>Only apps that offer network connectivity to the user should be registering callbacks.
+ * These are the only apps whose callbacks will be invoked by the system. Apps considered to
+ * meet these conditions include:
*
* <ul>
* <li>Carrier apps with active subscriptions
@@ -640,15 +649,14 @@
* <li>WiFi Suggesters
* </ul>
*
- * <p>Callbacks will be limited to receiving notifications for networks over which apps provide
- * connectivity.
+ * <p>Callbacks registered by apps not meeting the above criteria will not be invoked.
*
* <p>If a registering app loses its relevant permissions, any callbacks it registered will
* silently stop receiving callbacks.
*
- * <p>Each register() call <b>MUST</b> use a unique ConnectivityDiagnosticsCallback instance. If
- * a single instance is registered with multiple NetworkRequests, an IllegalArgumentException
- * will be thrown.
+ * <p>Each register() call <b>MUST</b> use a ConnectivityDiagnosticsCallback instance that is
+ * not currently registered. If a ConnectivityDiagnosticsCallback instance is registered with
+ * multiple NetworkRequests, an IllegalArgumentException will be thrown.
*
* @param request The NetworkRequest that will be used to match with Networks for which
* callbacks will be fired
@@ -657,15 +665,21 @@
* System
* @throws IllegalArgumentException if the same callback instance is registered with multiple
* NetworkRequests
- * @throws SecurityException if the caller does not have appropriate permissions to register a
- * callback
*/
public void registerConnectivityDiagnosticsCallback(
@NonNull NetworkRequest request,
@NonNull Executor e,
@NonNull ConnectivityDiagnosticsCallback callback) {
- // TODO(b/143187964): implement ConnectivityDiagnostics functionality
- throw new UnsupportedOperationException("registerCallback() not supported yet");
+ final ConnectivityDiagnosticsBinder binder = new ConnectivityDiagnosticsBinder(callback, e);
+ if (sCallbacks.putIfAbsent(callback, binder) != null) {
+ throw new IllegalArgumentException("Callback is currently registered");
+ }
+
+ try {
+ mService.registerConnectivityDiagnosticsCallback(binder, request);
+ } catch (RemoteException exception) {
+ exception.rethrowFromSystemServer();
+ }
}
/**
@@ -678,7 +692,15 @@
*/
public void unregisterConnectivityDiagnosticsCallback(
@NonNull ConnectivityDiagnosticsCallback callback) {
- // TODO(b/143187964): implement ConnectivityDiagnostics functionality
- throw new UnsupportedOperationException("registerCallback() not supported yet");
+ // unconditionally removing from sCallbacks prevents race conditions here, since remove() is
+ // atomic.
+ final ConnectivityDiagnosticsBinder binder = sCallbacks.remove(callback);
+ if (binder == null) return;
+
+ try {
+ mService.unregisterConnectivityDiagnosticsCallback(binder);
+ } catch (RemoteException exception) {
+ exception.rethrowFromSystemServer();
+ }
}
}
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index ce9693d..fa12c08 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -3322,15 +3322,19 @@
// of dependent changes that would conflict throughout the automerger graph. Having this
// temporarily helps with the process of going through with all these dependent changes across
// the entire tree.
+ // STOPSHIP (b/148055573) : remove this before R is released.
/**
* @hide
* Register a NetworkAgent with ConnectivityService.
* @return Network corresponding to NetworkAgent.
+ * @deprecated use the version that takes a NetworkScore and a provider ID.
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
+ @Deprecated
public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
NetworkCapabilities nc, int score, NetworkAgentConfig config) {
- return registerNetworkAgent(messenger, ni, lp, nc, score, config, NetworkProvider.ID_NONE);
+ final NetworkScore ns = new NetworkScore.Builder().setLegacyScore(score).build();
+ return registerNetworkAgent(messenger, ni, lp, nc, ns, config, NetworkProvider.ID_NONE);
}
/**
@@ -3340,7 +3344,7 @@
*/
@RequiresPermission(android.Manifest.permission.NETWORK_FACTORY)
public Network registerNetworkAgent(Messenger messenger, NetworkInfo ni, LinkProperties lp,
- NetworkCapabilities nc, int score, NetworkAgentConfig config, int providerId) {
+ NetworkCapabilities nc, NetworkScore score, NetworkAgentConfig config, int providerId) {
try {
return mService.registerNetworkAgent(messenger, ni, lp, nc, score, config, providerId);
} catch (RemoteException e) {
diff --git a/core/java/android/net/IConnectivityManager.aidl b/core/java/android/net/IConnectivityManager.aidl
index 3e9e7fa..0dc66b5 100644
--- a/core/java/android/net/IConnectivityManager.aidl
+++ b/core/java/android/net/IConnectivityManager.aidl
@@ -26,6 +26,7 @@
import android.net.NetworkInfo;
import android.net.NetworkQuotaInfo;
import android.net.NetworkRequest;
+import android.net.NetworkScore;
import android.net.NetworkState;
import android.net.ISocketKeepaliveCallback;
import android.net.ProxyInfo;
@@ -154,7 +155,7 @@
void declareNetworkRequestUnfulfillable(in NetworkRequest request);
Network registerNetworkAgent(in Messenger messenger, in NetworkInfo ni, in LinkProperties lp,
- in NetworkCapabilities nc, int score, in NetworkAgentConfig config,
+ in NetworkCapabilities nc, in NetworkScore score, in NetworkAgentConfig config,
in int factorySerialNumber);
NetworkRequest requestNetwork(in NetworkCapabilities networkCapabilities,
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index 7cc569a..ddf8dbb 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -117,13 +117,6 @@
public static final int EVENT_NETWORK_PROPERTIES_CHANGED = BASE + 3;
/**
- * Centralize the place where base network score, and network score scaling, will be
- * stored, so as we can consistently compare apple and oranges, or wifi, ethernet and LTE
- * @hide
- */
- public static final int WIFI_BASE_SCORE = 60;
-
- /**
* Sent by the NetworkAgent to ConnectivityService to pass the current
* network score.
* obj = network score Integer
@@ -272,7 +265,13 @@
*/
public static final int CMD_REMOVE_KEEPALIVE_PACKET_FILTER = BASE + 17;
+ // STOPSHIP (b/148055573) : remove this before R is released.
+ private static NetworkScore makeNetworkScore(int score) {
+ return new NetworkScore.Builder().setLegacyScore(score).build();
+ }
+
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score) {
this(looper, context, logTag, ni, nc, lp, score, null, NetworkProvider.ID_NONE);
@@ -280,6 +279,7 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config) {
this(looper, context, logTag, ni, nc, lp, score, config, NetworkProvider.ID_NONE);
@@ -287,6 +287,7 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, int providerId) {
this(looper, context, logTag, ni, nc, lp, score, null, providerId);
@@ -294,10 +295,12 @@
}
/** @hide TODO: remove and replace usage with the public constructor. */
+ // STOPSHIP (b/148055573) : remove this before R is released.
public NetworkAgent(Looper looper, Context context, String logTag, NetworkInfo ni,
NetworkCapabilities nc, LinkProperties lp, int score, NetworkAgentConfig config,
int providerId) {
- this(looper, context, logTag, nc, lp, score, config, providerId, ni, true /* legacy */);
+ this(looper, context, logTag, nc, lp, makeNetworkScore(score), config, providerId, ni,
+ true /* legacy */);
register();
}
@@ -323,8 +326,9 @@
* @param provider the {@link NetworkProvider} managing this agent.
*/
public NetworkAgent(@NonNull Context context, @NonNull Looper looper, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
- @NonNull NetworkAgentConfig config, @Nullable NetworkProvider provider) {
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp,
+ @NonNull NetworkScore score, @NonNull NetworkAgentConfig config,
+ @Nullable NetworkProvider provider) {
this(looper, context, logTag, nc, lp, score, config,
provider == null ? NetworkProvider.ID_NONE : provider.getProviderId(),
getLegacyNetworkInfo(config), false /* legacy */);
@@ -334,12 +338,12 @@
public final Context context;
public final NetworkCapabilities capabilities;
public final LinkProperties properties;
- public final int score;
+ public final NetworkScore score;
public final NetworkAgentConfig config;
public final NetworkInfo info;
InitialConfiguration(@NonNull Context context, @NonNull NetworkCapabilities capabilities,
- @NonNull LinkProperties properties, int score, @NonNull NetworkAgentConfig config,
- @NonNull NetworkInfo info) {
+ @NonNull LinkProperties properties, @NonNull NetworkScore score,
+ @NonNull NetworkAgentConfig config, @NonNull NetworkInfo info) {
this.context = context;
this.capabilities = capabilities;
this.properties = properties;
@@ -351,7 +355,7 @@
private volatile InitialConfiguration mInitialConfiguration;
private NetworkAgent(@NonNull Looper looper, @NonNull Context context, @NonNull String logTag,
- @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, int score,
+ @NonNull NetworkCapabilities nc, @NonNull LinkProperties lp, NetworkScore score,
@NonNull NetworkAgentConfig config, int providerId, @NonNull NetworkInfo ni,
boolean legacy) {
mHandler = new NetworkAgentHandler(looper);
@@ -646,22 +650,8 @@
* Must be called by the agent to update the score of this network.
* @param score the new score.
*/
- public void sendNetworkScore(int score) {
- if (score < 0) {
- throw new IllegalArgumentException("Score must be >= 0");
- }
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, score);
- updateScore(ns);
- }
-
- /**
- * Must be called by the agent when it has a new {@link NetworkScore} for this network.
- * @param ns the new score.
- * @hide TODO: unhide the NetworkScore class, and rename to sendNetworkScore.
- */
- public void updateScore(@NonNull NetworkScore ns) {
- queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, new NetworkScore(ns));
+ public void sendNetworkScore(@NonNull final NetworkScore score) {
+ queueOrSendMessage(EVENT_NETWORK_SCORE_CHANGED, score);
}
/**
diff --git a/core/java/android/net/NetworkScore.aidl b/core/java/android/net/NetworkScore.aidl
new file mode 100644
index 0000000..be9a98b
--- /dev/null
+++ b/core/java/android/net/NetworkScore.aidl
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net;
+
+parcelable NetworkScore;
diff --git a/core/java/android/net/NetworkScore.java b/core/java/android/net/NetworkScore.java
index 13f2994..ae17378 100644
--- a/core/java/android/net/NetworkScore.java
+++ b/core/java/android/net/NetworkScore.java
@@ -15,12 +15,18 @@
*/
package android.net;
+import android.annotation.IntDef;
+import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.SystemApi;
+import android.annotation.TestApi;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.Objects;
/**
@@ -28,57 +34,392 @@
*
* A NetworkScore object represents the characteristics of a network that affects how good the
* network is considered for a particular use.
+ *
+ * This class is not thread-safe.
* @hide
*/
+@TestApi
+@SystemApi
public final class NetworkScore implements Parcelable {
+ /** An object containing scoring-relevant metrics for a network. */
+ public static class Metrics {
+ /** Value meaning the latency is unknown. */
+ public static final int LATENCY_UNKNOWN = -1;
- // The key of bundle which is used to get the legacy network score of NetworkAgentInfo.
- // TODO: Remove this when the transition to NetworkScore is over.
- public static final String LEGACY_SCORE = "LEGACY_SCORE";
+ /** Value meaning the bandwidth is unknown. */
+ public static final int BANDWIDTH_UNKNOWN = -1;
+
+ /**
+ * Round-trip delay in milliseconds to the relevant destination for this Metrics object.
+ *
+ * LATENCY_UNKNOWN if unknown.
+ */
+ @IntRange(from = LATENCY_UNKNOWN)
+ public final int latencyMs;
+
+ /**
+ * Downlink in kB/s with the relevant destination for this Metrics object.
+ *
+ * BANDWIDTH_UNKNOWN if unknown. If directional bandwidth is unknown, up and downlink
+ * bandwidth can have the same value.
+ */
+ @IntRange(from = BANDWIDTH_UNKNOWN)
+ public final int downlinkBandwidthKBps;
+
+ /**
+ * Uplink in kB/s with the relevant destination for this Metrics object.
+ *
+ * BANDWIDTH_UNKNOWN if unknown. If directional bandwidth is unknown, up and downlink
+ * bandwidth can have the same value.
+ */
+ @IntRange(from = BANDWIDTH_UNKNOWN)
+ public final int uplinkBandwidthKBps;
+
+ /** Constructor */
+ public Metrics(@IntRange(from = LATENCY_UNKNOWN) final int latency,
+ @IntRange(from = BANDWIDTH_UNKNOWN) final int downlinkBandwidth,
+ @IntRange(from = BANDWIDTH_UNKNOWN) final int uplinkBandwidth) {
+ latencyMs = latency;
+ downlinkBandwidthKBps = downlinkBandwidth;
+ uplinkBandwidthKBps = uplinkBandwidth;
+ }
+
+ /** toString */
+ public String toString() {
+ return "latency = " + latencyMs + " downlinkBandwidth = " + downlinkBandwidthKBps
+ + "uplinkBandwidth = " + uplinkBandwidthKBps;
+ }
+
+ @NonNull
+ public static final Metrics EMPTY =
+ new Metrics(LATENCY_UNKNOWN, BANDWIDTH_UNKNOWN, BANDWIDTH_UNKNOWN);
+ }
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "POLICY_", value = {
+ POLICY_LOCKDOWN_VPN,
+ POLICY_VPN,
+ POLICY_IGNORE_ON_WIFI,
+ POLICY_DEFAULT_SUBSCRIPTION
+ })
+ public @interface Policy {
+ }
+
+ /**
+ * This network is a VPN with lockdown enabled.
+ *
+ * If a network with this bit is present in the list of candidates and not connected,
+ * no network can satisfy the request.
+ */
+ public static final int POLICY_LOCKDOWN_VPN = 1 << 0;
+
+ /**
+ * This network is a VPN.
+ *
+ * If a network with this bit is present and the request UID is included in the UID ranges
+ * of this network, it outscores all other networks without this bit.
+ */
+ public static final int POLICY_VPN = 1 << 1;
+
+ /**
+ * This network should not be used if a previously validated WiFi network is available.
+ *
+ * If a network with this bit is present and a previously validated WiFi is present too, the
+ * network with this bit is outscored by it. This stays true if the WiFi network
+ * becomes unvalidated : this network will not be considered.
+ */
+ public static final int POLICY_IGNORE_ON_WIFI = 1 << 2;
+
+ /**
+ * This network is the default subscription for this transport.
+ *
+ * If a network with this bit is present, other networks of the same transport without this
+ * bit are outscored by it. A device with two active subscriptions and a setting
+ * to decide the default one would have this policy bit on the network for the default
+ * subscription so that when both are active at the same time, the device chooses the
+ * network associated with the default subscription rather than the one with the best link
+ * quality (which will happen if policy doesn't dictate otherwise).
+ */
+ public static final int POLICY_DEFAULT_SUBSCRIPTION = 1 << 3;
+
+ /**
+ * Policy bits for this network. Filled in by the NetworkAgent.
+ */
+ private final int mPolicy;
+
+ /**
+ * Predicted metrics to the gateway (it contains latency and bandwidth to the gateway).
+ * This is filled by the NetworkAgent with the theoretical values of the link if available,
+ * although they may fill it with predictions from historical data if available.
+ * Note that while this member cannot be null, any and all of its members can be unknown.
+ */
@NonNull
- private final Bundle mExtensions;
+ private final Metrics mLinkLayerMetrics;
- public NetworkScore() {
- mExtensions = new Bundle();
- }
+ /**
+ * Predicted metrics to representative servers.
+ * This is filled by connectivity with (if available) a best-effort estimate of the performance
+ * information to servers the user connects to in similar circumstances, and predicted from
+ * actual measurements if possible.
+ * Note that while this member cannot be null, any and all of its members can be unknown.
+ */
+ @NonNull
+ private final Metrics mEndToEndMetrics;
- public NetworkScore(@NonNull NetworkScore source) {
- mExtensions = new Bundle(source.mExtensions);
+ /** Value meaning the signal strength is unknown. */
+ public static final int UNKNOWN_SIGNAL_STRENGTH = -1;
+
+ /** The smallest meaningful signal strength. */
+ public static final int MIN_SIGNAL_STRENGTH = 0;
+
+ /** The largest meaningful signal strength. */
+ public static final int MAX_SIGNAL_STRENGTH = 1000;
+
+ /**
+ * User-visible measure of the strength of the signal normalized 1~1000.
+ * This represents a measure of the signal strength for this network.
+ * If unknown, this has value UNKNOWN_SIGNAL_STRENGTH.
+ */
+ // A good way to populate this value is to fill it with the number of bars displayed in
+ // the system UI, scaled 0 to 1000. This is what the user sees and it makes sense to them.
+ // Cellular for example could quantize the ASU value (see SignalStrength#getAsuValue) into
+ // this, while WiFi could scale the RSSI (see WifiManager#calculateSignalLevel).
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ private final int mSignalStrength;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = "RANGE_", value = {
+ RANGE_UNKNOWN, RANGE_CLOSE, RANGE_SHORT, RANGE_MEDIUM, RANGE_LONG
+ })
+ public @interface Range {
}
/**
- * Put the value of parcelable inside the bundle by key.
+ * The range of this network is not known.
+ * This can be used by VPN the range of which depends on the range of the underlying network.
*/
- public void putExtension(@Nullable String key, @Nullable Parcelable value) {
- mExtensions.putParcelable(key, value);
+ public static final int RANGE_UNKNOWN = 0;
+
+ /**
+ * This network typically only operates at close range, like an NFC beacon.
+ */
+ public static final int RANGE_CLOSE = 1;
+
+ /**
+ * This network typically operates at a range of a few meters to a few dozen meters, like WiFi.
+ */
+ public static final int RANGE_SHORT = 2;
+
+ /**
+ * This network typically operates at a range of a few dozen to a few hundred meters, like CBRS.
+ */
+ public static final int RANGE_MEDIUM = 3;
+
+ /**
+ * This network typically offers continuous connectivity up to many kilometers away, like LTE.
+ */
+ public static final int RANGE_LONG = 4;
+
+ /**
+ * The typical range of this networking technology.
+ *
+ * This is one of the RANGE_* constants and is filled by the NetworkAgent.
+ * This may be useful when evaluating how desirable a network is, because for two networks that
+ * have equivalent performance and cost, the one that won't lose IP continuity when the user
+ * moves is probably preferable.
+ * Agents should fill this with the largest typical range this technology provides. See the
+ * descriptions of the individual constants for guidance.
+ *
+ * If unknown, this is set to RANGE_UNKNOWN.
+ */
+ @Range private final int mRange;
+
+ /**
+ * A prediction of whether this network is likely to be unusable in a few seconds.
+ *
+ * NetworkAgents set this to true to mean they are aware that usability is limited due to
+ * low signal strength, congestion, or other reasons, and indicates that the system should
+ * only use this network as a last resort. An example would be a WiFi network when the device
+ * is about to move outside of range.
+ *
+ * This is filled by the NetworkAgent. Agents that don't know whether this network is likely
+ * to be unusable soon should set this to false.
+ */
+ private final boolean mExiting;
+
+ /**
+ * The legacy score, as a migration strategy from Q to R.
+ * STOPSHIP : remove this before R ships.
+ */
+ private final int mLegacyScore;
+
+ /**
+ * Create a new NetworkScore object.
+ */
+ private NetworkScore(@Policy final int policy, @Nullable final Metrics l2Perf,
+ @Nullable final Metrics e2ePerf,
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ final int signalStrength,
+ @Range final int range, final boolean exiting, final int legacyScore) {
+ mPolicy = policy;
+ mLinkLayerMetrics = null != l2Perf ? l2Perf : Metrics.EMPTY;
+ mEndToEndMetrics = null != e2ePerf ? e2ePerf : Metrics.EMPTY;
+ mSignalStrength = signalStrength;
+ mRange = range;
+ mExiting = exiting;
+ mLegacyScore = legacyScore;
}
/**
- * Put the value of int inside the bundle by key.
+ * Utility function to return a copy of this with a different exiting value.
*/
- public void putIntExtension(@Nullable String key, int value) {
- mExtensions.putInt(key, value);
+ @NonNull public NetworkScore withExiting(final boolean exiting) {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
+ mSignalStrength, mRange, exiting, mLegacyScore);
}
/**
- * Get the value of non primitive type by key.
+ * Utility function to return a copy of this with a different signal strength.
*/
- public <T extends Parcelable> T getExtension(@Nullable String key) {
- return mExtensions.getParcelable(key);
+ @NonNull public NetworkScore withSignalStrength(
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH) final int signalStrength) {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToEndMetrics,
+ signalStrength, mRange, mExiting, mLegacyScore);
}
/**
- * Get the value of int by key.
+ * Returns whether this network has a particular policy flag.
+ * @param policy the policy, as one of the POLICY_* constants.
*/
- public int getIntExtension(@Nullable String key) {
- return mExtensions.getInt(key);
+ public boolean hasPolicy(@Policy final int policy) {
+ return 0 != (mPolicy & policy);
}
/**
- * Remove the entry by given key.
+ * Returns the Metrics representing the performance of the link layer.
+ *
+ * This contains the theoretical performance of the link, if available.
+ * Note that while this function cannot return null, any and/or all of the members of the
+ * returned object can be null if unknown.
*/
- public void removeExtension(@Nullable String key) {
- mExtensions.remove(key);
+ @NonNull public Metrics getLinkLayerMetrics() {
+ return mLinkLayerMetrics;
+ }
+
+ /**
+ * Returns the Metrics representing the end-to-end performance of the network.
+ *
+ * This contains the end-to-end performance of the link, if available.
+ * Note that while this function cannot return null, any and/or all of the members of the
+ * returned object can be null if unknown.
+ */
+ @NonNull public Metrics getEndToEndMetrics() {
+ return mEndToEndMetrics;
+ }
+
+ /**
+ * Returns the signal strength of this network normalized 0~1000, or UNKNOWN_SIGNAL_STRENGTH.
+ */
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ public int getSignalStrength() {
+ return mSignalStrength;
+ }
+
+ /**
+ * Returns the typical range of this network technology as one of the RANGE_* constants.
+ */
+ @Range public int getRange() {
+ return mRange;
+ }
+
+ /** Returns a prediction of whether this network is likely to be unusable in a few seconds. */
+ public boolean isExiting() {
+ return mExiting;
+ }
+
+ /**
+ * Get the legacy score.
+ * @hide
+ */
+ public int getLegacyScore() {
+ return mLegacyScore;
+ }
+
+ /** Builder for NetworkScore. */
+ public static class Builder {
+ private int mPolicy = 0;
+ @NonNull
+ private Metrics mLinkLayerMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+ Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
+ @NonNull
+ private Metrics mEndToMetrics = new Metrics(Metrics.LATENCY_UNKNOWN,
+ Metrics.BANDWIDTH_UNKNOWN, Metrics.BANDWIDTH_UNKNOWN);
+ private int mSignalStrength = UNKNOWN_SIGNAL_STRENGTH;
+ private int mRange = RANGE_UNKNOWN;
+ private boolean mExiting = false;
+ private int mLegacyScore = 0;
+ @NonNull private Bundle mExtensions = new Bundle();
+
+ /** Create a new builder. */
+ public Builder() { }
+
+ /** Add a policy flag. */
+ @NonNull public Builder addPolicy(@Policy final int policy) {
+ mPolicy |= policy;
+ return this;
+ }
+
+ /** Clear a policy flag */
+ @NonNull public Builder clearPolicy(@Policy final int policy) {
+ mPolicy &= ~policy;
+ return this;
+ }
+
+ /** Set the link layer metrics. */
+ @NonNull public Builder setLinkLayerMetrics(@NonNull final Metrics linkLayerMetrics) {
+ mLinkLayerMetrics = linkLayerMetrics;
+ return this;
+ }
+
+ /** Set the end-to-end metrics. */
+ @NonNull public Builder setEndToEndMetrics(@NonNull final Metrics endToEndMetrics) {
+ mEndToMetrics = endToEndMetrics;
+ return this;
+ }
+
+ /** Set the signal strength. */
+ @NonNull public Builder setSignalStrength(
+ @IntRange(from = UNKNOWN_SIGNAL_STRENGTH, to = MAX_SIGNAL_STRENGTH)
+ final int signalStrength) {
+ mSignalStrength = signalStrength;
+ return this;
+ }
+
+ /** Set the range. */
+ @NonNull public Builder setRange(@Range final int range) {
+ mRange = range;
+ return this;
+ }
+
+ /** Set whether this network is exiting. */
+ @NonNull public Builder setExiting(final boolean exiting) {
+ mExiting = exiting;
+ return this;
+ }
+
+ /** Add a parcelable extension. */
+ @NonNull public Builder setLegacyScore(final int legacyScore) {
+ mLegacyScore = legacyScore;
+ return this;
+ }
+
+ /** Build the NetworkScore object represented by this builder. */
+ @NonNull public NetworkScore build() {
+ return new NetworkScore(mPolicy, mLinkLayerMetrics, mEndToMetrics,
+ mSignalStrength, mRange, mExiting, mLegacyScore);
+ }
}
@Override
@@ -88,9 +429,17 @@
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
- synchronized (this) {
- dest.writeBundle(mExtensions);
- }
+ dest.writeInt(mPolicy);
+ dest.writeInt(mLinkLayerMetrics.latencyMs);
+ dest.writeInt(mLinkLayerMetrics.downlinkBandwidthKBps);
+ dest.writeInt(mLinkLayerMetrics.uplinkBandwidthKBps);
+ dest.writeInt(mEndToEndMetrics.latencyMs);
+ dest.writeInt(mEndToEndMetrics.downlinkBandwidthKBps);
+ dest.writeInt(mEndToEndMetrics.uplinkBandwidthKBps);
+ dest.writeInt(mSignalStrength);
+ dest.writeInt(mRange);
+ dest.writeBoolean(mExiting);
+ dest.writeInt(mLegacyScore);
}
public static final @NonNull Creator<NetworkScore> CREATOR = new Creator<NetworkScore>() {
@@ -106,57 +455,52 @@
};
private NetworkScore(@NonNull Parcel in) {
- mExtensions = in.readBundle();
+ mPolicy = in.readInt();
+ mLinkLayerMetrics = new Metrics(in.readInt(), in.readInt(), in.readInt());
+ mEndToEndMetrics = new Metrics(in.readInt(), in.readInt(), in.readInt());
+ mSignalStrength = in.readInt();
+ mRange = in.readInt();
+ mExiting = in.readBoolean();
+ mLegacyScore = in.readInt();
}
- // TODO: Modify this method once new fields are added into this class.
@Override
public boolean equals(@Nullable Object obj) {
if (!(obj instanceof NetworkScore)) {
return false;
}
final NetworkScore other = (NetworkScore) obj;
- return bundlesEqual(mExtensions, other.mExtensions);
+ return mPolicy == other.mPolicy
+ && mLinkLayerMetrics.latencyMs == other.mLinkLayerMetrics.latencyMs
+ && mLinkLayerMetrics.uplinkBandwidthKBps
+ == other.mLinkLayerMetrics.uplinkBandwidthKBps
+ && mEndToEndMetrics.latencyMs == other.mEndToEndMetrics.latencyMs
+ && mEndToEndMetrics.uplinkBandwidthKBps
+ == other.mEndToEndMetrics.uplinkBandwidthKBps
+ && mSignalStrength == other.mSignalStrength
+ && mRange == other.mRange
+ && mExiting == other.mExiting
+ && mLegacyScore == other.mLegacyScore;
}
@Override
public int hashCode() {
- int result = 29;
- for (String key : mExtensions.keySet()) {
- final Object value = mExtensions.get(key);
- // The key may be null, so call Objects.hash() is safer.
- result += 31 * value.hashCode() + 37 * Objects.hash(key);
- }
- return result;
- }
-
- // mExtensions won't be null since the constructor will create it.
- private boolean bundlesEqual(@NonNull Bundle bundle1, @NonNull Bundle bundle2) {
- if (bundle1 == bundle2) {
- return true;
- }
-
- // This is unlikely but it's fine to add this clause here.
- if (null == bundle1 || null == bundle2) {
- return false;
- }
-
- if (bundle1.size() != bundle2.size()) {
- return false;
- }
-
- for (String key : bundle1.keySet()) {
- final Object value1 = bundle1.get(key);
- final Object value2 = bundle2.get(key);
- if (!Objects.equals(value1, value2)) {
- return false;
- }
- }
- return true;
+ return Objects.hash(mPolicy,
+ mLinkLayerMetrics.latencyMs, mLinkLayerMetrics.uplinkBandwidthKBps,
+ mEndToEndMetrics.latencyMs, mEndToEndMetrics.uplinkBandwidthKBps,
+ mSignalStrength, mRange, mExiting, mLegacyScore);
}
/** Convert to a string */
public String toString() {
- return "NetworkScore[" + mExtensions.toString() + "]";
+ return "NetworkScore ["
+ + "Policy = " + mPolicy
+ + " LinkLayerMetrics = " + mLinkLayerMetrics
+ + " EndToEndMetrics = " + mEndToEndMetrics
+ + " SignalStrength = " + mSignalStrength
+ + " Range = " + mRange
+ + " Exiting = " + mExiting
+ + " LegacyScore = " + mLegacyScore
+ + "]";
}
}
diff --git a/core/java/android/os/RecoverySystem.java b/core/java/android/os/RecoverySystem.java
index cdcb3ff..be22458 100644
--- a/core/java/android/os/RecoverySystem.java
+++ b/core/java/android/os/RecoverySystem.java
@@ -41,7 +41,6 @@
import android.text.format.DateFormat;
import android.util.Log;
import android.view.Display;
-import android.view.WindowManager;
import libcore.io.Streams;
@@ -615,8 +614,7 @@
// On TV, reboot quiescently if the screen is off
if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
- WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- if (wm.getDefaultDisplay().getState() != Display.STATE_ON) {
+ if (context.getDisplay().getState() != Display.STATE_ON) {
reason += ",quiescent";
}
}
diff --git a/core/java/android/os/VibrationAttributes.java b/core/java/android/os/VibrationAttributes.java
index 3e16640..27782fa 100644
--- a/core/java/android/os/VibrationAttributes.java
+++ b/core/java/android/os/VibrationAttributes.java
@@ -391,11 +391,23 @@
* Replaces flags
* @param flags any combination of flags.
* @return the same Builder instance.
+ * @hide
*/
public @NonNull Builder replaceFlags(int flags) {
mFlags = flags;
return this;
}
+
+ /**
+ * Set flags
+ * @param flags combination of flags to be set.
+ * @param mask Bit range that should be changed.
+ * @return the same Builder instance.
+ */
+ public @NonNull Builder setFlags(int flags, int mask) {
+ mFlags = (mFlags & ~mask) | (flags & mask);
+ return this;
+ }
}
}
diff --git a/core/java/android/os/WorkSource.java b/core/java/android/os/WorkSource.java
index 7161b07..6adba63 100644
--- a/core/java/android/os/WorkSource.java
+++ b/core/java/android/os/WorkSource.java
@@ -149,7 +149,7 @@
}
/**
- * Returns the size of this work source.
+ * Returns the number of uids in this work source.
* @hide
*/
@TestApi
diff --git a/core/java/android/os/incremental/IncrementalFileStorages.java b/core/java/android/os/incremental/IncrementalFileStorages.java
index a0bfc1b..4a66879 100644
--- a/core/java/android/os/incremental/IncrementalFileStorages.java
+++ b/core/java/android/os/incremental/IncrementalFileStorages.java
@@ -31,17 +31,10 @@
* @throws IllegalStateException the session is not an Incremental installation session.
*/
-import static dalvik.system.VMRuntime.getInstructionSet;
-
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.DataLoaderParams;
import android.content.pm.InstallationFile;
-import android.os.IVold;
-import android.os.Process;
-import android.os.RemoteException;
-import android.os.ServiceManager;
-import android.util.ArraySet;
import android.util.Slog;
import java.io.File;
@@ -58,26 +51,14 @@
public final class IncrementalFileStorages {
private static final String TAG = "IncrementalFileStorages";
private @Nullable IncrementalStorage mDefaultStorage;
- private @Nullable IncrementalStorage mApkStorage;
- private @Nullable IncrementalStorage mObbStorage;
private @Nullable String mDefaultDir;
- private @Nullable String mObbDir;
private @NonNull IncrementalManager mIncrementalManager;
- private @Nullable ArraySet<String> mLibDirs;
- private @NonNull String mPackageName;
private @NonNull File mStageDir;
/**
- * Set up files and directories used in an installation session.
- * Currently only used by Incremental Installation.
- * For Incremental installation, the expected outcome of this function is:
- * 0) All the files are in defaultStorage
- * 1) All APK files are in the same directory, bound to mApkStorage, and bound to the
- * InstallerSession's stage dir. The files are linked from mApkStorage to defaultStorage.
- * 2) All lib files are in the sub directories as their names suggest, and in the same parent
- * directory as the APK files. The files are linked from mApkStorage to defaultStorage.
- * 3) OBB files are in another directory that is different from APK files and lib files, bound
- * to mObbStorage. The files are linked from mObbStorage to defaultStorage.
+ * Set up files and directories used in an installation session. Only used by Incremental.
+ * All the files will be created in defaultStorage.
+ * TODO(b/133435829): code clean up
*
* @throws IllegalStateException the session is not an Incremental installation session.
*/
@@ -85,7 +66,6 @@
@NonNull File stageDir,
@NonNull IncrementalManager incrementalManager,
@NonNull DataLoaderParams dataLoaderParams) {
- mPackageName = packageName;
mStageDir = stageDir;
mIncrementalManager = incrementalManager;
if (dataLoaderParams.getComponentName().getPackageName().equals("local")) {
@@ -114,83 +94,23 @@
}
if (file.getFileType() == InstallationFile.FILE_TYPE_APK) {
addApkFile(file);
- } else if (file.getFileType() == InstallationFile.FILE_TYPE_OBB) {
- addObbFile(file);
- } else if (file.getFileType() == InstallationFile.FILE_TYPE_LIB) {
- addLibFile(file);
} else {
throw new IOException("Unknown file type: " + file.getFileType());
}
}
private void addApkFile(@NonNull InstallationFile apk) throws IOException {
- // Create a storage for APK files and lib files
final String stageDirPath = mStageDir.getAbsolutePath();
- if (mApkStorage == null) {
- mApkStorage = mIncrementalManager.createStorage(stageDirPath, mDefaultStorage,
- IncrementalManager.CREATE_MODE_CREATE
- | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
- mApkStorage.bind(stageDirPath);
- }
-
- if (!new File(mDefaultDir, apk.getName()).exists()) {
- mDefaultStorage.makeFile(apk.getName(), apk.getSize(), null,
+ mDefaultStorage.bind(stageDirPath);
+ String apkName = apk.getName();
+ File targetFile = Paths.get(stageDirPath, apkName).toFile();
+ if (!targetFile.exists()) {
+ mDefaultStorage.makeFile(apkName, apk.getSize(), null,
apk.getMetadata(), 0, null, null, null);
}
- // Assuming APK files are already named properly, e.g., "base.apk"
- mDefaultStorage.makeLink(apk.getName(), mApkStorage, apk.getName());
- }
-
- private void addLibFile(@NonNull InstallationFile lib) throws IOException {
- // TODO(b/136132412): remove this after we have incfs support for lib file mapping
- if (mApkStorage == null) {
- throw new IOException("Cannot add lib file without adding an apk file first");
+ if (targetFile.exists()) {
+ Slog.i(TAG, "!!! created: " + targetFile.getAbsolutePath());
}
- if (mLibDirs == null) {
- mLibDirs = new ArraySet<>();
- }
- String current = "";
- final Path libDirPath = Paths.get(lib.getName()).getParent();
- final int numDirComponents = libDirPath.getNameCount();
- for (int i = 0; i < numDirComponents; i++) {
- String dirName = libDirPath.getName(i).toString();
- try {
- dirName = getInstructionSet(dirName);
- } catch (IllegalArgumentException ignored) {
- }
- current += dirName;
- if (!mLibDirs.contains(current)) {
- mDefaultStorage.makeDirectory(current);
- mApkStorage.makeDirectory(current);
- mLibDirs.add(current);
- }
- current += '/';
- }
- String libFilePath = current + Paths.get(lib.getName()).getFileName();
- mDefaultStorage.makeFile(libFilePath, lib.getSize(), null, lib.getMetadata(), 0, null, null,
- null);
- mDefaultStorage.makeLink(libFilePath, mApkStorage, libFilePath);
- }
-
- private void addObbFile(@NonNull InstallationFile obb) throws IOException {
- if (mObbStorage == null) {
- // Create a storage for OBB files
- mObbDir = getTempDir();
- if (mObbDir == null) {
- throw new IOException("Failed to create obb storage directory.");
- }
- mObbStorage = mIncrementalManager.createStorage(
- mObbDir, mDefaultStorage,
- IncrementalManager.CREATE_MODE_CREATE
- | IncrementalManager.CREATE_MODE_TEMPORARY_BIND);
- }
- mDefaultStorage.makeFile(obb.getName(), obb.getSize(), null, obb.getMetadata(), 0, null,
- null, null);
- mDefaultStorage.makeLink(obb.getName(), mObbStorage, obb.getName());
- }
-
- private boolean hasObb() {
- return (mObbStorage != null && mObbDir != null);
}
/**
@@ -208,35 +128,6 @@
* Sets up obb storage directory and create bindings.
*/
public void finishSetUp() {
- if (!hasObb()) {
- return;
- }
- final String obbDir = "/storage/emulated/0/Android/obb";
- final String packageObbDir = String.format("%s/%s", obbDir, mPackageName);
- final String packageObbDirRoot =
- String.format("/mnt/runtime/%s/emulated/0/Android/obb/", mPackageName);
- final String[] obbDirs = {
- packageObbDirRoot + "read",
- packageObbDirRoot + "write",
- packageObbDirRoot + "full",
- packageObbDirRoot + "default",
- String.format("/data/media/0/Android/obb/%s", mPackageName),
- packageObbDir,
- };
- try {
- Slog.i(TAG, "Creating obb directory '" + packageObbDir + "'");
- final IVold vold = IVold.Stub.asInterface(ServiceManager.getServiceOrThrow("vold"));
- vold.setupAppDir(packageObbDir, obbDir, Process.ROOT_UID);
- for (String d : obbDirs) {
- mObbStorage.bindPermanent(d);
- }
- } catch (ServiceManager.ServiceNotFoundException ex) {
- Slog.e(TAG, "vold service is not found.");
- cleanUp();
- } catch (IOException | RemoteException ex) {
- Slog.e(TAG, "Failed to create obb dir at: " + packageObbDir, ex);
- cleanUp();
- }
}
/**
@@ -247,26 +138,12 @@
if (mDefaultStorage != null && mDefaultDir != null) {
try {
mDefaultStorage.unBind(mDefaultDir);
+ mDefaultStorage.unBind(mStageDir.getAbsolutePath());
} catch (IOException ignored) {
}
mDefaultDir = null;
mDefaultStorage = null;
}
- if (mApkStorage != null && mStageDir != null) {
- try {
- mApkStorage.unBind(mStageDir.getAbsolutePath());
- } catch (IOException ignored) {
- }
- mApkStorage = null;
- }
- if (mObbStorage != null && mObbDir != null) {
- try {
- mObbStorage.unBind(mObbDir);
- } catch (IOException ignored) {
- }
- mObbDir = null;
- mObbStorage = null;
- }
}
private String getTempDir() {
diff --git a/core/java/android/os/incremental/IncrementalStorage.java b/core/java/android/os/incremental/IncrementalStorage.java
index 91dda08..e5d1b43 100644
--- a/core/java/android/os/incremental/IncrementalStorage.java
+++ b/core/java/android/os/incremental/IncrementalStorage.java
@@ -174,9 +174,12 @@
@Nullable byte[] metadata, int hashAlgorithm, @Nullable byte[] rootHash,
@Nullable byte[] additionalData, @Nullable byte[] signature) throws IOException {
try {
+ if (id == null && metadata == null) {
+ throw new IOException("File ID and metadata cannot both be null");
+ }
final IncrementalNewFileParams params = new IncrementalNewFileParams();
params.size = size;
- params.metadata = metadata;
+ params.metadata = (metadata == null ? new byte[0] : metadata);
params.fileId = idToBytes(id);
if (hashAlgorithm != 0 || signature != null) {
params.signature = new IncrementalSignature();
@@ -354,9 +357,10 @@
* @param id The id to convert
* @return Byte array that contains the same ID.
*/
- public static byte[] idToBytes(UUID id) {
+ @NonNull
+ public static byte[] idToBytes(@Nullable UUID id) {
if (id == null) {
- return null;
+ return new byte[0];
}
final ByteBuffer buf = ByteBuffer.wrap(new byte[UUID_BYTE_SIZE]);
buf.putLong(id.getMostSignificantBits());
@@ -370,7 +374,8 @@
* @param bytes The id in byte array format, 16 bytes long
* @return UUID constructed from the byte array.
*/
- public static UUID bytesToId(byte[] bytes) {
+ @NonNull
+ public static UUID bytesToId(byte[] bytes) throws IllegalArgumentException {
if (bytes.length != UUID_BYTE_SIZE) {
throw new IllegalArgumentException("Expected array of size " + UUID_BYTE_SIZE
+ ", got " + bytes.length);
diff --git a/core/java/android/os/storage/StorageManager.java b/core/java/android/os/storage/StorageManager.java
index 3ea64f1..bb1dafc 100644
--- a/core/java/android/os/storage/StorageManager.java
+++ b/core/java/android/os/storage/StorageManager.java
@@ -2309,6 +2309,121 @@
private static final String XATTR_CACHE_GROUP = "user.cache_group";
private static final String XATTR_CACHE_TOMBSTONE = "user.cache_tombstone";
+
+ // Matches AID_MEDIA_RW in android_filesystem_config.h
+ private static final int QUOTA_PROJECT_ID_MEDIA_NONE = 1023;
+
+ // Matches AID_MEDIA_IMAGE in android_filesystem_config.h
+ private static final int QUOTA_PROJECT_ID_MEDIA_IMAGE = 1057;
+
+ // Matches AID_MEDIA_AUDIO in android_filesystem_config.h
+ private static final int QUOTA_PROJECT_ID_MEDIA_AUDIO = 1055;
+
+ // Matches AID_MEDIA_VIDEO in android_filesystem_config.h
+ private static final int QUOTA_PROJECT_ID_MEDIA_VIDEO = 1056;
+
+ /**
+ * Constant for use with
+ * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
+ * is not a media file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int QUOTA_TYPE_MEDIA_NONE = 0;
+
+ /**
+ * Constant for use with
+ * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
+ * is an image file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int QUOTA_TYPE_MEDIA_IMAGE = 1;
+
+ /**
+ * Constant for use with
+ * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
+ * is an audio file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int QUOTA_TYPE_MEDIA_AUDIO = 2;
+
+ /**
+ * Constant for use with
+ * {@link #updateExternalStorageFileQuotaType(String, int)} (String, int)}, to indicate the file
+ * is a video file.
+ *
+ * @hide
+ */
+ @SystemApi
+ public static final int QUOTA_TYPE_MEDIA_VIDEO = 3;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = { "QUOTA_TYPE_" }, value = {
+ QUOTA_TYPE_MEDIA_NONE,
+ QUOTA_TYPE_MEDIA_AUDIO,
+ QUOTA_TYPE_MEDIA_VIDEO,
+ QUOTA_TYPE_MEDIA_IMAGE,
+ })
+ public @interface QuotaType {}
+
+ private static native boolean setQuotaProjectId(String path, long projectId);
+
+ /**
+ * Let StorageManager know that the quota type for a file on external storage should
+ * be updated. Android tracks quotas for various media types. Consequently, this should be
+ * called on first creation of a new file on external storage, and whenever the
+ * media type of the file is updated later.
+ *
+ * This API doesn't require any special permissions, though typical implementations
+ * will require being called from an SELinux domain that allows setting file attributes
+ * related to quota (eg the GID or project ID).
+ *
+ * The default platform user of this API is the MediaProvider process, which is
+ * responsible for managing all of external storage.
+ *
+ * @param path the path to the file for which we should update the quota type
+ * @param quotaType the quota type of the file; this is based on the
+ * {@code QuotaType} constants, eg
+ * {@code StorageManager.QUOTA_TYPE_MEDIA_AUDIO}
+ *
+ * @throws IllegalArgumentException if {@code quotaType} does not correspond to a valid
+ * quota type.
+ * @throws IOException if the quota type could not be updated.
+ *
+ * @hide
+ */
+ @SystemApi
+ public void updateExternalStorageFileQuotaType(@NonNull File path,
+ @QuotaType int quotaType) throws IOException {
+ long projectId;
+ final String filePath = path.getCanonicalPath();
+ switch (quotaType) {
+ case QUOTA_TYPE_MEDIA_NONE:
+ projectId = QUOTA_PROJECT_ID_MEDIA_NONE;
+ break;
+ case QUOTA_TYPE_MEDIA_AUDIO:
+ projectId = QUOTA_PROJECT_ID_MEDIA_AUDIO;
+ break;
+ case QUOTA_TYPE_MEDIA_VIDEO:
+ projectId = QUOTA_PROJECT_ID_MEDIA_VIDEO;
+ break;
+ case QUOTA_TYPE_MEDIA_IMAGE:
+ projectId = QUOTA_PROJECT_ID_MEDIA_IMAGE;
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid quota type: " + quotaType);
+ }
+ if (!setQuotaProjectId(filePath, projectId)) {
+ throw new IOException("Failed to update quota type for " + filePath);
+ }
+ }
+
/** {@hide} */
private static void setCacheBehavior(File path, String name, boolean enabled)
throws IOException {
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index bb1c8ed..47f2461 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -16,8 +16,6 @@
package android.provider;
-import static android.annotation.SystemApi.Client.MODULE_APPS;
-
import static com.android.internal.util.Preconditions.checkCollectionElementsNotNull;
import static com.android.internal.util.Preconditions.checkCollectionNotEmpty;
@@ -955,7 +953,7 @@
*
* @hide
*/
- @SystemApi(client = MODULE_APPS)
+ @SystemApi
@NonNull
public static Uri buildDocumentUriAsUser(
@NonNull String authority, @NonNull String documentId, @NonNull UserHandle user) {
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 605c585..30e4eee08 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -2417,6 +2417,10 @@
public static class NameValueTable implements BaseColumns {
public static final String NAME = "name";
public static final String VALUE = "value";
+ // A flag indicating whether the current value of a setting should be preserved during
+ // restore.
+ /** @hide */
+ public static final String IS_PRESERVED_IN_RESTORE = "is_preserved_in_restore";
protected static boolean putString(ContentResolver resolver, Uri uri,
String name, String value) {
@@ -14051,7 +14055,7 @@
* means Common Criteria mode is enabled.
* @hide
*/
- @SystemApi(client = SystemApi.Client.MODULE_APPS)
+ @SystemApi
public static final String COMMON_CRITERIA_MODE = "common_criteria_mode";
}
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 6334d9d..368c94c 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -31,6 +31,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.os.Build;
+import android.os.Bundle;
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
@@ -39,6 +40,7 @@
import android.os.RemoteException;
import android.os.SystemClock;
import android.service.autofill.Dataset;
+import android.service.autofill.FillEventHistory;
import android.service.autofill.augmented.PresentationParams.SystemPopupPresentationParams;
import android.util.Log;
import android.util.Pair;
@@ -319,6 +321,31 @@
pw.print(getClass().getName()); pw.println(": nothing to dump");
}
+ /**
+ * Gets the inline augmented autofill events that happened after the last
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillController, FillCallback)} call.
+ *
+ * <p>The history is not persisted over reboots, and it's cleared every time the service
+ * replies to a
+ * {@link #onFillRequest(FillRequest, CancellationSignal, FillController, FillCallback)}
+ * by calling {@link FillCallback#onSuccess(FillResponse)}. Hence, the service should call
+ * {@link #getFillEventHistory() before finishing the {@link FillCallback}.
+ *
+ * <p>Also note that the events from the dropdown suggestion UI is not stored in the history
+ * since the service owns the UI.
+ *
+ * @return The history or {@code null} if there are no events.
+ */
+ @Nullable public final FillEventHistory getFillEventHistory() {
+ final AutofillManager afm = getSystemService(AutofillManager.class);
+
+ if (afm == null) {
+ return null;
+ } else {
+ return afm.getFillEventHistory();
+ }
+ }
+
/** @hide */
static final class AutofillProxy {
@@ -487,9 +514,10 @@
}
}
- public void onInlineSuggestionsDataReady(@NonNull List<Dataset> inlineSuggestionsData) {
+ public void onInlineSuggestionsDataReady(@NonNull List<Dataset> inlineSuggestionsData,
+ @Nullable Bundle clientState) {
try {
- mCallback.onSuccess(inlineSuggestionsData.toArray(new Dataset[]{}));
+ mCallback.onSuccess(inlineSuggestionsData.toArray(new Dataset[]{}), clientState);
} catch (RemoteException e) {
Log.e(TAG, "Error calling back with the inline suggestions data: " + e);
}
@@ -511,7 +539,8 @@
}
}
try {
- mCallback.onSuccess(/* mInlineSuggestionsData= */null);
+ mCallback.onSuccess(/* inlineSuggestionsData= */null, /* clientState=*/
+ null);
} catch (RemoteException e) {
Log.e(TAG, "Error reporting success: " + e);
}
diff --git a/core/java/android/service/autofill/augmented/FillCallback.java b/core/java/android/service/autofill/augmented/FillCallback.java
index b767799..d0ffd7b 100644
--- a/core/java/android/service/autofill/augmented/FillCallback.java
+++ b/core/java/android/service/autofill/augmented/FillCallback.java
@@ -60,7 +60,7 @@
List<Dataset> inlineSuggestions = response.getInlineSuggestions();
if (inlineSuggestions != null && !inlineSuggestions.isEmpty()) {
- mProxy.onInlineSuggestionsDataReady(inlineSuggestions);
+ mProxy.onInlineSuggestionsDataReady(inlineSuggestions, response.getClientState());
return;
}
diff --git a/core/java/android/service/autofill/augmented/FillResponse.java b/core/java/android/service/autofill/augmented/FillResponse.java
index e8e6ff0..68ba63a 100644
--- a/core/java/android/service/autofill/augmented/FillResponse.java
+++ b/core/java/android/service/autofill/augmented/FillResponse.java
@@ -19,6 +19,7 @@
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
+import android.os.Bundle;
import android.service.autofill.Dataset;
import com.android.internal.util.DataClass;
@@ -50,6 +51,13 @@
@DataClass.PluralOf("inlineSuggestion")
private @Nullable List<Dataset> mInlineSuggestions;
+ /**
+ * The client state that {@link AugmentedAutofillService} implementation can put anything in to
+ * identify the request and the response when calling
+ * {@link AugmentedAutofillService#getFillEventHistory()}.
+ */
+ private @Nullable Bundle mClientState;
+
private static FillWindow defaultFillWindow() {
return null;
}
@@ -58,6 +66,10 @@
return null;
}
+ private static Bundle defaultClientState() {
+ return null;
+ }
+
/** @hide */
abstract static class BaseBuilder {
@@ -82,9 +94,11 @@
@DataClass.Generated.Member
/* package-private */ FillResponse(
@Nullable FillWindow fillWindow,
- @Nullable List<Dataset> inlineSuggestions) {
+ @Nullable List<Dataset> inlineSuggestions,
+ @Nullable Bundle clientState) {
this.mFillWindow = fillWindow;
this.mInlineSuggestions = inlineSuggestions;
+ this.mClientState = clientState;
// onConstructed(); // You can define this method to get a callback
}
@@ -111,6 +125,18 @@
}
/**
+ * The client state that {@link AugmentedAutofillService} implementation can put anything in to
+ * identify the request and the response when calling
+ * {@link AugmentedAutofillService#getFillEventHistory()}.
+ *
+ * @hide
+ */
+ @DataClass.Generated.Member
+ public @Nullable Bundle getClientState() {
+ return mClientState;
+ }
+
+ /**
* A builder for {@link FillResponse}
*/
@SuppressWarnings("WeakerAccess")
@@ -119,6 +145,7 @@
private @Nullable FillWindow mFillWindow;
private @Nullable List<Dataset> mInlineSuggestions;
+ private @Nullable Bundle mClientState;
private long mBuilderFieldsSet = 0L;
@@ -157,10 +184,23 @@
return this;
}
+ /**
+ * The client state that {@link AugmentedAutofillService} implementation can put anything in to
+ * identify the request and the response when calling
+ * {@link AugmentedAutofillService#getFillEventHistory()}.
+ */
+ @DataClass.Generated.Member
+ public @NonNull Builder setClientState(@Nullable Bundle value) {
+ checkNotUsed();
+ mBuilderFieldsSet |= 0x4;
+ mClientState = value;
+ return this;
+ }
+
/** Builds the instance. This builder should not be touched after calling this! */
public @NonNull FillResponse build() {
checkNotUsed();
- mBuilderFieldsSet |= 0x4; // Mark builder used
+ mBuilderFieldsSet |= 0x8; // Mark builder used
if ((mBuilderFieldsSet & 0x1) == 0) {
mFillWindow = defaultFillWindow();
@@ -168,14 +208,18 @@
if ((mBuilderFieldsSet & 0x2) == 0) {
mInlineSuggestions = defaultInlineSuggestions();
}
+ if ((mBuilderFieldsSet & 0x4) == 0) {
+ mClientState = defaultClientState();
+ }
FillResponse o = new FillResponse(
mFillWindow,
- mInlineSuggestions);
+ mInlineSuggestions,
+ mClientState);
return o;
}
private void checkNotUsed() {
- if ((mBuilderFieldsSet & 0x4) != 0) {
+ if ((mBuilderFieldsSet & 0x8) != 0) {
throw new IllegalStateException(
"This Builder should not be reused. Use a new Builder instance instead");
}
@@ -183,10 +227,10 @@
}
@DataClass.Generated(
- time = 1577476012370L,
+ time = 1580335256422L,
codegenVersion = "1.0.14",
sourceFile = "frameworks/base/core/java/android/service/autofill/augmented/FillResponse.java",
- inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nclass BaseBuilder extends java.lang.Object implements []")
+ inputSignatures = "private @android.annotation.Nullable android.service.autofill.augmented.FillWindow mFillWindow\nprivate @com.android.internal.util.DataClass.PluralOf(\"inlineSuggestion\") @android.annotation.Nullable java.util.List<android.service.autofill.Dataset> mInlineSuggestions\nprivate @android.annotation.Nullable android.os.Bundle mClientState\nprivate static android.service.autofill.augmented.FillWindow defaultFillWindow()\nprivate static java.util.List<android.service.autofill.Dataset> defaultInlineSuggestions()\nprivate static android.os.Bundle defaultClientState()\nclass FillResponse extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genBuilder=true, genHiddenGetters=true)\nabstract android.service.autofill.augmented.FillResponse.Builder addInlineSuggestion(android.service.autofill.Dataset)\nclass BaseBuilder extends java.lang.Object implements []")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/service/autofill/augmented/IFillCallback.aidl b/core/java/android/service/autofill/augmented/IFillCallback.aidl
index 3ccb311..31e77f35 100644
--- a/core/java/android/service/autofill/augmented/IFillCallback.aidl
+++ b/core/java/android/service/autofill/augmented/IFillCallback.aidl
@@ -16,6 +16,7 @@
package android.service.autofill.augmented;
+import android.os.Bundle;
import android.os.ICancellationSignal;
import android.service.autofill.Dataset;
@@ -27,7 +28,7 @@
*/
interface IFillCallback {
void onCancellable(in ICancellationSignal cancellation);
- void onSuccess(in @nullable Dataset[] mInlineSuggestionsData);
+ void onSuccess(in @nullable Dataset[] inlineSuggestionsData, in @nullable Bundle clientState);
boolean isCompleted();
void cancel();
}
diff --git a/core/java/android/telephony/PhoneStateListener.java b/core/java/android/telephony/PhoneStateListener.java
index 023f000..531ade0 100644
--- a/core/java/android/telephony/PhoneStateListener.java
+++ b/core/java/android/telephony/PhoneStateListener.java
@@ -168,9 +168,11 @@
public static final int LISTEN_SIGNAL_STRENGTHS = 0x00000100;
/**
- * Listen for always reported changes of the network signal strengths (cellular),
+ * Listen for changes of the network signal strengths (cellular) always reported from modem,
* even in some situations such as the screen of the device is off.
*
+ * @see #onSignalStrengthsChanged
+ *
* @hide
*/
@RequiresPermission(android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
diff --git a/core/java/android/timezone/CountryTimeZones.java b/core/java/android/timezone/CountryTimeZones.java
index e5bbdf4..5875761 100644
--- a/core/java/android/timezone/CountryTimeZones.java
+++ b/core/java/android/timezone/CountryTimeZones.java
@@ -56,7 +56,7 @@
*/
@NonNull
public String getTimeZoneId() {
- return mDelegate.timeZoneId;
+ return mDelegate.getTimeZoneId();
}
/**
@@ -187,7 +187,7 @@
* would be a good choice <em>generally</em> when there's no other information available.
*/
public boolean isDefaultTimeZoneBoosted() {
- return mDelegate.getDefaultTimeZoneBoost();
+ return mDelegate.isDefaultTimeZoneBoosted();
}
/**
@@ -220,7 +220,8 @@
mDelegate.lookupByOffsetWithBias(
totalOffsetMillis, isDst, dstOffsetMillis, whenMillis, bias);
return delegateOffsetResult == null ? null :
- new OffsetResult(delegateOffsetResult.mTimeZone, delegateOffsetResult.mOneMatch);
+ new OffsetResult(
+ delegateOffsetResult.getTimeZone(), delegateOffsetResult.isOnlyMatch());
}
/**
diff --git a/core/java/android/timezone/TzDataSetVersion.java b/core/java/android/timezone/TzDataSetVersion.java
index 605155e..efe50a0 100644
--- a/core/java/android/timezone/TzDataSetVersion.java
+++ b/core/java/android/timezone/TzDataSetVersion.java
@@ -111,23 +111,23 @@
/** Returns the major version number. See {@link TzDataSetVersion}. */
public int getFormatMajorVersion() {
- return mDelegate.formatMajorVersion;
+ return mDelegate.getFormatMajorVersion();
}
/** Returns the minor version number. See {@link TzDataSetVersion}. */
public int getFormatMinorVersion() {
- return mDelegate.formatMinorVersion;
+ return mDelegate.getFormatMinorVersion();
}
/** Returns the tzdb version string. See {@link TzDataSetVersion}. */
@NonNull
public String getRulesVersion() {
- return mDelegate.rulesVersion;
+ return mDelegate.getRulesVersion();
}
/** Returns the Android revision. See {@link TzDataSetVersion}. */
public int getRevision() {
- return mDelegate.revision;
+ return mDelegate.getRevision();
}
@Override
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 06fccaf8..5fdac81 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -47,6 +47,9 @@
/** @hide */
public static final String BACKUP_NO_KV_DATA_CHANGE_CALLS =
"backup_enable_no_data_notification_calls";
+ /** @hide */
+ public static final String SETTINGS_DO_NOT_RESTORE_PRESERVED =
+ "settings_do_not_restore_preserved";
private static final Map<String, String> DEFAULT_FLAGS;
@@ -68,6 +71,11 @@
// Disabled until backup transports support it.
DEFAULT_FLAGS.put(BACKUP_NO_KV_DATA_CHANGE_CALLS, "false");
+ // Disabled by default until b/148278926 is resolved. This flags guards a feature
+ // introduced in R and will be removed in the next release (b/148367230).
+ DEFAULT_FLAGS.put(SETTINGS_DO_NOT_RESTORE_PRESERVED, "false");
+
+ DEFAULT_FLAGS.put("settings_tether_all_in_one", "false");
}
/**
diff --git a/core/java/android/util/TimeUtils.java b/core/java/android/util/TimeUtils.java
index c325874..36f4e53 100644
--- a/core/java/android/util/TimeUtils.java
+++ b/core/java/android/util/TimeUtils.java
@@ -81,7 +81,7 @@
}
CountryTimeZones.OffsetResult offsetResult = countryTimeZones.lookupByOffsetWithBias(
offsetMillis, isDst, null /* dstOffsetMillis */, whenMillis, bias);
- return offsetResult != null ? offsetResult.mTimeZone : null;
+ return offsetResult != null ? offsetResult.getTimeZone() : null;
}
/**
@@ -109,8 +109,8 @@
List<String> timeZoneIds = new ArrayList<>();
for (TimeZoneMapping timeZoneMapping : countryTimeZones.getTimeZoneMappings()) {
- if (timeZoneMapping.showInPicker) {
- timeZoneIds.add(timeZoneMapping.timeZoneId);
+ if (timeZoneMapping.isShownInPicker()) {
+ timeZoneIds.add(timeZoneMapping.getTimeZoneId());
}
}
return Collections.unmodifiableList(timeZoneIds);
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index e92aafe..5ccdd30 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -26,8 +26,7 @@
* {@hide}
*/
oneway interface ITaskOrganizer {
- void taskAppeared(in IWindowContainer container,
- in ActivityManager.RunningTaskInfo taskInfo);
+ void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
void taskVanished(in IWindowContainer container);
/**
@@ -35,4 +34,19 @@
* ActivityTaskManagerService#applyTaskOrganizerTransaction
*/
void transactionReady(int id, in SurfaceControl.Transaction t);
+
+ /**
+ * Will fire when core attributes of a Task's info change. Relevant properties include the
+ * {@link WindowConfiguration.ActivityType} and whether it is resizable.
+ *
+ * This is used, for example, during split-screen. The flow for starting is: Something sends an
+ * Intent with windowingmode. Then WM finds a matching root task and launches the new task into
+ * it. This causes the root task's info to change because now it has a task when it didn't
+ * before. The default Divider implementation interprets this as a request to enter
+ * split-screen mode and will move all other Tasks into the secondary root task. When WM
+ * applies this change, it triggers an info change in the secondary root task because it now
+ * has children. The Divider impl looks at the info and can see that the secondary root task
+ * has adopted an ActivityType of HOME and proceeds to show the minimized dock UX.
+ */
+ void onTaskInfoChanged(in ActivityManager.RunningTaskInfo info);
}
\ No newline at end of file
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index e1f1581..f9a023f 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -120,12 +120,14 @@
*
* @param token Token to be registered.
* @param type Window type to be used with this token.
+ * @param options A bundle used to pass window-related options.
* @param displayId The ID of the display where this token should be added.
* @param packageName The name of package to request to add window token.
* @return {@link WindowManagerGlobal#ADD_OKAY} if the addition was successful, an error code
* otherwise.
*/
- int addWindowContextToken(IBinder token, int type, int displayId, String packageName);
+ int addWindowTokenWithOptions(IBinder token, int type, int displayId, in Bundle options,
+ String packageName);
void addWindowToken(IBinder token, int type, int displayId);
void removeWindowToken(IBinder token, int displayId);
void prepareAppTransition(int transit, boolean alwaysKeepCurrent);
diff --git a/core/java/android/view/ImeInsetsSourceConsumer.java b/core/java/android/view/ImeInsetsSourceConsumer.java
index 23ba097..f226369 100644
--- a/core/java/android/view/ImeInsetsSourceConsumer.java
+++ b/core/java/android/view/ImeInsetsSourceConsumer.java
@@ -17,6 +17,7 @@
package android.view;
import static android.view.InsetsState.ITYPE_IME;
+import static android.view.InsetsState.toPublicType;
import android.annotation.Nullable;
import android.inputmethodservice.InputMethodService;
@@ -44,6 +45,12 @@
*/
private boolean mShowOnNextImeRender;
+ /**
+ * Tracks whether we have an outstanding request from the IME to show, but weren't able to
+ * execute it because we didn't have control yet.
+ */
+ private boolean mImeRequestedShow;
+
public ImeInsetsSourceConsumer(
InsetsState state, Supplier<Transaction> transactionSupplier,
InsetsController controller) {
@@ -81,13 +88,14 @@
public void onWindowFocusLost() {
super.onWindowFocusLost();
getImm().unregisterImeConsumer(this);
+ mImeRequestedShow = false;
}
@Override
- public void setControl(@Nullable InsetsSourceControl control) {
- super.setControl(control);
- if (control == null) {
- hide();
+ public void show(boolean fromIme) {
+ super.show(fromIme);
+ if (fromIme) {
+ mImeRequestedShow = true;
}
}
@@ -99,7 +107,11 @@
public @ShowResult int requestShow(boolean fromIme) {
// TODO: ResultReceiver for IME.
// TODO: Set mShowOnNextImeRender to automatically show IME and guard it with a flag.
- if (fromIme) {
+
+ // If we had a request before to show from IME (tracked with mImeRequestedShow), reaching
+ // this code here means that we now got control, so we can start the animation immediately.
+ if (fromIme || mImeRequestedShow) {
+ mImeRequestedShow = false;
return ShowResult.SHOW_IMMEDIATELY;
}
@@ -115,6 +127,15 @@
getImm().notifyImeHidden();
}
+ @Override
+ public void setControl(@Nullable InsetsSourceControl control, int[] showTypes,
+ int[] hideTypes) {
+ super.setControl(control, showTypes, hideTypes);
+ if (control == null) {
+ hide();
+ }
+ }
+
private boolean isDummyOrEmptyEditor(EditorInfo info) {
// TODO(b/123044812): Handle dummy input gracefully in IME Insets API
return info == null || (info.fieldId <= 0 && info.inputType <= 0);
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 5c24047..0653b06 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -16,8 +16,6 @@
package android.view;
-import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
-import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ISIDE_BOTTOM;
import static android.view.InsetsState.ISIDE_FLOATING;
import static android.view.InsetsState.ISIDE_LEFT;
@@ -188,7 +186,7 @@
@Override
public void finish(boolean shown) {
- if (mCancelled) {
+ if (mCancelled || mFinished) {
return;
}
setInsetsAndAlpha(shown ? mShownInsets : mHiddenInsets, 1f /* alpha */, 1f /* fraction */);
@@ -210,6 +208,10 @@
mListener.onCancelled();
}
+ public boolean isCancelled() {
+ return mCancelled;
+ }
+
InsetsAnimation getAnimation() {
return mAnimation;
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 6f76497..22d6f37 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -39,6 +39,7 @@
import android.util.Pair;
import android.util.Property;
import android.util.SparseArray;
+import android.view.InputDevice.MotionRange;
import android.view.InsetsSourceConsumer.ShowResult;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
@@ -69,7 +70,7 @@
private static final int ANIMATION_DURATION_HIDE_MS = 340;
private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
- static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
+ public static final Interpolator INTERPOLATOR = new PathInterpolator(0.4f, 0f, 0.2f, 1f);
/**
* Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -77,7 +78,7 @@
* be called as if the changing insets types are shown, which will result in the views being
* laid out as if the insets are fully shown.
*/
- static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
+ public static final int LAYOUT_INSETS_DURING_ANIMATION_SHOWN = 0;
/**
* Layout mode during insets animation: The views should be laid out as if the changing inset
@@ -85,7 +86,7 @@
* be called as if the changing insets types are hidden, which will result in the views being
* laid out as if the insets are fully hidden.
*/
- static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
+ public static final int LAYOUT_INSETS_DURING_ANIMATION_HIDDEN = 1;
/**
* Determines the behavior of how the views should be laid out during an insets animation that
@@ -148,7 +149,7 @@
@Override
public void set(WindowInsetsAnimationController controller, Insets value) {
controller.setInsetsAndAlpha(
- value, 1f /* alpha */, (((DefaultAnimationControlListener)
+ value, 1f /* alpha */, (((InternalAnimationControlListener)
((InsetsAnimationControlImpl) controller).getListener())
.getRawFraction()));
}
@@ -165,7 +166,7 @@
private ObjectAnimator mAnimator;
protected boolean mShow;
- InternalAnimationControlListener(boolean show) {
+ public InternalAnimationControlListener(boolean show) {
mShow = show;
}
@@ -213,7 +214,10 @@
return (float) mAnimator.getCurrentPlayTime() / mAnimator.getDuration();
}
- protected long getDurationMs() {
+ /**
+ * To get the animation duration in MS.
+ */
+ public long getDurationMs() {
if (mAnimator != null) {
return mAnimator.getDuration();
}
@@ -273,7 +277,7 @@
private final String TAG = "InsetsControllerImpl";
private final InsetsState mState = new InsetsState();
- private final InsetsState mTmpState = new InsetsState();
+ private final InsetsState mLastDispachedState = new InsetsState();
private final Rect mFrame = new Rect();
private final BiFunction<InsetsController, Integer, InsetsSourceConsumer> mConsumerCreator;
@@ -367,15 +371,20 @@
return mState;
}
- boolean onStateChanged(InsetsState state) {
- if (mState.equals(state)) {
+ public InsetsState getLastDispatchedState() {
+ return mLastDispachedState;
+ }
+
+ @VisibleForTesting
+ public boolean onStateChanged(InsetsState state) {
+ if (mState.equals(state) && mLastDispachedState.equals(state)) {
return false;
}
mState.set(state);
- mTmpState.set(state, true /* copySources */);
+ mLastDispachedState.set(state, true /* copySources */);
applyLocalVisibilityOverride();
mViewRoot.notifyInsetsChanged();
- if (!mState.equals(mTmpState)) {
+ if (!mState.equals(mLastDispachedState)) {
sendStateToWindowManager();
}
return true;
@@ -419,6 +428,9 @@
}
}
+ int[] showTypes = new int[1];
+ int[] hideTypes = new int[1];
+
// Ensure to update all existing source consumers
for (int i = mSourceConsumers.size() - 1; i >= 0; i--) {
final InsetsSourceConsumer consumer = mSourceConsumers.valueAt(i);
@@ -426,15 +438,23 @@
// control may be null, but we still need to update the control to null if it got
// revoked.
- consumer.setControl(control);
+ consumer.setControl(control, showTypes, hideTypes);
}
// Ensure to create source consumers if not available yet.
for (int i = mTmpControlArray.size() - 1; i >= 0; i--) {
final InsetsSourceControl control = mTmpControlArray.valueAt(i);
- getSourceConsumer(control.getType()).setControl(control);
+ InsetsSourceConsumer consumer = getSourceConsumer(control.getType());
+ consumer.setControl(control, showTypes, hideTypes);
+
}
mTmpControlArray.clear();
+ if (showTypes[0] != 0) {
+ applyAnimation(showTypes[0], true /* show */, false /* fromIme */);
+ }
+ if (hideTypes[0] != 0) {
+ applyAnimation(hideTypes[0], false /* show */, false /* fromIme */);
+ }
}
@Override
@@ -465,7 +485,7 @@
@InternalInsetsType int internalType = internalTypes.valueAt(i);
@AnimationType int animationType = getAnimationType(internalType);
InsetsSourceConsumer consumer = getSourceConsumer(internalType);
- if (mState.getSource(internalType).isVisible() && animationType == ANIMATION_TYPE_NONE
+ if (consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
|| animationType == ANIMATION_TYPE_SHOW) {
// no-op: already shown or animating in (because window visibility is
// applied before starting animation).
@@ -488,7 +508,7 @@
@InternalInsetsType int internalType = internalTypes.valueAt(i);
@AnimationType int animationType = getAnimationType(internalType);
InsetsSourceConsumer consumer = getSourceConsumer(internalType);
- if (!mState.getSource(internalType).isVisible() && animationType == ANIMATION_TYPE_NONE
+ if (!consumer.isRequestedVisible() && animationType == ANIMATION_TYPE_NONE
|| animationType == ANIMATION_TYPE_HIDE) {
// no-op: already hidden or animating out.
continue;
@@ -535,7 +555,7 @@
final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
Pair<Integer, Boolean> typesReadyPair = collectSourceControls(
- fromIme, internalTypes, controls);
+ fromIme, internalTypes, controls, animationType);
int typesReady = typesReadyPair.first;
boolean imeReady = typesReadyPair.second;
if (!imeReady) {
@@ -562,17 +582,20 @@
* @return Pair of (types ready to animate, IME ready to animate).
*/
private Pair<Integer, Boolean> collectSourceControls(boolean fromIme,
- ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls) {
+ ArraySet<Integer> internalTypes, SparseArray<InsetsSourceControl> controls,
+ @AnimationType int animationType) {
int typesReady = 0;
boolean imeReady = true;
for (int i = internalTypes.size() - 1; i >= 0; i--) {
InsetsSourceConsumer consumer = getSourceConsumer(internalTypes.valueAt(i));
- boolean setVisible = !consumer.isRequestedVisible();
- if (setVisible) {
+ boolean show = animationType == ANIMATION_TYPE_SHOW
+ || animationType == ANIMATION_TYPE_USER;
+ boolean canRun = false;
+ if (show) {
// Show request
switch(consumer.requestShow(fromIme)) {
case ShowResult.SHOW_IMMEDIATELY:
- typesReady |= InsetsState.toPublicType(consumer.getType());
+ canRun = true;
break;
case ShowResult.IME_SHOW_DELAYED:
imeReady = false;
@@ -589,11 +612,22 @@
if (!fromIme) {
consumer.notifyHidden();
}
- typesReady |= InsetsState.toPublicType(consumer.getType());
+ canRun = true;
+ }
+ if (!canRun) {
+ continue;
}
final InsetsSourceControl control = consumer.getControl();
if (control != null) {
controls.put(consumer.getType(), control);
+ typesReady |= toPublicType(consumer.getType());
+ } else if (animationType == ANIMATION_TYPE_SHOW) {
+
+ // We don't have a control at the moment. However, we still want to update requested
+ // visibility state such that in case we get control, we can apply show animation.
+ consumer.show(fromIme);
+ } else if (animationType == ANIMATION_TYPE_HIDE) {
+ consumer.hide();
}
}
return new Pair<>(typesReady, imeReady);
@@ -808,7 +842,7 @@
private void showDirectly(@InsetsType int types) {
final ArraySet<Integer> internalTypes = InsetsState.toInternalType(types);
for (int i = internalTypes.size() - 1; i >= 0; i--) {
- getSourceConsumer(internalTypes.valueAt(i)).show();
+ getSourceConsumer(internalTypes.valueAt(i)).show(false /* fromIme */);
}
}
@@ -840,6 +874,9 @@
@Override
public boolean onPreDraw() {
mViewRoot.mView.getViewTreeObserver().removeOnPreDrawListener(this);
+ if (controller.isCancelled()) {
+ return true;
+ }
mViewRoot.mView.dispatchWindowInsetsAnimationStart(animation, bounds);
listener.onReady(controller, types);
return true;
diff --git a/core/java/android/view/InsetsSource.java b/core/java/android/view/InsetsSource.java
index 37034ee..d4961ea 100644
--- a/core/java/android/view/InsetsSource.java
+++ b/core/java/android/view/InsetsSource.java
@@ -53,6 +53,9 @@
mType = other.mType;
mFrame = new Rect(other.mFrame);
mVisible = other.mVisible;
+ mVisibleFrame = other.mVisibleFrame != null
+ ? new Rect(other.mVisibleFrame)
+ : null;
}
public void setFrame(Rect frame) {
@@ -165,6 +168,7 @@
public int hashCode() {
int result = mType;
result = 31 * result + mFrame.hashCode();
+ result = 31 * result + (mVisibleFrame != null ? mVisibleFrame.hashCode() : 0);
result = 31 * result + (mVisible ? 1 : 0);
return result;
}
@@ -189,6 +193,15 @@
dest.writeBoolean(mVisible);
}
+ @Override
+ public String toString() {
+ return "InsetsSource: {"
+ + "mType=" + InsetsState.typeToString(mType)
+ + ", mFrame=" + mFrame.toShortString()
+ + ", mVisible" + mVisible
+ + "}";
+ }
+
public static final @android.annotation.NonNull Creator<InsetsSource> CREATOR = new Creator<InsetsSource>() {
public InsetsSource createFromParcel(Parcel in) {
diff --git a/core/java/android/view/InsetsSourceConsumer.java b/core/java/android/view/InsetsSourceConsumer.java
index 9901d05..e6497c0 100644
--- a/core/java/android/view/InsetsSourceConsumer.java
+++ b/core/java/android/view/InsetsSourceConsumer.java
@@ -17,11 +17,14 @@
package android.view;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
+import static android.view.InsetsState.toPublicType;
import android.annotation.IntDef;
import android.annotation.Nullable;
+import android.util.MutableShort;
import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl.Transaction;
+import android.view.WindowInsets.Type.InsetsType;
import com.android.internal.annotations.VisibleForTesting;
@@ -71,18 +74,48 @@
mRequestedVisible = InsetsState.getDefaultVisibility(type);
}
- public void setControl(@Nullable InsetsSourceControl control) {
+ /**
+ * Updates the control delivered from the server.
+
+ * @param showTypes An integer array with a single entry that determines which types a show
+ * animation should be run after setting the control.
+ * @param hideTypes An integer array with a single entry that determines which types a hide
+ * animation should be run after setting the control.
+ */
+ public void setControl(@Nullable InsetsSourceControl control,
+ @InsetsType int[] showTypes, @InsetsType int[] hideTypes) {
if (mSourceControl == control) {
return;
}
mSourceControl = control;
- applyHiddenToControl();
+
+ // We are loosing control
+ if (mSourceControl == null) {
+ mController.notifyControlRevoked(this);
+
+ // Restore server visibility.
+ mState.getSource(getType()).setVisible(
+ mController.getLastDispatchedState().getSource(getType()).isVisible());
+ applyLocalVisibilityOverride();
+ return;
+ }
+
+ // We are gaining control, and need to run an animation since previous state didn't match
+ if (mRequestedVisible != mState.getSource(mType).isVisible()) {
+ if (mRequestedVisible) {
+ showTypes[0] |= toPublicType(getType());
+ } else {
+ hideTypes[0] |= toPublicType(getType());
+ }
+ return;
+ }
+
+ // We are gaining control, but don't need to run an animation. However make sure that the
+ // leash visibility is still up to date.
if (applyLocalVisibilityOverride()) {
mController.notifyVisibilityChanged();
}
- if (mSourceControl == null) {
- mController.notifyControlRevoked(this);
- }
+ applyHiddenToControl();
}
@VisibleForTesting
@@ -95,7 +128,7 @@
}
@VisibleForTesting
- public void show() {
+ public void show(boolean fromIme) {
setRequestedVisible(true);
}
@@ -172,17 +205,13 @@
* the moment.
*/
private void setRequestedVisible(boolean requestedVisible) {
- if (mRequestedVisible == requestedVisible) {
- return;
- }
mRequestedVisible = requestedVisible;
- applyLocalVisibilityOverride();
- mController.notifyVisibilityChanged();
+ if (applyLocalVisibilityOverride()) {
+ mController.notifyVisibilityChanged();
+ }
}
private void applyHiddenToControl() {
-
- // TODO: Handle case properly when animation is running already (it shouldn't!)
if (mSourceControl == null || mSourceControl.getLeash() == null) {
return;
}
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index bd19799..8648682 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -21,7 +21,6 @@
import static android.view.ViewRootImpl.NEW_INSETS_MODE_IME;
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
-import static android.view.WindowInsets.Type.IME;
import static android.view.WindowInsets.Type.MANDATORY_SYSTEM_GESTURES;
import static android.view.WindowInsets.Type.SIZE;
import static android.view.WindowInsets.Type.SYSTEM_GESTURES;
@@ -43,7 +42,6 @@
import android.util.SparseIntArray;
import android.view.WindowInsets.Type;
import android.view.WindowInsets.Type.InsetsType;
-import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.LayoutParams.SoftInputModeFlags;
import java.io.PrintWriter;
@@ -366,7 +364,12 @@
return result;
}
- static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
+ /**
+ * Converting a internal type to the public type.
+ * @param type internal insets type, {@code InternalInsetsType}.
+ * @return public insets type, {@code Type.InsetsType}.
+ */
+ public static @Type.InsetsType int toPublicType(@InternalInsetsType int type) {
switch (type) {
case ITYPE_STATUS_BAR:
return Type.STATUS_BARS;
@@ -510,5 +513,13 @@
mSources.put(source.getType(), source);
}
}
+
+ @Override
+ public String toString() {
+ return "InsetsState: {"
+ + "mDisplayFrame=" + mDisplayFrame
+ + ", mSources=" + mSources
+ + "}";
+ }
}
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index d70bf22f..ee7f6fb 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -3654,8 +3654,7 @@
*
* @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
* {@link Type#navigationBars()}. For non-floating windows that fill the screen, call
- * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
- * doesn't fit the navigation bar on the window content level.
+ * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}.
*/
public static final int SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION = 0x00000200;
@@ -3683,8 +3682,7 @@
*
* @deprecated For floating windows, use {@link LayoutParams#setFitInsetsTypes(int)} with
* {@link Type#statusBars()} ()}. For non-floating windows that fill the screen, call
- * {@link Window#setOnContentApplyWindowInsetsListener} with {@code null} or a listener that
- * doesn't fit the status bar on the window content level.
+ * {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false}.
*/
@Deprecated
public static final int SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN = 0x00000400;
@@ -4673,7 +4671,7 @@
private ArrayList<OnUnhandledKeyEventListener> mUnhandledKeyListeners;
- private WindowInsetsAnimationCallback mWindowInsetsAnimationCallback;
+ WindowInsetsAnimationCallback mWindowInsetsAnimationCallback;
/**
* This lives here since it's only valid for interactive views.
@@ -11537,7 +11535,7 @@
}
/**
- * @see #PFLAG4_OPTIONAL_FITS_SYSTEM_WINDOWS
+ * @see #PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS
* @hide
*/
public void makeFrameworkOptionalFitsSystemWindows() {
@@ -11545,6 +11543,13 @@
}
/**
+ * @hide
+ */
+ public boolean isFrameworkOptionalFitsSystemWindows() {
+ return (mPrivateFlags4 & PFLAG4_FRAMEWORK_OPTIONAL_FITS_SYSTEM_WINDOWS) != 0;
+ }
+
+ /**
* Returns the visibility status for this view.
*
* @return One of {@link #VISIBLE}, {@link #INVISIBLE}, or {@link #GONE}.
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index a66b508..47a79bd 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -28,6 +28,7 @@
import android.os.RemoteException;
import android.provider.Settings;
import android.util.DisplayMetrics;
+import android.util.Size;
import android.util.SparseArray;
import android.util.TypedValue;
@@ -408,11 +409,9 @@
mAmbiguousGestureMultiplier = multiplierValue.getFloat();
// Size of the screen in bytes, in ARGB_8888 format
- final WindowManager win = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- final Display display = win.getDefaultDisplay();
- final Point size = new Point();
- display.getRealSize(size);
- mMaximumDrawingCacheSize = 4 * size.x * size.y;
+ final WindowManager windowManager = context.getSystemService(WindowManager.class);
+ final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
+ mMaximumDrawingCacheSize = 4 * maxWindowSize.getWidth() * maxWindowSize.getHeight();
mOverscrollDistance = (int) (sizeAndDensity * OVERSCROLL_DISTANCE + 0.5f);
mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index 4f03ca1..d416d42 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -7239,6 +7239,18 @@
public void dispatchWindowInsetsAnimationPrepare(
@NonNull InsetsAnimation animation) {
super.dispatchWindowInsetsAnimationPrepare(animation);
+
+ // If we are root-level content view that fits insets, set dispatch mode to stop to imitate
+ // consume behavior.
+ boolean isOptionalFitSystemWindows = (mViewFlags & OPTIONAL_FITS_SYSTEM_WINDOWS) != 0
+ || isFrameworkOptionalFitsSystemWindows();
+ if (isOptionalFitSystemWindows && mAttachInfo != null
+ && getListenerInfo().mWindowInsetsAnimationCallback == null
+ && mAttachInfo.mContentOnApplyWindowInsetsListener != null) {
+ mInsetsAnimationDispatchMode = DISPATCH_MODE_STOP;
+ return;
+ }
+
if (mInsetsAnimationDispatchMode == DISPATCH_MODE_STOP) {
return;
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 51ea30b..549035f 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3348,7 +3348,6 @@
private void performLayout(WindowManager.LayoutParams lp, int desiredWindowWidth,
int desiredWindowHeight) {
- mLayoutRequested = false;
mScrollMayChange = true;
mInLayout = true;
@@ -4887,8 +4886,14 @@
break;
case MSG_INSETS_CONTROL_CHANGED: {
SomeArgs args = (SomeArgs) msg.obj;
- mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
+
+ // Deliver state change before control change, such that:
+ // a) When gaining control, controller can compare with server state to evaluate
+ // whether it needs to run animation.
+ // b) When loosing control, controller can restore server state by taking last
+ // dispatched state as truth.
mInsetsController.onStateChanged((InsetsState) args.arg1);
+ mInsetsController.onControlsChanged((InsetsSourceControl[]) args.arg2);
break;
}
case MSG_SHOW_INSETS: {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0ef4e33..4b284db 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -697,12 +697,10 @@
}
/**
- * Listener for applying window insets on the content of a window in a custom way.
+ * Listener for applying window insets on the content of a window. Used only by the framework to
+ * fit content according to legacy SystemUI flags.
*
- * <p>Apps may choose to implement this interface if they want to apply custom policy
- * to the way that window insets are treated for fitting root-level content views.
- *
- * @see Window#setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener)
+ * @hide
*/
public interface OnContentApplyWindowInsetsListener {
@@ -716,13 +714,15 @@
*
* @param insets The root level insets that are about to be dispatched
* @return A pair, with the first element containing the insets to apply as margin to the
- * root-level content views, and the second element determining what should be
- * dispatched to the content view.
+ * root-level content views, and the second element determining what should be
+ * dispatched to the content view.
*/
- @NonNull Pair<Insets, WindowInsets> onContentApplyWindowInsets(
+ @NonNull
+ Pair<Insets, WindowInsets> onContentApplyWindowInsets(
@NonNull WindowInsets insets);
}
+
public Window(Context context) {
mContext = context;
mFeatures = mLocalFeatures = getDefaultFeatures(context);
@@ -1311,33 +1311,21 @@
}
/**
- * Sets the listener to be invoked when fitting root-level content views.
+ * Sets whether the decor view should fit root-level content views for {@link WindowInsets}.
* <p>
- * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
- * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
- * fits content according to these flags.
+ * If set to {@code true}, the framework will inspect the now deprecated
+ * {@link View#SYSTEM_UI_LAYOUT_FLAGS} as well the
+ * {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag and fits content according
+ * to these flags.
* </p>
- * @param contentOnApplyWindowInsetsListener The listener to use for fitting root-level content
- * views, or {@code null} to disable any kind of
- * content fitting on the window level and letting the
- * {@link WindowInsets} pass through to the content
- * view.
- * @see OnContentApplyWindowInsetsListener
- */
- public void setOnContentApplyWindowInsetsListener(
- @Nullable OnContentApplyWindowInsetsListener contentOnApplyWindowInsetsListener) {
- }
-
- /**
- * Resets the listener set via {@link #setOnContentApplyWindowInsetsListener} to the default
- * state.
* <p>
- * By default, a listener that inspects the now deprecated {@link View#SYSTEM_UI_LAYOUT_FLAGS}
- * as well the {@link WindowManager.LayoutParams#SOFT_INPUT_ADJUST_RESIZE} flag is installed and
- * fits content according to these flags.
+ * If set to {@code false}, the framework will not fit the content view to the insets and will
+ * just pass through the {@link WindowInsets} to the content view.
* </p>
+ * @param decorFitsSystemWindows Whether the decor view should fit root-level content views for
+ * insets.
*/
- public void resetOnContentApplyWindowInsetsListener() {
+ public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
}
/**
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index c55caa3..33f21f2 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -86,6 +86,17 @@
return this;
}
+ /**
+ * Set the smallestScreenWidth of a container.
+ */
+ public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
+ int widthDp) {
+ Change cfg = getOrCreateChange(container.asBinder());
+ cfg.mConfiguration.smallestScreenWidthDp = widthDp;
+ cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ return this;
+ }
+
public Map<IBinder, Change> getChanges() {
return mChanges;
}
diff --git a/core/java/android/view/WindowInsetsAnimationCallback.java b/core/java/android/view/WindowInsetsAnimationCallback.java
index 1e04d02..4c8463b3 100644
--- a/core/java/android/view/WindowInsetsAnimationCallback.java
+++ b/core/java/android/view/WindowInsetsAnimationCallback.java
@@ -86,9 +86,9 @@
* following:
* <p>
* <ul>
- * <li>Application calls {@link WindowInsetsController#hideInputMethod()},
- * {@link WindowInsetsController#showInputMethod()},
- * {@link WindowInsetsController#controlInputMethodAnimation}</li>
+ * <li>Application calls {@link WindowInsetsController#hide(int)},
+ * {@link WindowInsetsController#show(int)},
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}</li>
* <li>onPrepare is called on the view hierarchy listeners</li>
* <li>{@link View#onApplyWindowInsets} will be called with the end state of the
* animation</li>
@@ -106,12 +106,12 @@
* related methods.
* <p>
* Note: If the animation is application controlled by using
- * {@link WindowInsetsController#controlInputMethodAnimation}, the end state of the animation
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}, the end state of the animation
* is undefined as the application may decide on the end state only by passing in the
* {@code shown} parameter when calling {@link WindowInsetsAnimationController#finish}. In this
* situation, the system will dispatch the insets in the opposite visibility state before the
* animation starts. Example: When controlling the input method with
- * {@link WindowInsetsController#controlInputMethodAnimation} and the input method is currently
+ * {@link WindowInsetsController#controlWindowInsetsAnimation} and the input method is currently
* showing, {@link View#onApplyWindowInsets} will receive a {@link WindowInsets} instance for
* which {@link WindowInsets#isVisible} will return {@code false} for {@link Type#ime}.
*
@@ -246,7 +246,7 @@
* be the same as the application passed into
* {@link WindowInsetsAnimationController#setInsetsAndAlpha(Insets, float, float)},
* interpolated with the interpolator passed into
- * {@link WindowInsetsController#controlInputMethodAnimation}.
+ * {@link WindowInsetsController#controlWindowInsetsAnimation}.
* </p>
* <p>
* Note: For system-initiated animations, this will always return a valid value between 0
diff --git a/core/java/android/view/WindowInsetsAnimationControlListener.java b/core/java/android/view/WindowInsetsAnimationControlListener.java
index f91254d..701bd31 100644
--- a/core/java/android/view/WindowInsetsAnimationControlListener.java
+++ b/core/java/android/view/WindowInsetsAnimationControlListener.java
@@ -39,7 +39,7 @@
* @param controller The controller to control the inset animation.
* @param types The {@link InsetsType}s it was able to gain control over. Note that this may be
* different than the types passed into
- * {@link WindowInsetsController#controlInputMethodAnimation} in case the window
+ * {@link WindowInsetsController#controlWindowInsetsAnimation} in case the window
* wasn't able to gain the controls because it wasn't the IME target or not
* currently the window that's controlling the system bars.
*/
diff --git a/core/java/android/view/WindowInsetsAnimationController.java b/core/java/android/view/WindowInsetsAnimationController.java
index 2bf0d27..4a864be 100644
--- a/core/java/android/view/WindowInsetsAnimationController.java
+++ b/core/java/android/view/WindowInsetsAnimationController.java
@@ -23,6 +23,7 @@
import android.graphics.Insets;
import android.view.WindowInsets.Type.InsetsType;
import android.view.WindowInsetsAnimationCallback.AnimationBounds;
+import android.view.animation.Interpolator;
/**
* Controller for app-driven animation of system windows.
@@ -32,7 +33,7 @@
* synchronized, such that changes the system windows and the app's current frame
* are rendered at the same time.
* <p>
- * Control is obtained through {@link WindowInsetsController#controlInputMethodAnimation}.
+ * Control is obtained through {@link WindowInsetsController#controlWindowInsetsAnimation}.
*/
@SuppressLint("NotClosable")
public interface WindowInsetsAnimationController {
diff --git a/core/java/android/view/WindowInsetsController.java b/core/java/android/view/WindowInsetsController.java
index 02323cf..f501de9 100644
--- a/core/java/android/view/WindowInsetsController.java
+++ b/core/java/android/view/WindowInsetsController.java
@@ -167,62 +167,6 @@
@NonNull WindowInsetsAnimationControlListener listener);
/**
- * Lets the application control the animation for showing the IME in a frame-by-frame manner by
- * modifying the position of the IME when it's causing insets.
- *
- * @param durationMillis Duration of the animation in
- * {@link java.util.concurrent.TimeUnit#MILLISECONDS}, or -1 if the
- * animation doesn't have a predetermined duration. This value will be
- * passed to {@link InsetsAnimation#getDurationMillis()}
- * @param interpolator The interpolator used for this animation, or {@code null} if this
- * animation doesn't follow an interpolation curve. This value will be
- * passed to {@link InsetsAnimation#getInterpolator()} and used to calculate
- * {@link InsetsAnimation#getInterpolatedFraction()}.
- * @param listener The {@link WindowInsetsAnimationControlListener} that gets called when the
- * IME are ready to be controlled, among other callbacks.
- *
- * @see InsetsAnimation#getFraction()
- * @see InsetsAnimation#getInterpolatedFraction()
- * @see InsetsAnimation#getInterpolator()
- * @see InsetsAnimation#getDurationMillis()
- */
- default void controlInputMethodAnimation(long durationMillis,
- @Nullable Interpolator interpolator,
- @NonNull WindowInsetsAnimationControlListener listener) {
- controlWindowInsetsAnimation(ime(), durationMillis, interpolator, listener);
- }
-
- /**
- * Makes the IME appear on screen.
- * <p>
- * Note that if the window currently doesn't have control over the IME, because it doesn't have
- * focus, it will apply the change as soon as the window gains control. The app can listen to
- * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
- * {@link WindowInsets#isVisible}.
- *
- * @see #controlInputMethodAnimation
- * @see #hideInputMethod()
- */
- default void showInputMethod() {
- show(ime());
- }
-
- /**
- * Makes the IME disappear on screen.
- * <p>
- * Note that if the window currently doesn't have control over IME, because it doesn't have
- * focus, it will apply the change as soon as the window gains control. The app can listen to
- * the event by observing {@link View#onApplyWindowInsets} and checking visibility with
- * {@link WindowInsets#isVisible}.
- *
- * @see #controlInputMethodAnimation
- * @see #showInputMethod()
- */
- default void hideInputMethod() {
- hide(ime());
- }
-
- /**
* Controls the appearance of system bars.
* <p>
* For example, the following statement adds {@link #APPEARANCE_LIGHT_STATUS_BARS}:
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index a6450a1..dad7671 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -80,6 +80,7 @@
import android.text.TextUtils;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
+import android.view.View.OnApplyWindowInsetsListener;
import android.view.WindowInsets.Side;
import android.view.WindowInsets.Side.InsetsSide;
import android.view.WindowInsets.Type;
@@ -2193,8 +2194,9 @@
* value for {@link #softInputMode} will be ignored; the window will
* not resize, but will stay fullscreen.
*
- * @deprecated Use {@link Window#setOnContentApplyWindowInsetsListener} instead with a
- * listener that fits {@link Type#ime()} instead.
+ * @deprecated Call {@link Window#setDecorFitsSystemWindows(boolean)} with {@code false} and
+ * install an {@link OnApplyWindowInsetsListener} on your root content view that fits insets
+ * of type {@link Type#ime()}.
*/
@Deprecated
public static final int SOFT_INPUT_ADJUST_RESIZE = 0x10;
diff --git a/core/java/android/view/autofill/AutofillPopupWindow.java b/core/java/android/view/autofill/AutofillPopupWindow.java
index 8266207..8d3dc83 100644
--- a/core/java/android/view/autofill/AutofillPopupWindow.java
+++ b/core/java/android/view/autofill/AutofillPopupWindow.java
@@ -19,13 +19,13 @@
import static android.view.autofill.Helper.sVerbose;
import android.annotation.NonNull;
-import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.IBinder;
import android.os.RemoteException;
import android.transition.Transition;
import android.util.Log;
+import android.util.Size;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.ViewTreeObserver;
@@ -127,11 +127,12 @@
// If it is not fullscreen height, put window at bottom. Computes absolute position.
// Note that we cannot easily change default gravity from Gravity.TOP to
// Gravity.BOTTOM because PopupWindow base class does not expose computeGravity().
- final Point outPoint = new Point();
- anchor.getContext().getDisplay().getSize(outPoint);
- width = outPoint.x;
+ final WindowManager windowManager = anchor.getContext()
+ .getSystemService(WindowManager.class);
+ final Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
+ width = windowSize.getWidth();
if (height != LayoutParams.MATCH_PARENT) {
- offsetY = outPoint.y - height;
+ offsetY = windowSize.getHeight() - height;
}
actualAnchor = anchor;
} else if (virtualBounds != null) {
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 051534c..bbb7513 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -359,7 +359,7 @@
mMultiProfilePagerAdapter.getPersonalListAdapter());
mPersonalPackageMonitor.register(
this, getMainLooper(), getPersonalProfileUserHandle(), false);
- if (hasWorkProfile()) {
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
mWorkPackageMonitor = createPackageMonitor(
mMultiProfilePagerAdapter.getWorkListAdapter());
mWorkPackageMonitor.register(this, getMainLooper(), getWorkProfileUserHandle(), false);
@@ -725,7 +725,7 @@
if (!mRegistered) {
mPersonalPackageMonitor.register(this, getMainLooper(),
getPersonalProfileUserHandle(), false);
- if (hasWorkProfile()) {
+ if (hasWorkProfile() && ENABLE_TABBED_VIEW) {
if (mWorkPackageMonitor == null) {
mWorkPackageMonitor = createPackageMonitor(
mMultiProfilePagerAdapter.getWorkListAdapter());
@@ -1155,7 +1155,9 @@
}
private void safelyStartActivityInternal(TargetInfo cti) {
- mPersonalPackageMonitor.unregister();
+ if (mPersonalPackageMonitor != null) {
+ mPersonalPackageMonitor.unregister();
+ }
if (mWorkPackageMonitor != null) {
mWorkPackageMonitor.unregister();
}
diff --git a/core/java/com/android/internal/compat/ChangeReporter.java b/core/java/com/android/internal/compat/ChangeReporter.java
index e0eb9af..5e886a6 100644
--- a/core/java/com/android/internal/compat/ChangeReporter.java
+++ b/core/java/com/android/internal/compat/ChangeReporter.java
@@ -16,13 +16,16 @@
package com.android.internal.compat;
+import android.annotation.IntDef;
import android.util.Log;
import android.util.Slog;
-import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.FrameworkStatsLog;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
@@ -42,7 +45,7 @@
long mChangeId;
int mState;
- ChangeReport(long changeId, int state) {
+ ChangeReport(long changeId, @State int state) {
mChangeId = changeId;
mState = state;
}
@@ -69,7 +72,7 @@
// When true will of every time to debug (logcat).
private boolean mDebugLogAll;
- public ChangeReporter(int source) {
+ public ChangeReporter(@Source int source) {
mSource = source;
mReportedChanges = new HashMap<>();
mDebugLogAll = false;
@@ -85,8 +88,8 @@
*/
public void reportChange(int uid, long changeId, int state) {
if (shouldWriteToStatsLog(uid, changeId, state)) {
- StatsLog.write(StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid, changeId,
- state, mSource);
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED, uid,
+ changeId, state, mSource);
}
if (shouldWriteToDebug(uid, changeId, state)) {
debugLog(uid, changeId, state);
@@ -110,7 +113,7 @@
/**
- * Returns whether the next report should be logged to statsLog.
+ * Returns whether the next report should be logged to FrameworkStatsLog.
*
* @param uid affected by the change
* @param changeId the reported change id
@@ -174,7 +177,7 @@
private void debugLog(int uid, long changeId, int state) {
String message = String.format("Compat change id reported: %d; UID %d; state: %s", changeId,
uid, stateToString(state));
- if (mSource == StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER) {
+ if (mSource == SOURCE_SYSTEM_SERVER) {
Slog.d(TAG, message);
} else {
Log.d(TAG, message);
@@ -183,21 +186,56 @@
}
/**
- * Transforms StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE enum to a string.
+ * Transforms {@link #ChangeReporter.State} enum to a string.
*
* @param state to transform
* @return a string representing the state
*/
- private static String stateToString(int state) {
+ private static String stateToString(@State int state) {
switch (state) {
- case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED:
+ case STATE_LOGGED:
return "LOGGED";
- case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED:
+ case STATE_ENABLED:
return "ENABLED";
- case StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED:
+ case STATE_DISABLED:
return "DISABLED";
default:
return "UNKNOWN";
}
}
+
+ /** These values should be kept in sync with those in atoms.proto */
+ public static final int STATE_UNKNOWN_STATE =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__UNKNOWN_STATE;
+ public static final int STATE_ENABLED =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED;
+ public static final int STATE_DISABLED =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED;
+ public static final int STATE_LOGGED =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED;
+ public static final int SOURCE_UNKNOWN_SOURCE =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__UNKNOWN_SOURCE;
+ public static final int SOURCE_APP_PROCESS =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__APP_PROCESS;
+ public static final int SOURCE_SYSTEM_SERVER =
+ FrameworkStatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER;
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "STATE_" }, value = {
+ STATE_UNKNOWN_STATE,
+ STATE_ENABLED,
+ STATE_DISABLED,
+ STATE_LOGGED
+ })
+ public @interface State {
+ }
+
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(flag = true, prefix = { "SOURCE_" }, value = {
+ SOURCE_UNKNOWN_SOURCE,
+ SOURCE_APP_PROCESS,
+ SOURCE_SYSTEM_SERVER
+ })
+ public @interface Source {
+ }
}
diff --git a/core/java/com/android/internal/os/RuntimeInit.java b/core/java/com/android/internal/os/RuntimeInit.java
index db009f6..c6ed624 100644
--- a/core/java/com/android/internal/os/RuntimeInit.java
+++ b/core/java/com/android/internal/os/RuntimeInit.java
@@ -67,9 +67,10 @@
private static volatile boolean mCrashing = false;
- /*
+ /**
* Native heap allocations will now have a non-zero tag in the most significant byte.
- * See {@linktourl https://source.android.com/devices/tech/debug/tagged-pointers}.
+ * See
+ * <a href="https://source.android.com/devices/tech/debug/tagged-pointers">https://source.android.com/devices/tech/debug/tagged-pointers</a>.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = VersionCodes.Q)
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index f13a638..46d7f4e 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -320,7 +320,8 @@
/** @see ViewRootImpl#mActivityConfigCallback */
private ActivityConfigCallback mActivityConfigCallback;
- private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener;
+ private OnContentApplyWindowInsetsListener mPendingOnContentApplyWindowInsetsListener
+ = createDefaultContentWindowInsetsListener();
static class WindowManagerHolder {
static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -2109,14 +2110,9 @@
/** Notify when decor view is attached to window and {@link ViewRootImpl} is available. */
void onViewRootImplSet(ViewRootImpl viewRoot) {
viewRoot.setActivityConfigCallback(mActivityConfigCallback);
- if (mPendingOnContentApplyWindowInsetsListener != null) {
- viewRoot.setOnContentApplyWindowInsetsListener(
- mPendingOnContentApplyWindowInsetsListener);
- mPendingOnContentApplyWindowInsetsListener = null;
- } else {
- viewRoot.setOnContentApplyWindowInsetsListener(
- createDefaultContentWindowInsetsListener());
- }
+ viewRoot.setOnContentApplyWindowInsetsListener(
+ mPendingOnContentApplyWindowInsetsListener);
+ mPendingOnContentApplyWindowInsetsListener = null;
}
private OnContentApplyWindowInsetsListener createDefaultContentWindowInsetsListener() {
@@ -2125,8 +2121,9 @@
return new Pair<>(Insets.NONE, insets);
}
- boolean includeIme = (getAttributes().softInputMode & SOFT_INPUT_MASK_ADJUST)
- == SOFT_INPUT_ADJUST_RESIZE;
+ boolean includeIme =
+ (getViewRootImpl().mWindowAttributes.softInputMode & SOFT_INPUT_MASK_ADJUST)
+ == SOFT_INPUT_ADJUST_RESIZE;
Insets insetsToApply;
if (ViewRootImpl.sNewInsetsMode == 0) {
insetsToApply = insets.getSystemWindowInsets();
@@ -3902,17 +3899,15 @@
}
@Override
- public void setOnContentApplyWindowInsetsListener(OnContentApplyWindowInsetsListener listener) {
+ public void setDecorFitsSystemWindows(boolean decorFitsSystemWindows) {
ViewRootImpl impl = getViewRootImpl();
+ OnContentApplyWindowInsetsListener listener = decorFitsSystemWindows
+ ? createDefaultContentWindowInsetsListener()
+ : null;
if (impl != null) {
impl.setOnContentApplyWindowInsetsListener(listener);
} else {
mPendingOnContentApplyWindowInsetsListener = listener;
}
}
-
- @Override
- public void resetOnContentApplyWindowInsetsListener() {
- setOnContentApplyWindowInsetsListener(createDefaultContentWindowInsetsListener());
- }
}
diff --git a/core/java/com/android/internal/util/Preconditions.java b/core/java/com/android/internal/util/Preconditions.java
index 408a7a8..a87e080f 100644
--- a/core/java/com/android/internal/util/Preconditions.java
+++ b/core/java/com/android/internal/util/Preconditions.java
@@ -21,7 +21,9 @@
import android.compat.annotation.UnsupportedAppUsage;
import android.text.TextUtils;
+import java.util.Arrays;
import java.util.Collection;
+import java.util.Objects;
/**
* Simple static methods to be called at the start of your own methods to verify
@@ -497,6 +499,64 @@
}
/**
+ * Ensures that the given byte array is not {@code null}, and contains at least one element.
+ *
+ * @param value an array of elements.
+ * @param valueName the name of the argument to use if the check fails.
+
+ * @return the validated array
+ *
+ * @throws NullPointerException if the {@code value} was {@code null}
+ * @throws IllegalArgumentException if the {@code value} was empty
+ */
+ @NonNull
+ public static byte[] checkByteArrayNotEmpty(final byte[] value, final String valueName) {
+ if (value == null) {
+ throw new NullPointerException(valueName + " must not be null");
+ }
+ if (value.length == 0) {
+ throw new IllegalArgumentException(valueName + " is empty");
+ }
+ return value;
+ }
+
+ /**
+ * Ensures that argument {@code value} is one of {@code supportedValues}.
+ *
+ * @param supportedValues an array of string values
+ * @param value a string value
+ *
+ * @return the validated value
+ *
+ * @throws NullPointerException if either {@code value} or {@code supportedValues} is null
+ * @throws IllegalArgumentException if the {@code value} is not in {@code supportedValues}
+ */
+ @NonNull
+ public static String checkArgumentIsSupported(final String[] supportedValues,
+ final String value) {
+ checkNotNull(value);
+ checkNotNull(supportedValues);
+
+ if (!contains(supportedValues, value)) {
+ throw new IllegalArgumentException(value + "is not supported "
+ + Arrays.toString(supportedValues));
+ }
+ return value;
+ }
+
+ private static boolean contains(String[] values, String value) {
+ if (values == null) {
+ return false;
+ }
+ for (int i = 0; i < values.length; ++i) {
+ if (Objects.equals(value, values[i])) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
* Ensures that all elements in the argument floating point array are within the inclusive range
*
* <p>While this can be used to range check against +/- infinity, note that all NaN numbers
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index f9e98e7..69b1609 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -29,7 +29,6 @@
import android.view.ViewConfiguration;
import android.view.ViewGroup;
import android.view.ViewParent;
-import android.view.WindowManager;
import android.widget.PopupWindow;
import com.android.internal.R;
@@ -211,8 +210,7 @@
}
private boolean isContentRectWithinBounds() {
- mContext.getSystemService(WindowManager.class)
- .getDefaultDisplay().getRealSize(mDisplaySize);
+ mContext.getDisplay().getRealSize(mDisplaySize);
mScreenRect.set(0, 0, mDisplaySize.x, mDisplaySize.y);
return intersectsClosed(mContentRectOnScreen, mScreenRect)
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index bac6025..0aeaa47 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -24,10 +24,12 @@
import android.content.Context;
import android.graphics.Point;
import android.graphics.Rect;
+import android.util.Size;
import android.view.Display;
import android.view.Gravity;
import android.view.View;
import android.view.WindowManager;
+import android.view.WindowMetrics;
import android.widget.PopupWindow.OnDismissListener;
import com.android.internal.view.menu.MenuPresenter.Callback;
@@ -224,13 +226,10 @@
*/
@NonNull
private MenuPopup createPopup() {
- final WindowManager windowManager = (WindowManager) mContext.getSystemService(
- Context.WINDOW_SERVICE);
- final Display display = windowManager.getDefaultDisplay();
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
+ final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
+ final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
- final int smallestWidth = Math.min(displaySize.x, displaySize.y);
+ final int smallestWidth = Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
final int minSmallestWidthCascading = mContext.getResources().getDimensionPixelSize(
com.android.internal.R.dimen.cascading_menus_min_smallest_width);
final boolean enableCascadingSubmenus = smallestWidth >= minSmallestWidthCascading;
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index de02eb0..e24e982 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -89,4 +89,6 @@
in List<WrappedApplicationKey> applicationKeys);
void closeSession(in String sessionId);
boolean hasSecureLockScreen();
+ boolean tryUnlockWithCachedUnifiedChallenge(int userId);
+ void removeCachedUnifiedChallenge(int userId);
}
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f37a468..864429c 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -55,10 +55,10 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.LocalServices;
-import libcore.util.HexEncoding;
-
import com.google.android.collect.Lists;
+import libcore.util.HexEncoding;
+
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.security.MessageDigest;
@@ -1755,4 +1755,33 @@
return FRP_CREDENTIAL_ENABLED && context.getResources().getBoolean(
com.android.internal.R.bool.config_enableCredentialFactoryResetProtection);
}
+
+ /**
+ * Attempt to rederive the unified work challenge for the specified profile user and unlock the
+ * user. If successful, this would allow the user to leave quiet mode automatically without
+ * additional user authentication.
+ *
+ * This is made possible by the framework storing an encrypted copy of the unified challenge
+ * auth-bound to the primary user's lockscreen. As long as the primery user has unlocked
+ * recently (7 days), the framework will be able to decrypt it and plug the secret into the
+ * unlock flow.
+ *
+ * @return {@code true} if automatic unlocking is successful, {@code false} otherwise.
+ */
+ public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
+ try {
+ return getLockSettings().tryUnlockWithCachedUnifiedChallenge(userId);
+ } catch (RemoteException re) {
+ return false;
+ }
+ }
+
+ /** Remove cached unified profile challenge, for testing and CTS usage. */
+ public void removeCachedUnifiedChallenge(int userId) {
+ try {
+ getLockSettings().removeCachedUnifiedChallenge(userId);
+ } catch (RemoteException re) {
+ re.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index a2f514a..cec68df 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -137,6 +137,7 @@
"android_os_Parcel.cpp",
"android_os_SELinux.cpp",
"android_os_SharedMemory.cpp",
+ "android_os_storage_StorageManager.cpp",
"android_os_Trace.cpp",
"android_os_UEventObserver.cpp",
"android_os_VintfObject.cpp",
@@ -147,7 +148,6 @@
"android_service_DataLoaderService.cpp",
"android_util_AssetManager.cpp",
"android_util_Binder.cpp",
- "android_util_StatsLog.cpp",
"android_util_MemoryIntArray.cpp",
"android_util_Process.cpp",
"android_util_StringBlock.cpp",
@@ -269,6 +269,7 @@
"libnativewindow",
"libdl",
"libdl_android",
+ "libstats_jni",
"libstatslog",
"server_configurable_flags",
],
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 9783b65..481be24 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -144,6 +144,7 @@
extern int register_android_os_SELinux(JNIEnv* env);
extern int register_android_os_VintfObject(JNIEnv *env);
extern int register_android_os_VintfRuntimeInfo(JNIEnv *env);
+extern int register_android_os_storage_StorageManager(JNIEnv* env);
extern int register_android_os_SystemProperties(JNIEnv *env);
extern int register_android_os_SystemClock(JNIEnv* env);
extern int register_android_os_Trace(JNIEnv* env);
@@ -622,6 +623,8 @@
char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
char jittransitionweightOptBuf[sizeof("-Xjittransitionweight:")-1 + PROPERTY_VALUE_MAX];
char hotstartupsamplesOptsBuf[sizeof("-Xps-hot-startup-method-samples:")-1 + PROPERTY_VALUE_MAX];
+ char saveResolvedClassesDelayMsOptsBuf[
+ sizeof("-Xps-save-resolved-classes-delay-ms:")-1 + PROPERTY_VALUE_MAX];
char madviseRandomOptsBuf[sizeof("-XX:MadviseRandomAccess:")-1 + PROPERTY_VALUE_MAX];
char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
@@ -817,6 +820,9 @@
parseRuntimeOption("dalvik.vm.hot-startup-method-samples", hotstartupsamplesOptsBuf,
"-Xps-hot-startup-method-samples:");
+ parseRuntimeOption("dalvik.vm.ps-resolved-classes-delay-ms", saveResolvedClassesDelayMsOptsBuf,
+ "-Xps-save-resolved-classes-delay-ms:");
+
property_get("ro.config.low_ram", propBuf, "");
if (strcmp(propBuf, "true") == 0) {
addOption("-XX:LowMemoryMode");
@@ -1463,6 +1469,7 @@
REG_JNI(register_android_os_HwParcel),
REG_JNI(register_android_os_HwRemoteBinder),
REG_JNI(register_android_os_NativeHandle),
+ REG_JNI(register_android_os_storage_StorageManager),
REG_JNI(register_android_os_VintfObject),
REG_JNI(register_android_os_VintfRuntimeInfo),
REG_JNI(register_android_service_DataLoaderService),
diff --git a/core/jni/android_os_storage_StorageManager.cpp b/core/jni/android_os_storage_StorageManager.cpp
new file mode 100644
index 0000000..aee6733
--- /dev/null
+++ b/core/jni/android_os_storage_StorageManager.cpp
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "StorageManager"
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <fcntl.h>
+#include <linux/fs.h>
+
+#include <nativehelper/JNIHelp.h>
+#include "core_jni_helpers.h"
+
+namespace android {
+
+jboolean android_os_storage_StorageManager_setQuotaProjectId(JNIEnv* env, jobject self,
+ jstring path, jlong projectId) {
+ struct fsxattr fsx;
+ ScopedUtfChars utf_chars_path(env, path);
+
+ if (projectId > UINT32_MAX) {
+ LOG(ERROR) << "Invalid project id: " << projectId;
+ return JNI_FALSE;
+ }
+
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(utf_chars_path.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << utf_chars_path.c_str() << " to set project id.";
+ return JNI_FALSE;
+ }
+
+ int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx);
+ if (ret == -1) {
+ PLOG(ERROR) << "Failed to get extended attributes for " << utf_chars_path.c_str()
+ << " to get project id.";
+ return JNI_FALSE;
+ }
+
+ fsx.fsx_projid = projectId;
+ ret = ioctl(fd, FS_IOC_FSSETXATTR, &fsx);
+ if (ret == -1) {
+ PLOG(ERROR) << "Failed to set extended attributes for " << utf_chars_path.c_str()
+ << " to set project id.";
+ return JNI_FALSE;
+ }
+
+ return JNI_TRUE;
+}
+
+// ----------------------------------------------------------------------------
+
+static const JNINativeMethod gStorageManagerMethods[] = {
+ {"setQuotaProjectId", "(Ljava/lang/String;J)Z",
+ (void*)android_os_storage_StorageManager_setQuotaProjectId},
+};
+
+const char* const kStorageManagerPathName = "android/os/storage/StorageManager";
+
+int register_android_os_storage_StorageManager(JNIEnv* env) {
+ return RegisterMethodsOrDie(env, kStorageManagerPathName, gStorageManagerMethods,
+ NELEM(gStorageManagerMethods));
+}
+
+}; // namespace android
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index 538861e..a8246c7 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -151,11 +151,11 @@
return true;
}
-static jboolean android_view_RenderNode_setOutlineConvexPath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
+static jboolean android_view_RenderNode_setOutlinePath(CRITICAL_JNI_PARAMS_COMMA jlong renderNodePtr,
jlong outlinePathPtr, jfloat alpha) {
RenderNode* renderNode = reinterpret_cast<RenderNode*>(renderNodePtr);
SkPath* outlinePath = reinterpret_cast<SkPath*>(outlinePathPtr);
- renderNode->mutateStagingProperties().mutableOutline().setConvexPath(outlinePath, alpha);
+ renderNode->mutateStagingProperties().mutableOutline().setPath(outlinePath, alpha);
renderNode->setPropertyFieldsDirty(RenderNode::GENERIC);
return true;
}
@@ -684,7 +684,7 @@
{ "nSetProjectionReceiver","(JZ)Z", (void*) android_view_RenderNode_setProjectionReceiver },
{ "nSetOutlineRoundRect", "(JIIIIFF)Z", (void*) android_view_RenderNode_setOutlineRoundRect },
- { "nSetOutlineConvexPath", "(JJF)Z", (void*) android_view_RenderNode_setOutlineConvexPath },
+ { "nSetOutlinePath", "(JJF)Z", (void*) android_view_RenderNode_setOutlinePath },
{ "nSetOutlineEmpty", "(J)Z", (void*) android_view_RenderNode_setOutlineEmpty },
{ "nSetOutlineNone", "(J)Z", (void*) android_view_RenderNode_setOutlineNone },
{ "nHasShadow", "(J)Z", (void*) android_view_RenderNode_hasShadow },
diff --git a/core/jni/fd_utils.cpp b/core/jni/fd_utils.cpp
index 1fcc8ac..cfd3c09 100644
--- a/core/jni/fd_utils.cpp
+++ b/core/jni/fd_utils.cpp
@@ -51,6 +51,7 @@
"/dev/socket/webview_zygote",
"/dev/socket/heapprofd",
"/sys/kernel/debug/tracing/trace_marker",
+ "/sys/kernel/tracing/trace_marker",
"/system/framework/framework-res.apk",
"/dev/urandom",
"/dev/ion",
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 1426932..0a2fd70 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -55,87 +55,8 @@
message ActivityManagerServiceDumpActivitiesProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
- optional ActivityStackSupervisorProto activity_stack_supervisor = 1;
-}
-
-message ActivityStackSupervisorProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
- repeated ActivityDisplayProto displays = 2;
- optional KeyguardControllerProto keyguard_controller = 3;
- // TODO(b/111541062): Focused stack and resumed activity are now per-display. Topmost instances
- // can be obtained from top display and these fields can be removed.
- optional int32 focused_stack_id = 4;
- optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
- // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
- // know what activity types to check for when invoking splitscreen multi-window.
- optional bool is_home_recents_component = 6;
- repeated .com.android.server.wm.IdentifierProto pending_activities = 7;
- optional .com.android.server.wm.RootWindowContainerProto root_window_container = 8;
-}
-
-/* represents ActivityStackSupervisor.ActivityDisplay */
-message ActivityDisplayProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // To be removed soon.
- optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
- optional int32 id = 2;
- repeated ActivityStackProto stacks = 3;
- optional int32 focused_stack_id = 4;
- optional .com.android.server.wm.IdentifierProto resumed_activity = 5;
- optional bool single_task_instance = 6;
- optional .com.android.server.wm.DisplayContentProto display = 7;
-}
-
-message ActivityStackProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // To be removed soon.
- optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
- optional int32 id = 2;
- repeated TaskRecordProto tasks = 3;
- optional .com.android.server.wm.IdentifierProto resumed_activity = 4;
- optional int32 display_id = 5;
- optional bool fullscreen = 6;
- optional .android.graphics.RectProto bounds = 7;
- optional .com.android.server.wm.StackProto stack = 8;
-}
-
-message TaskRecordProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- // To be removed soon.
- optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 1 [deprecated=true];
- optional int32 id = 2;
- repeated .com.android.server.wm.ActivityRecordProto activities = 3;
- optional int32 stack_id = 4;
- optional .android.graphics.RectProto last_non_fullscreen_bounds = 5;
- optional string real_activity = 6;
- optional string orig_activity = 7;
- optional int32 activity_type = 8;
- optional int32 resize_mode = 9;
- optional bool fullscreen = 10;
- optional .android.graphics.RectProto bounds = 11;
- optional int32 min_width = 12;
- optional int32 min_height = 13;
- optional .com.android.server.wm.TaskProto task = 14;
-}
-
-message KeyguardControllerProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional bool keyguard_showing = 1;
- repeated KeyguardOccludedProto keyguard_occluded_states= 2;
- optional bool aod_showing = 3;
-}
-
-message KeyguardOccludedProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional int32 display_id = 1;
- optional bool keyguard_occluded = 2;
+ reserved 1; // activity_stack_supervisor
+ optional .com.android.server.wm.RootWindowContainerProto root_window_container = 2;
}
// "dumpsys activity --proto broadcasts"
@@ -669,8 +590,6 @@
optional int64 previous_proc_visible_time_ms = 17;
optional ProcessRecordProto heavy_weight_proc = 18;
optional .android.content.ConfigurationProto global_configuration = 19;
- // ActivityStackSupervisorProto dumps these values as well, still here?
- // repeated ActivityDisplayProto displays = 20;
optional bool config_will_change = 21;
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index c0743e5..b0b9ce6f 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -54,8 +54,14 @@
optional WindowContainerProto window_container = 1;
repeated DisplayContentProto displays = 2;
+ reserved 3; // IdentifierProto windows
/* window references in top down z order */
- repeated IdentifierProto windows = 3;
+ repeated WindowStateProto windows = 4;
+ optional KeyguardControllerProto keyguard_controller = 5;
+ // Whether or not the home activity is the recents activity. This is needed for the CTS tests to
+ // know what activity types to check for when invoking splitscreen multi-window.
+ optional bool is_home_recents_component = 6;
+ repeated IdentifierProto pending_activities = 7;
}
message BarControllerProto {
@@ -94,6 +100,21 @@
optional InteractiveState interactive_state = 5;
}
+message KeyguardControllerProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional bool keyguard_showing = 1;
+ repeated KeyguardOccludedProto keyguard_occluded_states = 2;
+ optional bool aod_showing = 3;
+}
+
+message KeyguardOccludedProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional int32 display_id = 1;
+ optional bool keyguard_occluded = 2;
+}
+
/* represents PhoneWindowManager */
message WindowManagerPolicyProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
@@ -145,14 +166,14 @@
optional WindowContainerProto window_container = 1;
optional int32 id = 2;
- repeated StackProto stacks = 3;
+ reserved 3; // stacks
optional DockedStackDividerControllerProto docked_stack_divider_controller = 4;
// Will be removed soon.
optional PinnedStackControllerProto pinned_stack_controller = 5 [deprecated=true];
/* non app windows */
- repeated WindowTokenProto above_app_windows = 6;
- repeated WindowTokenProto below_app_windows = 7;
- repeated WindowTokenProto ime_windows = 8;
+ repeated WindowTokenProto above_app_windows = 6 [deprecated=true];
+ repeated WindowTokenProto below_app_windows = 7 [deprecated=true];
+ repeated WindowTokenProto ime_windows = 8 [deprecated=true];
optional int32 dpi = 9;
optional .android.view.DisplayInfoProto display_info = 10;
optional int32 rotation = 11;
@@ -165,6 +186,36 @@
repeated IdentifierProto closing_apps = 18;
repeated IdentifierProto changing_apps = 19;
repeated WindowTokenProto overlay_windows = 20;
+ optional DisplayAreaProto root_display_area = 21;
+
+
+ optional bool single_task_instance = 22;
+ optional int32 focused_root_task_id = 23;
+ optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
+ repeated TaskProto tasks = 25;
+}
+
+/* represents DisplayArea object */
+message DisplayAreaProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ optional WindowContainerProto window_container = 1;
+ optional string name = 2 [ (.android.privacy).dest = DEST_EXPLICIT ];
+ repeated DisplayAreaChildProto children = 3;
+}
+
+/* represents a generic child of a DisplayArea */
+message DisplayAreaChildProto {
+ option (.android.msg_privacy).dest = DEST_AUTOMATIC;
+
+ /* At most one of the following should be present: */
+
+ /* represents a DisplayArea child */
+ optional DisplayAreaProto display_area = 1;
+ /* represents a WindowToken child */
+ optional WindowTokenProto window = 2;
+ /* represents an unknown child - the class name is recorded */
+ repeated string unknown = 3;
}
/* represents DisplayFrames */
@@ -189,39 +240,41 @@
optional .android.graphics.RectProto movement_bounds = 2 [deprecated=true];
}
-/* represents TaskStack */
-message StackProto {
- option (.android.msg_privacy).dest = DEST_AUTOMATIC;
-
- optional WindowContainerProto window_container = 1;
- optional int32 id = 2;
- repeated TaskProto tasks = 3;
- optional bool fills_parent = 4;
- optional .android.graphics.RectProto bounds = 5;
- optional bool animation_background_surface_is_dimming = 6 [deprecated=true];
- optional bool defer_removal = 7;
- optional float minimize_amount = 8;
- optional bool adjusted_for_ime = 9;
- optional float adjust_ime_amount = 10;
- optional float adjust_divider_amount = 11;
- optional .android.graphics.RectProto adjusted_bounds = 12;
- optional bool animating_bounds = 13;
-}
-
/* represents Task */
message TaskProto {
option (.android.msg_privacy).dest = DEST_AUTOMATIC;
optional WindowContainerProto window_container = 1;
optional int32 id = 2;
- repeated ActivityRecordProto activity = 3;
+ reserved 3; // activity
optional bool fills_parent = 4;
optional .android.graphics.RectProto bounds = 5;
optional .android.graphics.RectProto displayed_bounds = 6;
- // Will be removed soon.
- optional bool defer_removal = 7 [deprecated=true];
+ optional bool defer_removal = 7;
optional int32 surface_width = 8;
optional int32 surface_height = 9;
+
+ repeated TaskProto tasks = 10;
+ repeated ActivityRecordProto activities = 11;
+
+ optional .com.android.server.wm.IdentifierProto resumed_activity = 12;
+ optional string real_activity = 13;
+ optional string orig_activity = 14;
+
+ optional int32 display_id = 15;
+ optional int32 root_task_id = 16;
+ optional int32 activity_type = 17;
+ optional int32 resize_mode = 18;
+ optional int32 min_width = 19;
+ optional int32 min_height = 20;
+
+ optional .android.graphics.RectProto adjusted_bounds = 21;
+ optional .android.graphics.RectProto last_non_fullscreen_bounds = 22;
+ optional bool adjusted_for_ime = 23;
+ optional float adjust_ime_amount = 24;
+ optional float adjust_divider_amount = 25;
+ optional bool animating_bounds = 26;
+ optional float minimize_amount = 27;
}
/* represents ActivityRecordProto */
@@ -246,17 +299,15 @@
optional int32 num_drawn_windows = 15;
optional bool all_drawn = 16;
optional bool last_all_drawn = 17;
- // Will be removed soon
- optional bool removed = 18 [deprecated=true];
+ reserved 18; // removed
optional IdentifierProto starting_window = 19;
optional bool starting_displayed = 20;
- optional bool starting_moved = 21;
+ optional bool starting_moved = 201;
optional bool visible_set_from_transferred_starting_window = 22;
repeated .android.graphics.RectProto frozen_bounds = 23;
optional bool visible = 24;
- // To be removed soon.
- optional .com.android.server.wm.ConfigurationContainerProto configuration_container = 25 [deprecated=true];
- optional .com.android.server.wm.IdentifierProto identifier = 26;
+ reserved 25; // configuration_container
+ optional IdentifierProto identifier = 26;
optional string state = 27;
optional bool front_of_task = 28;
optional int32 proc_id = 29;
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 181a32d..3a1b63d 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4858,19 +4858,6 @@
<permission android:name="android.permission.ACCESS_SHARED_LIBRARIES"
android:protectionLevel="signature|installer" />
- <!-- Allows an app to log compat change usage.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.LOG_COMPAT_CHANGE"
- android:protectionLevel="signature" />
- <!-- Allows an app to read compat change config.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"
- android:protectionLevel="signature" />
- <!-- Allows an app to override compat change config.
- @hide <p>Not for use by third-party applications.</p> -->
- <permission android:name="android.permission.OVERRIDE_COMPAT_CHANGE_CONFIG"
- android:protectionLevel="signature" />
-
<!-- Allows input events to be monitored. Very dangerous! @hide -->
<permission android:name="android.permission.MONITOR_INPUT"
android:protectionLevel="signature" />
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index c34a485..d6c5a13 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Jou toestel sal uitgevee word"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Die administrasieprogram kan nie gebruik word nie. Jou toestel sal nou uitgevee word.\n\nKontak jou organisasie se administrateur as jy vrae het."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Druk is gedeaktiveer deur <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Persoonlike programme is deur \'n administrateur opgeskort"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tik hier om voldoening aan beleid te kontroleer."</string>
<string name="me" msgid="6207584824693813140">"Ek"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-opsies"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-opsies"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Jy het jou ontsluitpatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer verkeerdelik geteken. Na nog <xliff:g id="NUMBER_1">%2$d</xliff:g> onsuksesvolle pogings, sal jy gevra word om jou foon te ontsluit deur middel van \'n e-posrekening.\n\n Probeer weer oor <xliff:g id="NUMBER_2">%3$d</xliff:g> sekondes."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Verwyder"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Die voorgronddiens wat in die agtergrond begin het vanaf <xliff:g id="PACKAGENAME">%1$s</xliff:g> sal nie ingebruik-toestemming hê in toekomstige R-bouweergawes nie. Raadpleeg asseblief go/r-bg-fgs-restriction en dien \'n foutverslag in."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Verhoog volume bo aanbevole vlak?\n\nOm lang tydperke teen hoë volume te luister, kan jou gehoor beskadig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gebruik toeganklikheidkortpad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word.\n\n Bestaande toeganklikheidkenmerk:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Jy kan die kenmerk in Instellings > Toeganklikheid verander."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Program is nie beskikbaar nie"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nie nou onmiddellik beskikbaar nie. Dit word bestuur deur <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Kom meer te wete"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Hervat program"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Skakel werkprofiel aan?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jou werkprogramme, kennisgewings, data en ander werkprofielkenmerke sal aangeskakel word"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Skakel aan"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Wissel verdeelde skerm"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sluitskerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skermkiekie"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Toeganklikheid-kieslys"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> se onderskrifbalk."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in die BEPERK-groep geplaas"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlik"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string>
</resources>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 23e6ccd..e9409fb 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"የእርስዎ መሣሪያ ይደመሰሳል"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"የአስተዳዳሪ መተግበሪያ ስራ ላይ ሊውል አይችልም። የእርስዎን መሣሪያ አሁን ይደመሰሳል።\n\nጥያቄዎች ካለዎት የድርጅትዎን አስተዳዳሪ ያነጋግሩ።"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ማተም በ<xliff:g id="OWNER_APP">%s</xliff:g> ተሰናክሏል።"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"የግል መተግበሪያዎች በአስተዳዳሪ ታግዷል"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"የመመሪያ ተገዥነትን ለመፈተሽ እዚህ ላይ መለያ ያድርጉ።"</string>
<string name="me" msgid="6207584824693813140">"እኔ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"የጡባዊ አማራጮች"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV አማራጮች"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"የመክፈቻ ስርዓተ ጥለቱን <xliff:g id="NUMBER_0">%1$d</xliff:g> ጊዜ በትክክል አልሳሉትም። ከ<xliff:g id="NUMBER_1">%2$d</xliff:g> ተጨማሪ ያልተሳኩ ሙከራዎች በኋላ የኢሜይል መለያ ተጠቅመው ስልክዎን እንዲከፍቱ ይጠየቃሉ።\n\nእባክዎ ከ<xliff:g id="NUMBER_2">%3$d</xliff:g> ሰከንዶች በኋላ እንደገና ይሞክሩ።"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"አስወግድ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ዳራው ከ<xliff:g id="PACKAGENAME">%1$s</xliff:g> የጀመረው የፊት አገልግሎት ወደፊት በሚኖሩት R ግንቦች ላይ ጥቅም ላይ እየዋለ ፈቃድ አይኖረውም። እባክዎ go/r-bg-fgs-restriction እና ፋይል ሳንካ ሪፖርትን ይመልከቱ።"</string>
<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="8306239551412868396">"አቋራጩ ሲበራ ሁለቱንም የድምፅ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።\n\n አሁን ያለ የተደራሽነት ባህሪ፦\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ባህሪውን በቅንብሮች > ተደራሽነት ውስጥ ሊለውጡት ይችላሉ።"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"መተግበሪያ አይገኝም"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> አሁን ላይ አይገኝም። በ<xliff:g id="APP_NAME_1">%2$s</xliff:g> የሚተዳደር ነው።"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"የበለጠ ለመረዳት"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"መተግበሪያን ላፍታ እንዳይቆም አድርግ"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"የስራ መገለጫ ይብራ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"የእርስዎ የስራ መተግበሪያዎች፣ ማሳወቂያዎች፣ ውሂብ እና ሌሎች የስራ መገለጫ ባህሪያት ይበራሉ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"አብራ"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"የተከፈለ ማያን ቀያይር"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"የማያ ገጽ ቁልፍ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ቅጽበታዊ ገጽ እይታ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"የተደራሽነት ምናሌ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"የ<xliff:g id="APP_NAME">%1$s</xliff:g> የሥዕል ገላጭ ጽሑፍ አሞሌ።"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ወደ የRESTRICTED ባልዲ ተከትቷል"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"የግል"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ሥራ"</string>
</resources>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 80c04eb..23ffd7b 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -202,10 +202,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"سيتم محو بيانات جهازك."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"تعذّر استخدام تطبيق المشرف. سيتم محو بيانات جهازك الآن.\n\nإذا كانت لديك أسئلة، اتصل بمشرف مؤسستك."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"تم إيقاف الطباعة بواسطة <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"علّق المشرف عمل التطبيقات الشخصية"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"انقر هنا للتحقّق من الالتزام بالسياسات."</string>
<string name="me" msgid="6207584824693813140">"أنا"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"خيارات الجهاز اللوحي"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"خيارات Android TV"</string>
@@ -1701,8 +1699,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"لقد رسمت نقش فتح القفل بشكل غير صحيح <xliff:g id="NUMBER_0">%1$d</xliff:g> مرة. بعد إجراء <xliff:g id="NUMBER_1">%2$d</xliff:g> من المحاولات غير الناجحة الأخرى، ستُطالب بإلغاء تأمين الهاتف باستخدام حساب بريد إلكتروني لإلغاء تأمين الهاتف.\n\n أعد المحاولة خلال <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانية."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"إزالة"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"لن يتم منح إذن الوصول إلى الموقع الجغرافي أثناء الاستخدام للخدمات التي تعمل في المقدّمة من <xliff:g id="PACKAGENAME">%1$s</xliff:g> والتي تبدأ من الخلفية في إصدارات R القادمة. يُرجى مراجعة go/r-bg-fgs-restriction وتقديم تقرير خطأ."</string>
<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="8306239551412868396">"عند تشغيل الاختصار، يؤدي الضغط على زرّي مستوى الصوت لمدة 3 ثوانٍ إلى تفعيل ميزة \"سهولة الاستخدام\".\n\n ميزة \"سهولة الاستخدام\" الحالية:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n يمكنك تغيير الميزة من \"الإعدادات\" > \"سهولة الاستخدام\"."</string>
@@ -1980,8 +1977,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"التطبيق غير متاح"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"التطبيق <xliff:g id="APP_NAME_0">%1$s</xliff:g> غير متاح الآن، وهو مُدار بواسطة <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"مزيد من المعلومات"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"استئناف تشغيل التطبيق"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"تفعيل الملف الشخصي للعمل؟"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"سيتم تفعيل تطبيقات العمل التي تستخدمها والإشعارات والبيانات وغيرها من ميزات الملف الشخصي للعمل"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"تشغيل"</string>
@@ -2121,7 +2117,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"جدول بيانات: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"عرض تقديمي"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"عرض تقديمي: <xliff:g id="EXTENSION">%1$s</xliff:g>"</string>
- <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"سيظل البلوتوث مفعَّلاً أثناء تفعيل \"وضع الطائرة\"."</string>
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"سيظل البلوتوث مفعَّلاً أثناء استخدام \"وضع الطائرة\"."</string>
<string name="car_loading_profile" msgid="8219978381196748070">"جارٍ التحميل"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="zero"><xliff:g id="FILE_NAME_2">%s</xliff:g> و<xliff:g id="COUNT_3">%d</xliff:g> ملف</item>
@@ -2143,12 +2139,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تبديل \"تقسيم الشاشة\""</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"شاشة القفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"لقطة شاشة"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"قائمة \"سهولة الاستخدام\""</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"شريط الشرح لتطبيق <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"تم وضع <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> في الحزمة \"محظورة\"."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصي"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"عمل"</string>
</resources>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 73e32b8..a09c377 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"আপোনাৰ ডিভাইচৰ ডেটা মচা হ\'ব"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"এই প্ৰশাসক এপটো ব্যৱহাৰ কৰিব নোৱাৰি। এতিয়া আপোনাৰ ডিভাইচটোৰ ডেটা মচা হ\'ব।\n\nআপোনাৰ কিবা প্ৰশ্ন থাকিলে আপোনাৰ প্ৰতিষ্ঠানৰ প্ৰশাসকৰ সৈতে যোগাযোগ কৰক।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"প্ৰিণ্ট কৰা কাৰ্য <xliff:g id="OWNER_APP">%s</xliff:g>এ অক্ষম কৰি ৰাখিছে।"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ব্যক্তিগত এপ্সমূহ এগৰাকী প্ৰশাসকে নিলম্বিত কৰিছে"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"নীতি মানি চলেনে নাই পৰীক্ষা কৰিবলৈ ইয়াত টিপক।"</string>
<string name="me" msgid="6207584824693813140">"মই"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"টে\'বলেটৰ বিকল্পসমূহ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVৰ বিকল্পসমূহ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"আপুনি আপোনাৰ ল\'ক খোলাৰ আৰ্হিটো <xliff:g id="NUMBER_0">%1$d</xliff:g>বাৰ ভুলকৈ আঁকিছে। <xliff:g id="NUMBER_1">%2$d</xliff:g>তকৈ বেছি বাৰ ভুল আৰ্হি আঁকিলে আপোনাৰ ফ\'নটো কোনো একাউণ্টৰ জৰিয়তে আনলক কৰিবলৈ কোৱা হ\'ব।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ছেকেণ্ডৰ পিছত আকৌ চেষ্টা কৰক।"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"আঁতৰাওক"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"নেপথ্যই <xliff:g id="PACKAGENAME">%1$s</xliff:g>ৰ পৰা আৰম্ভ কৰা অগ্ৰভূমিৰ সেৱাটোৰ ভৱিষ্যতৰ R বিল্ডসমূহত ব্যৱহাৰ হৈ থকা সম্পৰ্কীয় অনুমতি নাথাকিব। অনুগ্ৰহ কৰি go/r-bg-fgs-restriction চাওক আৰু এটা বাগৰিপ\'ৰ্ট ফাইল কৰক।"</string>
<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="8306239551412868396">"শ্বৰ্টকাট অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটামত ৩ ছেকেণ্ডৰ বাবে ছাপ দি থাকিলে দিব্যাংগসকলৰ বাবে থকা সুবিধা এটা আৰম্ভ হ\'ব। \n\n চলিত দিব্যাংগসকলৰ সুবিধা:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপুনি এই সুবিধাটো ছেটিংসমূহ > দিব্যাংগসকলৰ বাবে সুবিধা-লৈ গৈ সলনি কৰিব পাৰে।"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"এপটো নাই"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"এই মুহূৰ্তত <xliff:g id="APP_NAME_0">%1$s</xliff:g> উপলব্ধ নহয়। ইয়াক <xliff:g id="APP_NAME_1">%2$s</xliff:g>এ পৰিচালনা কৰে।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"অধিক জানক"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"এপ্ আনপজ কৰক"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"কৰ্মস্থানৰ প্ৰ\'ফাইল অন কৰিবনে?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"আপোনাৰ কৰ্মস্থানৰ এপসমূহ, জাননীসমূহ, ডেটা আৰু কৰ্মস্থানৰ প্ৰ\'ফাইলৰ অইন সুবিধাসমূহ অন কৰা হ\'ব"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"অন কৰক"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"বিভাজিত স্ক্ৰীন ট’গল কৰক"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্ৰীন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্ৰীণশ্বট"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"সাধ্য সুবিধাৰ মেনু"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ৰ কেপশ্বন বাৰ।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ক সীমাবদ্ধ বাকেটটোত ৰখা হৈছে"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"কৰ্মস্থান"</string>
</resources>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index c894c29..b1209b1 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız təmizlənəcəkdir"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Admin tətbiqini istifadə etmək mümkün deyil. Cihaz indi təmizlənəcək.\n\nSualınız varsa, təşkilatın admini ilə əlaqə saxlayın."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Çap <xliff:g id="OWNER_APP">%s</xliff:g> tərəfindən deaktiv edildi."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Şəxsi tətbiqlər admin tərəfindən dayandırılıb"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Siyasətə uyğunluğu yoxlamaq üçün bura toxunun."</string>
<string name="me" msgid="6207584824693813140">"Mən"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planşet seçimləri"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçimləri"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Siz artıq modeli <xliff:g id="NUMBER_0">%1$d</xliff:g> dəfə yanlış daxil etmisiniz.<xliff:g id="NUMBER_1">%2$d</xliff:g> dəfə də yanlış daxil etsəniz, telefonun kilidinin açılması üçün elektron poçt ünvanınız tələb olunacaq.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniyə ərzində yenidən cəhd edin."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Yığışdır"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Arxa fonda başladılan <xliff:g id="PACKAGENAME">%1$s</xliff:g> üzrə ön plan xidmətinin gələcək R versiyalarında \"istifadə zamanı\" icazəsi olmayacaq. go/r-bg-fgs-restriction bölməsinə keçin və baq hesabatı göndərin."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Səsin həcmi tövsiyə olunan səviyyədən artıq olsun?\n\nYüksək səsi uzun zaman dinləmək eşitmə qabiliyyətinizə zərər vura bilər."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Əlçatımlılıq Qısayolu istifadə edilsin?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Qısayol aktiv olduqda hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası işə başlayacaq.\n\n Cari əlçatımlılıq funksiyası:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funksiyanı Ayarlar və Əçatımlılıq bölməsində dəyişə bilərsiniz."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Tətbiq əlçatmazdır"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hazırda əlçatan deyil. Bunu <xliff:g id="APP_NAME_1">%2$s</xliff:g> idarə edir."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Ətraflı məlumat"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Tətbiqi davam etdirin"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"İş profili aktiv edilsin?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"İş tətbiqləri, bildirişləri, data və digər iş profili funksiyaları aktiv ediləcək"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivləşdirin"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekrana keçid"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilid Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran şəkli"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Əlçatımlılıq Menyusu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> başlıq paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> MƏHDUDLAŞDIRILMIŞ səbətinə yerləşdirilib"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Şəxsi"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string>
</resources>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 909c315..5600882 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti obrisan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ne možete da koristite ovu aplikaciju za administratore. Uređaj će sada biti obrisan.\n\nAko imate pitanja, kontaktirajte administratora organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrator je suspendovao lične aplikacije"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovde da biste proverili usklađenost sa smernicama."</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije za tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string>
@@ -1635,8 +1633,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Nacrtali ste šablon za otključavanje netačno <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Posle još <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešna(ih) pokušaja, od vas će biti zatraženo da otključate telefon pomoću naloga e-pošte.\n\nProbajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunde/i."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prvom planu sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> koja je pokrenuta u pozadini neće imati dozvolu tokom korišćenja u budućim R verzijama. Posetite go/r-bg-fgs-restriction i pošaljite izveštaj o grešci."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite da pojačate zvuk iznad preporučenog nivoa?\n\nSlušanje glasne muzike duže vreme može da vam ošteti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li da koristite prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti.\n\n Aktuelna funkcija pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Možete da promenite funkciju u odeljku Podešavanja > Pristupačnost."</string>
@@ -1884,8 +1881,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. <xliff:g id="APP_NAME_1">%2$s</xliff:g> upravlja dostupnošću."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opozovi pauziranje aplikacije"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Da uključimo profil za Work?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Uključiće se poslovne aplikacije, obaveštenja, podaci i druge funkcije profila za Work"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
@@ -2041,12 +2037,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite/isključite podeljeni ekran"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključani ekran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni Pristupačnost"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka sa naslovima aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je dodat u segment OGRANIČENO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Lični"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Poslovni"</string>
</resources>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 19dcf92..fb80e4b 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Даныя вашай прылады будуць сцерты"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Немагчыма выкарыстоўваць праграму адміністравання. Звесткі на вашай прыладзе будуць выдалены.\n\nКалі ў вас ёсць пытанні, звярніцеся да адміністратара арганізацыі."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Друк адключаны ўладальнікам праграмы <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Асабістыя праграмы заблакіраваны адміністратарам"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Націсніце тут, каб упэўніцца ў адпаведнасці правілам."</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Параметры планшэта"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Параметры Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Вы няправільна ўвялі графічны ключ разблакiроўкi пэўную колькасць разоў: <xliff:g id="NUMBER_0">%1$d</xliff:g>. Пасля яшчэ некалькiх няўдалых спроб (<xliff:g id="NUMBER_1">%2$d</xliff:g>) вам будзе прапанавана разблакiраваць тэлефон, увайшоўшы ў Google.\n\n Паўтарыце спробу праз <xliff:g id="NUMBER_2">%3$d</xliff:g> с."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Выдалiць"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Запушчаны ў фонавым рэжыме асноўны сэрвіс з пакета \"<xliff:g id="PACKAGENAME">%1$s</xliff:g>\" не будзе мець дазволу while-in-use у будучых зборках на мове R. Наведайце сайт go/r-bg-fgs-restriction і адпраўце справаздачу пра памылку."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Павялiчыць гук вышэй рэкамендаванага ўзроўню?\n\nДоўгае праслухоўванне музыкi на вялiкай гучнасцi можа пашкодзiць ваш слых."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Выкарыстоўваць камбінацыю хуткага доступу для спецыяльных магчымасцей?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Калі камбінацыя хуткага доступу ўключана, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб уключыць функцыю спецыяльных магчымасцей.\n\n Бягучая функцыя спецыяльных магчымасцей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Вы можаце змяніць гэту функцыю ў меню \"Налады > Спецыяльныя магчымасці\"."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Праграма недаступная"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Праграма \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" цяпер недаступная. Яна кіруецца праграмай \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Даведацца больш"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Скасаваць прыпыненне для праграмы"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Уключыць працоўны профіль?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Будуць уключаны вашы рабочыя праграмы, апавяшчэнні, даныя і іншыя функцыі працоўнага профілю"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Уключыць"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Пераключальнік падзеленага экрана"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Экран блакіроўкі"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Здымак экрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню спецыяльных магчымасцей"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Панэль субцітраў праграмы \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" дададзены ў АБМЕЖАВАНУЮ групу"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Асабістыя"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Працоўныя"</string>
</resources>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 8a68766..2892853 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Данните на устройството ви ще бъдат изтрити"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Приложението за администриране не може да се използва. Сега данните на устройството ви ще бъдат изтрити.\n\nАко имате въпроси, свържете се с администратора на организацията си."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Отпечатването е деактивиранo от <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Личните приложения може да са спрени от администратора"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Докоснете тук, за да проверите дали правилата ст спазват."</string>
<string name="me" msgid="6207584824693813140">"Аз"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции за таблета"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции за Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Начертахте неправилно фигурата си за отключване <xliff:g id="NUMBER_0">%1$d</xliff:g> пъти. След още <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни опита ще бъдете помолени да отключите телефона посредством имейл адрес.\n\n Опитайте отново след <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Премахване"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Задният план, който е стартирал услуга на преден план от <xliff:g id="PACKAGENAME">%1$s</xliff:g>, няма да има разрешение при използване в бъдещите компилации R. Моля, вижте go/r-bg-fgs-restriction и подайте сигнал за програмна грешка."</string>
<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="8306239551412868396">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за промяна на силата на звука и ги задържите 3 секунди.\n\n Текущата функция за достъпност е:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцията от „Настройки“ > „Достъпност“."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Няма достъп до приложението"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"В момента няма достъп до <xliff:g id="APP_NAME_0">%1$s</xliff:g>. Това се управлява от <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Научете повече"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Отмяна на паузата за приложението"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Вкл. на служ. потр. профил?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Служебните ви приложения, известия и данни, както и другите функции на служебния потребителски профил ще бъдат включени"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включване"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Превключване на разделения екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заключен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Екранна снимка"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню за достъпност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Лента за надписи на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакетът <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е поставен в ОГРАНИЧЕНИЯ контейнер"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Служебни"</string>
</resources>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 9ca383d..4c95081 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"আপনার ডিভাইসটি মুছে ফেলা হবে"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"অ্যাডমিন অ্যাপটি ব্যবহার করা যাবে না। আপনার ডিভাইসে থাকা সবকিছু এখন মুছে ফেলা হবে।\n\nকোনও প্রশ্ন থাকলে আপনার প্রতিষ্ঠানের অ্যাডমিনের সাথে যোগাযোগ করুন।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> প্রিন্টিং বন্ধ রেখেছে।"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"অ্যাডমিন ব্যক্তিগত অ্যাপ সাসপেন্ড করেছেন"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"নীতি মেনে চলা হচ্ছে কিনা তা যাচাই করতে এখানে ট্যাপ করুন।"</string>
<string name="me" msgid="6207584824693813140">"আমাকে"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ট্যাবলেট বিকল্পগুলি"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-র বিকল্প"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"আপনি আপনার আনলকের প্যাটার্ন আঁকার ক্ষেত্রে <xliff:g id="NUMBER_0">%1$d</xliff:g> বার ভুল করেছেন৷ আর <xliff:g id="NUMBER_1">%2$d</xliff:g> বার অসফল প্রচেষ্টা করা হলে আপনাকে একটি ইমেল অ্যাকাউন্ট মারফত আপনার ফোন আনলক করতে বলা হবে৷\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> সেকেন্ডের মধ্যে আবার চেষ্টা করুন৷"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"সরান"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> থেকে শুরু হওয়া ফোরগ্রাউন্ড পরিষেবাটির ভবিষ্যতে আর বিল্ডগুলিতে ব্যবহারের অনুমতি নেই। go/r-bg-fgs-restriction দেখুন এবং বাগরিপোর্ট জমা দিন।"</string>
<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="8306239551412868396">"শর্টকাটটি চালু থাকলে দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি বৈশিষ্ট্য চালু হবে।\n\n বর্তমান অ্যাকসেসিবিলিটি বৈশিষ্ট্য:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n আপনি এই বৈশিষ্ট্যটি সেটিংস > অ্যাকসেসিবিলিটিতে গিয়ে পরিবর্তন করতে পারবেন।"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"অ্যাপটি উপলভ্য নয়"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> এখন উপলভ্য নয়। এই অ্যাপটিকে <xliff:g id="APP_NAME_1">%2$s</xliff:g> অ্যাপ ম্যানেজ করে।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"আরও জানুন"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"অ্যাপ আবার চালু করুন"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"কাজের প্রোফাইল চালু করবেন?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"আপনার কাজের অ্যাপ, বিজ্ঞপ্তি, ডেটা এবং কাজের প্রোফাইলের অন্যান্য বৈশিষ্ট্য চালু করা হবে"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"চালু করুন"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"স্প্লিট স্ক্রিন টগল করুন"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"লক স্ক্রিন"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"স্ক্রিনশট"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"অ্যাক্সেসিবিলিটি মেনু"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-এর ক্যাপশন বার।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> সীমাবদ্ধ গ্রুপে অন্তর্ভুক্ত করা হয়েছে"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ব্যক্তিগত"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"অফিস"</string>
</resources>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 5f83aa4..eaa212d 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će biti izbrisan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Nije moguće koristiti aplikaciju administratora. Potpuno će se izbrisati podaci na vašem uređaju.\n\nAko imate pitanja, obratite se administratoru svoje organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Štampanje je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Lične aplikacije je obustavio administrator"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovdje da provjerite usklađenost s pravilima."</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tableta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV uređaja"</string>
@@ -1637,8 +1635,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Pogrešno ste nacrtali uzorak za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Ako napravite još <xliff:g id="NUMBER_1">%2$d</xliff:g> pokušaja bez uspjeha, od vas će se tražiti da otključate telefon pomoću e-pošte. \n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluge iz prvog plana započete u pozadini s web lokacije <xliff:g id="PACKAGENAME">%1$s</xliff:g> neće imati odobrenje za funkciju \"za vrijeme korištenja\" u budućim R verzijama. Pogledajte go/r-bg-fgs-restriction i podnesite izvještaj o greškama."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučenog nivoa?\n\nDužim slušanjem glasnog zvuka možete oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li koristiti Prečicu za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je prečica uključena, pritiskom na oba dugmeta za podešavanje jačine zvuka u trajanju od 3 sekunde pokrenut će se funkcija za pristupačnost.\n\n Trenutna funkcija za pristupačnost je:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciju možete promijeniti ako odete u Postavke > Pristupačnost."</string>
@@ -1886,8 +1883,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno nije dostupna. Ovim upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Ponovo aktiviraj aplikaciju"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Uključiti radni profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se poslovne aplikacije, obavještenja, podaci i druge funkcije radnog profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
@@ -2024,7 +2020,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> tabela"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"Prezentacija"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> prezentacija"</string>
- <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen i u načinu rada u avionu"</string>
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"Bluetooth će ostati uključen tokom načina rada u avionu"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"Učitavanje"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> fajl</item>
@@ -2043,12 +2039,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključi/isključi podijeljeni ekran"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključavanje ekrana"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimak ekrana"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni za pristupačnost"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka za natpis aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je stavljen u odjeljak OGRANIČENO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Lično"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string>
</resources>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 930065b..0b58cae 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"El contingut del dispositiu s\'esborrarà"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No es pot utilitzar l\'aplicació d\'administració. S\'esborraran les dades del dispositiu.\n\nSi tens cap dubte, contacta amb l\'administrador de la teva organització."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha desactivat la impressió."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador ha suspès les aplicacions personals"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca per comprovar si es compleix la política."</string>
<string name="me" msgid="6207584824693813140">"Mi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcions de la tauleta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcions d\'Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Has dibuixat el patró de desbloqueig <xliff:g id="NUMBER_0">%1$d</xliff:g> vegades de manera incorrecta. Si falles <xliff:g id="NUMBER_1">%2$d</xliff:g> vegades més, se\'t demanarà que desbloquegis el telèfon amb un compte de correu electrònic.\n\n Torna-ho a provar d\'aquí a <xliff:g id="NUMBER_2">%3$d</xliff:g> segons."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Elimina"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servei en primer pla (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) iniciat en segon pla no tindrà permís durant l\'ús en compilacions R posteriors. Consulta la pàgina go/r-bg-fgs-restriction i presenta un informe d\'errors."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vols apujar el volum per sobre del nivell recomanat?\n\nSi escoltes música a un volum alt durant períodes llargs, pots danyar-te l\'oïda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vols fer servir la drecera d\'accessibilitat?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si la drecera està activada, prem els dos botons de volum durant 3 segons, per iniciar una funció d\'accessibilitat.\n\n Funció d\'accessibilitat actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pots canviar la funció a Configuració > Accessibilitat."</string>
@@ -1852,10 +1849,9 @@
<string name="app_suspended_title" msgid="888873445010322650">"L\'aplicació no està disponible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no està disponible en aquests moments. Aquesta opció es gestiona a <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Més informació"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reactiva l\'aplicació"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Activar el perfil professional?"</string>
- <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions per a la feina, les notificacions, les dades i altres funcions del perfil professional"</string>
+ <string name="work_mode_off_message" msgid="8417484421098563803">"S\'activaran les teves aplicacions de treball, les notificacions, les dades i altres funcions del perfil professional"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activa"</string>
<string name="deprecated_target_sdk_message" msgid="5203207875657579953">"Aquesta aplicació es va crear per a una versió antiga d\'Android i pot ser que no funcioni correctament. Prova de cercar actualitzacions o contacta amb el desenvolupador."</string>
<string name="deprecated_target_sdk_app_store" msgid="8456784048558808909">"Cerca actualitzacions"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Commuta Pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueig"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú d\'accessibilitat"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de títol de l\'aplicació <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> s\'ha transferit al segment RESTRINGIT"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Feina"</string>
</resources>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 2c017dd..5874c24 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Zařízení bude vymazáno"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikaci pro správu nelze použít. Zařízení teď bude vymazáno.\n\nV případě dotazů vám pomůže administrátor organizace."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Aplikace <xliff:g id="OWNER_APP">%s</xliff:g> tisk zakazuje."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osobní aplikace byly pozastaveny administrátorem"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Klepnutím sem zkontrolujete soulad se zásadami."</string>
<string name="me" msgid="6207584824693813140">"Já"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zařízení Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Již <xliff:g id="NUMBER_0">%1$d</xliff:g>krát jste nesprávně nakreslili své heslo odemknutí. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> dalších neúspěšných pokusech budete požádáni o odemčení telefonu pomocí e-mailového účtu.\n\n Zkuste to znovu za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odebrat"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba v popředí z balíčku <xliff:g id="PACKAGENAME">%1$s</xliff:g>, která byla spuštěna na pozadí, v budoucích sestavenách typu R nebude mít oprávnění ke spuštění při používání. Přejděte na adresu go/r-bg-fgs-restriction a vyplňte zprávu o chybě."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšit hlasitost nad doporučenou úroveň?\n\nDlouhodobý poslech hlasitého zvuku může poškodit sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použít zkratku přístupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti.\n\n Aktuální funkce přístupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkci můžete změnit v Nastavení > Přístupnost."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikace není k dispozici"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikace <xliff:g id="APP_NAME_0">%1$s</xliff:g> momentálně není dostupná. Tato předvolba se spravuje v aplikaci <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Další informace"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Zrušit pozastavení aplikace"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Zapnout pracovní profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vaše pracovní aplikace, oznámení, data a ostatní funkce pracovního účtu budou zapnuty"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnout"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Přepnout rozdělenou obrazovku"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Obrazovka uzamčení"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímek obrazovky"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Nabídka usnadnění přístupu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popisek aplikace <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balíček <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> byl vložen do sekce OMEZENO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobní"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Pracovní"</string>
</resources>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 4ebea89..eb7ad1b 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheden slettes"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administrationsappen kan ikke bruges. Enheden vil nu blive ryddet. \n\nKontakt din organisations administrator, hvis du har spørgsmål."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Udskrivning er deaktiveret af <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"En administrator har suspenderet personlige apps."</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tryk her for at tjekke overholdelsen af politikker."</string>
<string name="me" msgid="6207584824693813140">"Mig"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valgmuligheder for tabletcomputeren"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Valgmuligheder for Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har tegnet dit oplåsningsmønster forkert <xliff:g id="NUMBER_0">%1$d</xliff:g> gange. Efter <xliff:g id="NUMBER_1">%2$d</xliff:g> yderligere mislykkede forsøg til vil du blive bedt om at låse din telefon op ved hjælp af en mailkonto.\n\n Prøv igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjern"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Tjenesten i forgrunden fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der starter i baggrunden, vil i fremtidige R-builds ikke have tilladelse, mens den er i brug. Se go/r-bg-fgs-restriction, og indsend en fejlrapport."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du skrue højere op end det anbefalede lydstyrkeniveau?\n\nDu kan skade hørelsen ved at lytte til meget høj musik over længere tid."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruge genvejen til Hjælpefunktioner?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når genvejen er slået til, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder.\n\n Nuværende hjælpefunktion:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan skifte funktion i Indstillinger > Hjælpefunktioner."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgængelig"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgængelig lige nu. Dette administreres af <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Få flere oplysninger"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Afslut pause for app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Skal arbejdsprofilen slås til?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Dine arbejdsapps, notifikationer, data og andre funktioner til din arbejdsprofil deaktiveres"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå til"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå Opdelt skærm til eller fra"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskærm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menuen Hjælpefunktioner"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Titellinje for <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blevet placeret i samlingen BEGRÆNSET"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Arbejde"</string>
</resources>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 6fa0ac1..6b01af1 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Die Daten auf deinem Gerät werden gelöscht."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Die Admin-App kann nicht verwendet werden. Die Daten auf deinem Gerät werden nun gelöscht.\n\nBitte wende dich bei Fragen an den Administrator deiner Organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drucken wurde von <xliff:g id="OWNER_APP">%s</xliff:g> deaktiviert."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Private Apps wurden von einem Administrator gesperrt"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tippe hier, um die Einhaltung der Richtlinie zu prüfen."</string>
<string name="me" msgid="6207584824693813140">"Eigene"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-Optionen"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-Optionen"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du hast dein Entsperrungsmuster <xliff:g id="NUMBER_0">%1$d</xliff:g>-mal falsch gezeichnet. Nach <xliff:g id="NUMBER_1">%2$d</xliff:g> weiteren erfolglosen Versuchen wirst du aufgefordert, dein Telefon mithilfe eines E-Mail-Kontos zu entsperren.\n\n Versuche es in <xliff:g id="NUMBER_2">%3$d</xliff:g> Sekunden erneut."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Entfernen"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Der Dienst im Vordergrund von <xliff:g id="PACKAGENAME">%1$s</xliff:g>, der im Hintergrund gestartet wurde, hat in zukünftigen R-Builds keine Zugriffsberechtigung mehr während der Nutzung. Siehe dazu go/r-bg-fgs-restriction und reiche einen Fehlerbericht ein."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lautstärke über den Schwellenwert anheben?\n\nWenn du über einen längeren Zeitraum Musik in hoher Lautstärke hörst, kann dies dein Gehör schädigen."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Verknüpfung für Bedienungshilfen verwenden?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten.\n\n Aktuelle Bedienungshilfe:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kannst die Bedienungshilfe unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App nicht verfügbar"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ist momentan nicht verfügbar. Dies wird über die App \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\" verwaltet."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Weitere Informationen"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App-Pausierung aufheben"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Arbeitsprofil aktivieren?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Deine geschäftlichen Apps, Benachrichtigungen, Daten und andere Funktionen des Arbeitsprofils werden aktiviert"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivieren"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"\"Bildschirm teilen\" ein-/ausschalten"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Sperrbildschirm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menü \"Bedienungshilfen\""</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Untertitelleiste von <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> wurde in den BESCHRÄNKT-Bucket gelegt"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Geschäftlich"</string>
</resources>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 81a16f2..61ca692 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Η συσκευή σας θα διαγραφεί"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Δεν είναι δυνατή η χρήση της εφαρμογής διαχειριστή. Η συσκευή σας θα διαγραφεί.\n\nΕάν έχετε ερωτήσεις, επικοινωνήστε με τον διαχειριστή του οργανισμού σας."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Η εκτύπωση απενεργοποιήθηκε από τον χρήστη <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Οι προσωπικές εφαρμογές έχουν τεθεί σε αναστολή από έναν διαχειριστή"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Πατήστε εδώ για να ελέγξετε τη συμμόρφωση πολιτικής."</string>
<string name="me" msgid="6207584824693813140">"Για εμένα"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Επιλογές tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Επιλογές Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Σχεδιάσατε το μοτίβο ξεκλειδώματος εσφαλμένα <xliff:g id="NUMBER_0">%1$d</xliff:g> φορές. Μετά από <xliff:g id="NUMBER_1">%2$d</xliff:g> ανεπιτυχείς προσπάθειες ακόμη, θα σας ζητηθεί να ξεκλειδώσετε το τηλέφωνό σας με τη χρήση ενός λογαριασμού ηλεκτρονικού ταχυδρομείου.\n\n Δοκιμάστε ξανά σε <xliff:g id="NUMBER_2">%3$d</xliff:g> δευτερόλεπτα."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Κατάργηση"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Η υπηρεσία στο προσκήνιο που ξεκίνησε από το παρασκήνιο από το πακέτο <xliff:g id="PACKAGENAME">%1$s</xliff:g> δεν θα έχει άδεια πρόσβασης μόνο κατά τη χρήση σε μελλοντικές εκδόσεις R. Ανατρέξτε στο go/r-bg-fgs-restriction και υποβάλετε αναφορά σφάλματος."</string>
<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="8306239551412868396">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας.\n\n Τρέχουσα λειτουργία προσβασιμότητας:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Μπορείτε να αλλάξετε τη λειτουργία από τις Ρυθμίσεις > Προσβασιμότητα."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Η εφαρμογή δεν είναι διαθέσιμη"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Η εφαρμογή <xliff:g id="APP_NAME_0">%1$s</xliff:g> δεν είναι διαθέσιμη αυτήν τη στιγμή. Η διαχείριση πραγματοποιείται από την εφαρμογή <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Μάθετε περισσότερα"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Κατάργηση παύσης εφαρμογής"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ενεργοποίηση προφίλ εργασίας;"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Οι εφαρμογές, οι ειδοποιήσεις και τα δεδομένα εργασίας σας, καθώς και άλλες λειτουργίες του προφίλ εργασίας, θα ενεργοποιηθούν"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ενεργοποίηση"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Εναλλαγή διαχωρισμού οθόνης"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Οθόνη κλειδώματος"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Στιγμιότυπο οθόνης"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Μενού προσβασιμότητας"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Γραμμή υποτίτλων για την εφαρμογή <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Το πακέτο <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> τοποθετήθηκε στον κάδο ΠΕΡΙΟΡΙΣΜΕΝΗΣ ΠΡΟΣΒΑΣΗΣ."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Προσωπικό"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Εργασία"</string>
</resources>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 87e0c90..15a059f 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
</resources>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index 008ad8a..f3ab25a 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
</resources>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 87e0c90..15a059f 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
</resources>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 87e0c90..15a059f 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organisation\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bug report."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available at the moment. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility menu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
</resources>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index 777107a..871e528 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Your device will be erased"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"The admin app can\'t be used. Your device will now be erased.\n\nIf you have questions, contact your organization\'s admin."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printing disabled by <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personal apps have been suspended by an admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tap here to check policy compliance."</string>
<string name="me" msgid="6207584824693813140">"Me"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet options"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV options"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"You have incorrectly drawn your unlock pattern <xliff:g id="NUMBER_0">%1$d</xliff:g> times. After <xliff:g id="NUMBER_1">%2$d</xliff:g> more unsuccessful attempts, you will be asked to unlock your phone using an email account.\n\n Try again in <xliff:g id="NUMBER_2">%3$d</xliff:g> seconds."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remove"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"The background started foreground service from <xliff:g id="PACKAGENAME">%1$s</xliff:g> will not have while-in-use permission in future R builds. Please see go/r-bg-fgs-restriction and file a bugreport."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Raise volume above recommended level?\n\nListening at high volume for long periods may damage your hearing."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Use Accessibility Shortcut?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature.\n\n Current accessibility feature:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n You can change the feature in Settings > Accessibility."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App isn’t available"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> isn’t available right now. This is managed by <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Learn more"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Unpause app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Turn on work profile?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Your work apps, notifications, data, and other work profile features will be turned on"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Turn on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Toggle Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Accessibility Menu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar of <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> has been put into the RESTRICTED bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Work"</string>
</resources>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 4335c2b..1cb9fde 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Se borrarán los datos del dispositivo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No se puede usar la app de administrador. Ahora se borrará tu dispositivo.\n\nSi tienes preguntas, comunícate con el administrador de tu organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> inhabilitó la impresión."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador suspendió las apps personales"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Presiona aquí para consultar el cumplimiento de políticas."</string>
<string name="me" msgid="6207584824693813140">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones de tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Dibujaste incorrectamente tu patrón de desbloqueo <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Luego de <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos más, se te solicitará que desbloquees tu dispositivo mediante el uso de una cuenta de correo.\n\n Vuelve a intentarlo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminar"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio que pasó del segundo al primer plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permiso durante el uso en las próximas compilaciones de R. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar a un alto volumen durante largos períodos puede dañar tu audición."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Usar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cuando el acceso directo está activado, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Configuración > Accesibilidad."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"La app no está disponible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Reanudar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Se activaran las apps de trabajo, los datos, las notificaciones y otras funciones del perfil de trabajo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear pantalla"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Se colocó <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> en el depósito RESTRICTED"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string>
</resources>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 8d750ca..d8509a3 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Tu dispositivo se borrará"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"No se puede utilizar la aplicación de administración. Se borrarán todos los datos del dispositivo.\n\nSi tienes alguna pregunta, ponte en contacto con el administrador de tu organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ha inhabilitado la impresión."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador ha suspendido las aplicaciones personales"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca aquí para comprobar el cumplimiento de las políticas."</string>
<string name="me" msgid="6207584824693813140">"Yo"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opciones del tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opciones de Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Has fallado <xliff:g id="NUMBER_0">%1$d</xliff:g> veces al dibujar el patrón de desbloqueo. Si fallas otras <xliff:g id="NUMBER_1">%2$d</xliff:g> veces, deberás usar una cuenta de correo electrónico para desbloquear el teléfono.\n\n Inténtalo de nuevo en <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Quitar"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"El servicio en primer plano que se inició en segundo plano en <xliff:g id="PACKAGENAME">%1$s</xliff:g> no tendrá permisos en compilaciones R futuras mientras se estén usando. Ve a go/r-bg-fgs-restriction y envía un informe de errores."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"¿Quieres subir el volumen por encima del nivel recomendado?\n\nEscuchar sonidos fuertes durante mucho tiempo puede dañar los oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"¿Utilizar acceso directo de accesibilidad?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Si el acceso directo está activado, pulsa los dos botones de volumen durante tres segundos para iniciar una función de accesibilidad.\n\n Función de accesibilidad actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puedes cambiar la función en Ajustes > Accesibilidad."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"La aplicación no está disponible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> no está disponible en este momento. Esta opción se administra en <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Más información"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anular pausa de aplicación"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"¿Activar el perfil de trabajo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Tus aplicaciones, notificaciones, datos y otras funciones del perfil de trabajo se activarán"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar o desactivar la pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidad"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> se ha incluido en el grupo de restringidos"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabajo"</string>
</resources>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 7f423e9..2148c09 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Seade kustutatakse"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administraatori rakendust ei saa kasutada. Teie seade tühjendatakse nüüd.\n\nKui teil on küsimusi, võtke ühendust organisatsiooni administraatoriga."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Rakendus <xliff:g id="OWNER_APP">%s</xliff:g> on printimise keelanud."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administraator on isiklikud rakendused peatanud"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Eeskirjade järgimise kontrollimiseks puudutage siin."</string>
<string name="me" msgid="6207584824693813140">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tahvelarvuti valikud"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV valikud"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Joonistasite oma avamismustri <xliff:g id="NUMBER_0">%1$d</xliff:g> korda valesti. Pärast veel <xliff:g id="NUMBER_1">%2$d</xliff:g> ebaõnnestunud katset palutakse teil telefon avada meilikontoga.\n\n Proovige uuesti <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundi pärast."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eemalda"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustal käitatud esiplaanil oleval teenusel paketist <xliff:g id="PACKAGENAME">%1$s</xliff:g> ei ole tulevastes R-järkudes luba „kui kasutuses”. Vaadake saiti go/r-bg-fgs-restriction ja esitage veaaruanne."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Kas suurendada helitugevuse taset üle soovitatud taseme?\n\nPikaajaline valju helitugevusega kuulamine võib kuulmist kahjustada."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Kas kasutada juurdepääsetavuse otseteed?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni.\n\n Praegune juurdepääsetavuse funktsioon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Saate seda funktsiooni muuta valikutega Seaded > Juurdepääsetavus."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Rakendus pole saadaval"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pole praegu saadaval. Seda haldab rakendus <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Lisateave"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Jätka rakendust"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Kas lülitada tööprofiil sisse?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Teie töörakendused, märguanded, andmed ja muud tööprofiili funktsioonid lülitatakse sisse"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Lülita sisse"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Vaheta jagatud ekraanikuva"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukustuskuva"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekraanipilt"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Juurdepääsetavuse menüü"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> pealkirjariba."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on lisatud salve PIIRANGUTEGA"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Isiklik"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Töö"</string>
</resources>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 9d014a3..07bde5e 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Gailuko datuak ezabatu egingo dira"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ezin da erabili administratzeko aplikazioa. Ezabatu egingo da gailuko eduki guztia.\n\nZalantzarik baduzu, jarri erakundeko administratzailearekin harremanetan."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> aplikazioak desgaitu egin du inprimatzeko aukera."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikazio pertsonalak desgaitu egin ditu administratzaile batek"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Sakatu hau gidalerroa gordetzen den egiaztatzeko."</string>
<string name="me" msgid="6207584824693813140">"Ni"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletaren aukerak"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV gailuaren aukerak"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Desblokeatzeko eredua oker marraztu duzu <xliff:g id="NUMBER_0">%1$d</xliff:g> aldiz. Beste <xliff:g id="NUMBER_1">%2$d</xliff:g> aldiz oker marrazten baduzu, telefonoa posta-kontu baten bidez desblokeatzeko eskatuko dizugu.\n\n Saiatu berriro <xliff:g id="NUMBER_2">%3$d</xliff:g> segundo barru."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Kendu"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> webgunearen atzeko planoak hasitako aurreko planoko zerbitzuak ez du izango erabili bitarteko baimenik etorkizuneko R konpilazioetan. Joan go/r-bg-fgs-restriction atalera eta egin akatsaren txostena."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bolumena gomendatutako mailatik gora igo nahi duzu?\n\nMusika bolumen handian eta denbora luzez entzuteak entzumena kalte diezazuke."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erabilerraztasun-lasterbidea erabili nahi duzu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea.\n\n Uneko erabilerraztasun-eginbidea:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Eginbidea aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikazioa ez dago erabilgarri"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ez dago erabilgarri une honetan. Haren erabilgarritasuna <xliff:g id="APP_NAME_1">%2$s</xliff:g> aplikazioak kudeatzen du."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Lortu informazio gehiago"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Kendu pausaldia"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Laneko profila aktibatu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Laneko aplikazioak, jakinarazpenak, datuak eta laneko profileko bestelako eginbideak aktibatuko dira"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktibatu"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktibatu/Desaktibatu pantaila zatitua"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantaila blokeatua"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pantaila-argazkia"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Erabilerraztasun-menua"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> aplikazioko azpitituluen barra."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Murriztuen edukiontzian ezarri da <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Pertsonala"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Lanekoa"</string>
</resources>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 58ce7a7..d65357b 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"دستگاهتان پاک خواهد شد"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"برنامه سرپرست سیستم را نمیتوان استفاده کرد. دستگاه شما در این لحظه پاک میشود.\n\nاگر سؤالی دارید، با سرپرست سیستم سازمانتان تماس بگیرید."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> چاپ کردن را غیرفعال کرده است."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"سرپرستْ برنامههای شخصی را به حالت تعلیق درآورد"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"برای بررسی مطابقت با خطمشی، اینجا ضربه بزنید."</string>
<string name="me" msgid="6207584824693813140">"من"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"گزینههای رایانهٔ لوحی"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"گزینههای Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"شما الگوی بازگشایی قفل خود را <xliff:g id="NUMBER_0">%1$d</xliff:g> بار اشتباه کشیدهاید. پس از <xliff:g id="NUMBER_1">%2$d</xliff:g> تلاش ناموفق، از شما خواسته میشود که با استفاده از یک حساب ایمیل قفل تلفن خود را باز کنید.\n\n لطفاً پس از <xliff:g id="NUMBER_2">%3$d</xliff:g> ثانیه دوباره امتحان کنید."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"حذف"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"سرویس پیشنمای <xliff:g id="PACKAGENAME">%1$s</xliff:g>، که در پسزمینه شروع شده، در ساختهای آتی R اجازهٔ حین استفاده نخواهد داشت. لطفاً به go/r-bg-fgs-restriction بروید و گزارش اشکال ارسال کنید."</string>
<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="8306239551412868396">"وقتی میانبر روشن است، اگر هر دو دکمه صدا را ۳ ثانیه فشار دهید یکی از قابلیتهای دسترسپذیری شروع میشود.\n\n قابلیت دسترسپذیری کنونی:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n میتوانید در «تنظیمات > دسترسپذیری»، قابلیت را تغییر دهید."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"برنامه در دسترس نیست"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> درحالحاضر در دسترس نیست. <xliff:g id="APP_NAME_1">%2$s</xliff:g> آن را مدیریت میکند."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"بیشتر بدانید"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"لغو توقف موقت برنامه"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"نمایه کاری روشن شود؟"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"برنامهها، اعلانها، دادهها و سایر قابلیتهای نمایه کاری شما روشن خواهد شد"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"روشن کردن"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"تغییر وضعیت صفحهٔ دونیمه"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"صفحه قفل"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"عکس صفحهنمایش"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"منوی دسترسپذیری"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"نوار شرح <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> در سطل «محدودشده» قرار گرفت"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"شخصی"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"کاری"</string>
</resources>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index e0f4ed4..17b3d33b 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Laitteen tiedot poistetaan"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Hallintasovellusta ei voi käyttää. Laitteen tiedot pyyhitään.\n\nPyydä ohjeita järjestelmänvalvojaltasi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> on poistanut tulostuksen käytöstä."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Järjestelmänvalvoja on estänyt henkilökohtaisten sovellusten käytön"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Katso käytäntöjen noudattaminen napauttamalla tätä."</string>
<string name="me" msgid="6207584824693813140">"Minä"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet-laitteen asetukset"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ‑vaihtoehdot"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Piirsit lukituksenpoistokuvion väärin <xliff:g id="NUMBER_0">%1$d</xliff:g> kertaa. Jos piirrät kuvion väärin vielä <xliff:g id="NUMBER_1">%2$d</xliff:g> kertaa, sinua pyydetään poistamaan puhelimesi lukitus sähköpostitilin avulla.\n\n Yritä uudelleen <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunnin kuluttua."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Poista"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Taustalla aloitettu etualan palvelu (<xliff:g id="PACKAGENAME">%1$s</xliff:g>) ei ole käytön aikana sallittu R:n tulevissa versioissa. Lue go/r-bg-fgs-restriction ja lähetä virheraportti."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Nostetaanko äänenvoimakkuus suositellun tason yläpuolelle?\n\nPitkäkestoinen kova äänenvoimakkuus saattaa heikentää kuuloa."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Käytetäänkö esteettömyyden pikanäppäintä?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan.\n\n Tällä hetkellä valittu esteettömyystoiminto:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Voit vaihtaa toimintoa valitsemalla Asetukset > Esteettömyys."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Sovellus ei käytettävissä"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ei ole juuri nyt saatavilla. Tästä vastaa <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Lue lisää"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Peru keskeytys"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Otetaanko työprofiili käyttöön?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Työsovellukset, ‑ilmoitukset, ‑tiedot ja muut työprofiiliominaisuudet otetaan käyttöön"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ota käyttöön"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Jaettu näyttö päälle/pois"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lukitusnäyttö"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Kuvakaappaus"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Esteettömyysvalikko"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstityspalkki: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> on nyt rajoitettujen ryhmässä"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Henkilökohtainen"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Työ"</string>
</resources>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 5d99db1..45b8613 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Le contenu de votre appareil sera effacé"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, communiquez avec l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Les applications personnelles ont été suspendues par un administrateur"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Touchez ici pour vérifier la conformité aux politiques."</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Options d\'Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Supprimer"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation pendant l\'utilisation dans les futures versions R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bogue."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au-dessus du niveau recommandé?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité sous Paramètres > Accessibilité."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"L\'application n\'est pas accessible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas accessible pour le moment. Ceci est géré par <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Réactiver l\'application"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Activer le profil professionnel?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, vos notifications, vos données et les autres fonctionnalités de profil professionnel seront activées"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Basculer l\'écran partagé"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Écran de verrouillage"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu d\'accessibilité"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le compartiment RESTREINT"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Bureau"</string>
</resources>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 3f4f3e6..c646aeb 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Les données de votre appareil vont être effacées"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossible d\'utiliser l\'application d\'administration. Les données de votre appareil vont maintenant être effacées.\n\nSi vous avez des questions, contactez l\'administrateur de votre organisation."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impression désactivée par <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Les applications personnelles ont été suspendues par un administrateur"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Appuyez ici pour vérifier que les règles sont respectées."</string>
<string name="me" msgid="6207584824693813140">"Moi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Options de la tablette"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Options Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vous avez dessiné un schéma de déverrouillage incorrect à <xliff:g id="NUMBER_0">%1$d</xliff:g> reprises. Si vous échouez encore <xliff:g id="NUMBER_1">%2$d</xliff:g> fois, vous devrez déverrouiller votre téléphone à l\'aide d\'un compte de messagerie électronique.\n\n Veuillez réessayer dans <xliff:g id="NUMBER_2">%3$d</xliff:g> secondes."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Supprimer"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Le service de premier plan qui a démarré en arrière-plan et provenant de <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne disposera pas de l\'autorisation \"pendant l\'utilisation\" dans les futurs builds R. Veuillez accéder à go/r-bg-fgs-restriction et envoyer un rapport de bug."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Augmenter le volume au dessus du niveau recommandé ?\n\nL\'écoute prolongée à un volume élevé peut endommager vos facultés auditives."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utiliser le raccourci d\'accessibilité ?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité.\n\n Fonctionnalité d\'accessibilité utilisée actuellement :\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Vous pouvez changer de fonctionnalité dans Paramètres > Accessibilité."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Application indisponible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"L\'application <xliff:g id="APP_NAME_0">%1$s</xliff:g> n\'est pas disponible pour le moment. Cette suspension est gérée par l\'application <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"En savoir plus"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Débloquer l\'application"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Activer profil professionnel ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vos applications professionnelles, notifications, données et d\'autres fonctionnalités de votre profil professionnel seront activées"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activer"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activer/Désactiver l\'écran partagé"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Verrouiller l\'écran"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capture d\'écran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu d\'accessibilité"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barre de légende de l\'application <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a été placé dans le bucket RESTRICTED"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personnel"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Professionnel"</string>
</resources>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 2e5052c..2a2d7c4 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Borrarase o teu dispositivo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Non se pode utilizar a aplicación de administración. Borrarase o teu dispositivo.\n\nSe tes preguntas, contacta co administrador da organización."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> desactivou a impresión."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Un administrador suspendeu as aplicacións persoais"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toca aquí para comprobar o cumprimento da política."</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcións da tableta"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcións de Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Debuxaches o padrón de desbloqueo incorrectamente <xliff:g id="NUMBER_0">%1$d</xliff:g> veces. Se realizas <xliff:g id="NUMBER_1">%2$d</xliff:g> intentos incorrectos máis, terás que desbloquear o teléfono a través dunha conta de correo electrónico.\n\n Téntao de novo dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminar"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Nas futuras compilacións R, o servizo en primeiro plano iniciado en segundo plano desde <xliff:g id="PACKAGENAME">%1$s</xliff:g> non terá permiso mentres estea en uso. Consulta go/r-bg-fgs-restriction e presenta un informe de erros."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Queres subir o volume máis do nivel recomendado?\n\nA reprodución de son a un volume elevado durante moito tempo pode provocar danos nos oídos."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Queres utilizar o atallo de accesibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade.\n\n Función de accesibilidade actual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Podes cambiar a función en Configuración > Accesibilidade."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"A aplicación non está dispoñible"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicación <xliff:g id="APP_NAME_0">%1$s</xliff:g> non está dispoñible neste momento. A dispoñibilidade está xestionada por <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Máis información"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Volver activar aplicación"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Activar o perfil de traballo?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Activaranse as túas aplicacións de traballo, as notificacións, os datos e outras funcións do perfil de traballo"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activar/desactivar pantalla dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Pantalla de bloqueo"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de pantalla"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menú de accesibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de subtítulos de <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> incluíuse no grupo RESTRINXIDO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Traballo"</string>
</resources>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 8081ef2..aab09f7 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"તમારું ઉપકરણ કાઢી નાખવામાં આવશે"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"વ્યવસ્થાપક ઍપનો ઉપયોગ કરી શકાશે નહીં. તમારું ઉપકરણ હવે કાઢી નાખવામાં આવશે.\n\nજો તમને પ્રશ્નો હોય, તો તમારી સંસ્થાના વ્યવસ્થાપકનો સંપર્ક કરો."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> દ્વારા પ્રિન્ટ કરવાનું બંધ કરાયું છે."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"વ્યવસ્થાપક દ્વારા વ્યક્તિગત ઍપ સ્થગિત કરવામાં આવી છે"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"નીતિનું પાલન થાય છે કે કેમ તે તપાસવા માટે અહીં ટૅપ કરો."</string>
<string name="me" msgid="6207584824693813140">"હું"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ટેબ્લેટ વિકલ્પો"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TVના વિકલ્પો"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"તમે તમારી અનલૉક પૅટર્ન <xliff:g id="NUMBER_0">%1$d</xliff:g> વખત ખોટી રીતે દોરી. હજી <xliff:g id="NUMBER_1">%2$d</xliff:g> અસફળ પ્રયાસ પછી, તમને ઇમેઇલ એકાઉન્ટનો ઉપયોગ કરીને ફોનને અનલૉક કરવાનું કહેવામાં આવશે.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> સેકન્ડમાં ફરીથી પ્રયાસ કરો."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"દૂર કરો"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"બૅકગ્રાઉન્ડમાં શરૂ થયેલી <xliff:g id="PACKAGENAME">%1$s</xliff:g>ની ફોરગ્રાઉન્ડ સેવા પાસે ભવિષ્યની R બિલ્ડમાં ઉપયોગમાં હોય તે સમયની પરવાનગી હશે નહીં. કૃપા કરીને go/r-bg-fgs-restriction જુઓ અને ભૂલનો અહેવાલ દાખલ કરો."</string>
<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="8306239551412868396">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે.\n\n વર્તમાન ઍક્સેસિબિલિટી સુવિધા:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n તમે સેટિંગ્સ > ઍક્સેસિબિલિટીમાં જઈને આ સુવિધા બદલી શકો છો."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ઍપ ઉપલબ્ધ નથી"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> હમણાં ઉપલબ્ધ નથી. આને <xliff:g id="APP_NAME_1">%2$s</xliff:g> દ્વારા મેનેજ કરવામાં આવે છે."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"વધુ જાણો"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ઍપ ફરી શરૂ કરો"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"કાર્યાલયની પ્રોફાઇલ ચાલુ કરીએ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"તમારી કાર્યાલયની ઍપ, નોટિફિકેશન, ડેટા અને અન્ય કાર્યાલયની પ્રોફાઇલ સુવિધાઓ ચાલુ કરવામાં આવશે"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ચાલુ કરો"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"સ્ક્રીનને વિભાજિત કરવાની ક્રિયા ટૉગલ કરો"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"લૉક સ્ક્રીન"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ઍક્સેસિબિલિટી મેનૂ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>નું કૅપ્શન બાર."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>ને પ્રતિબંધિત સમૂહમાં મૂકવામાં આવ્યું છે"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"વ્યક્તિગત"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"કાર્યાલય"</string>
</resources>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 05efcd8..e1bb060 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"आपके डिवाइस को मिटा दिया जाएगा"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"एडमिन ऐप्लिकेशन का इस्तेमाल नहीं किया जा सकता. आपके डिवाइस पर मौजूद डेटा अब मिटा दिया जाएगा.\n\nअगर आप कुछ पूछना चाहते हैं तो, अपने संगठन के एडमिन से संपर्क करें."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ने प्रिंटिंग सुविधा बंद कर दी है."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"किसी एडमिन ने निजी ऐप्लिकेशन निलंबित कर दिए हैं"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"नीति का पालन किया जा रहा है या नहीं, इसकी जांच करने के लिए यहां टैप करें."</string>
<string name="me" msgid="6207584824693813140">"मैं"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"टैबलेट विकल्प"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV डिवाइस में फ़ोन से जुड़े विकल्प"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"आपने अपने अनलॉक आकार को <xliff:g id="NUMBER_0">%1$d</xliff:g> बार गलत तरीके से आरेखित किया है. <xliff:g id="NUMBER_1">%2$d</xliff:g> और असफल प्रयासों के बाद, आपसे अपने फ़ोन को किसी ईमेल खाते का उपयोग करके अनलॉक करने के लिए कहा जाएगा.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंड में फिर से प्रयास करें."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"निकालें"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>से बैकग्राउंड में शुरू की गई फ़ॉरग्राउंड सेवा के लिए, भविष्य के R बिल्ड में \'इस्तेमाल के समय अनुमति दें\' की सुविधा नहीं होगी. कृपया go/r-bg-fgs-restriction देखें और गड़बड़ी की शिकायत करें."</string>
<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="8306239551412868396">"इस शॉर्टकट के चालू होने पर, दोनों वॉल्यूम बटनों को 3 सेकंड तक दबाने से सुलभता सुविधा शुरू हो जाएगी.\n\n मौजूदा सुलभता सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n आप इस सुविधा को सेटिंग > सुलभता पर जाकर बदल सकते हैं."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"यह ऐप्लिकेशन उपलब्ध नहीं है"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"फ़िलहाल <xliff:g id="APP_NAME_0">%1$s</xliff:g> उपलब्ध नहीं है. इसे <xliff:g id="APP_NAME_1">%2$s</xliff:g> के ज़रिए प्रबंधित किया जाता है."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ज़्यादा जानें"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ऐप्लिकेशन पर लगी रोक हटाएं"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"वर्क प्रोफ़ाइल चालू करें?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"आपके काम से जुड़े ऐप्लिकेशन, सूचनाएं, डेटा और वर्क प्रोफ़ाइल से जुड़ी दूसरी सुविधाएं चालू हो जाएंगी"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करें"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"स्प्लिट स्क्रीन पर टॉगल करें"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करें"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट लें"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"सुलभता मेन्यू"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> का कैप्शन बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> को प्रतिबंधित बकेट में रखा गया है"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"निजी प्रोफ़ाइल"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"वर्क प्रोफ़ाइल"</string>
</resources>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index e4cefe8..3839434 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Uređaj će se izbrisati"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratorska aplikacija ne može se upotrebljavati. Uređaj će se izbrisati.\n\nAko imate pitanja, obratite se administratoru organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Ispis je onemogućila aplikacija <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrator je obustavio osobne aplikacije"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dodirnite ovdje da biste provjerili usklađenost s pravilima."</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcije tabletnog uređaja"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcije Android TV-a"</string>
@@ -1635,8 +1633,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Netočno ste iscrtali obrazac za otključavanje <xliff:g id="NUMBER_0">%1$d</xliff:g> puta. Nakon još ovoliko neuspješnih pokušaja: <xliff:g id="NUMBER_1">%2$d</xliff:g> morat ćete otključati telefon pomoću računa e-pošte.\n\n Pokušajte ponovo za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ukloni"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Usluga u prednjem planu s <xliff:g id="PACKAGENAME">%1$s</xliff:g> pokrenuta u pozadini neće imati dopuštenje tijekom upotrebe u budućim R kompilacijama. Pogledajte go/r-bg-fgs-restriction i pošaljite izvješće o programskoj pogrešci."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Želite li pojačati zvuk iznad preporučene razine?\n\nDugotrajno slušanje glasne glazbe može vam oštetiti sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite li upotrebljavati prečac za pristupačnost?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kada je taj prečac uključen, pritiskom na obje tipke za glasnoću na 3 sekunde pokrenut će se značajka pristupačnosti.\n\n Trenutačna značajka pristupačnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Značajku možete promijeniti u Postavkama > Pristupačnost."</string>
@@ -1884,8 +1881,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacija nije dostupna"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutačno nije dostupna. Ovime upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saznajte više"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekini pauzu aplikacije"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Želite uključiti radni profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Uključit će se vaše radne aplikacije, obavijesti, podaci i druge značajke radnog profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Uključi"</string>
@@ -2041,12 +2037,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Uključite ili isključite podijeljeni zaslon"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaključajte zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snimka zaslona"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Izbornik pristupačnosti"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Traka naslova aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> premješten je u spremnik OGRANIČENO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobno"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Posao"</string>
</resources>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 08cb1c7..fcea1ec 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"A rendszer törölni fogja eszközét"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"A rendszergazdai alkalmazás nem használható. A rendszer most törli az eszközt.\n\nKérdéseivel forduljon szervezete rendszergazdájához."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"A(z) <xliff:g id="OWNER_APP">%s</xliff:g> letiltotta a nyomtatást."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"A személyes alkalmazások adminisztrátori felfüggesztés alá kerültek"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Koppintson ide az irányelvek betartásának ellenőrzéséhez."</string>
<string name="me" msgid="6207584824693813140">"Saját"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Táblagép beállításai"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV beállításai"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g> alkalommal helytelenül rajzolta le a feloldási mintát. További <xliff:g id="NUMBER_1">%2$d</xliff:g> sikertelen kísérlet után egy e-mail fiók használatával kell feloldania a telefonját.\n\n Kérjük, próbálja újra <xliff:g id="NUMBER_2">%3$d</xliff:g> másodperc múlva."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eltávolítás"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"A háttér által indított előtérben futó szolgáltatás (innen: <xliff:g id="PACKAGENAME">%1$s</xliff:g>) nem tartalmaz majd használat közbeni engedélyt a jövőbeli R buildekben. Kérjük, keresse fel a go/r-bg-fgs-restriction webhelyet, és jelentse a hibát."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Az ajánlott szint fölé szeretné emelni a hangerőt?\n\nHa hosszú időn át teszi ki magát nagy hangerőnek, azzal károsíthatja a hallását."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Szeretné használni a Kisegítő lehetőségek billentyűparancsot?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ha be van kapcsolva a billentyűparancs, a két hangerőgomb 3 másodpercig tartó lenyomásával elindíthatja a kisegítő lehetőségek egyik funkcióját.\n\n A kisegítő lehetőségek jelenleg beállított funkciója:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n A funkciót a Beállítások > Kisegítő lehetőségek menüpontban módosíthatja."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Az alkalmazás nem áll rendelkezésre"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"A(z) <xliff:g id="APP_NAME_0">%1$s</xliff:g> alkalmazás jelenleg nem áll rendelkezésre. Ezt a(z) <xliff:g id="APP_NAME_1">%2$s</xliff:g> kezeli."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"További információ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Alkalmazás szüneteltetésének feloldása"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Bekapcsolja a munkaprofilt?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"A munkahelyi alkalmazások, értesítések, adatok és a munkaprofilhoz tartozó egyéb funkciók be lesznek kapcsolva"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bekapcsolás"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Osztott képernyő be- vagy kikapcsolása"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lezárási képernyő"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Képernyőkép"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Kisegítő lehetőségek menü"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"A(z) <xliff:g id="APP_NAME">%1$s</xliff:g> alkalmazás címsora."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"A következő csomag a KORLÁTOZOTT csoportba került: <xliff:g id="PACKAGE_NAME">%1$s</xliff:g>"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Személyes"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Munka"</string>
</resources>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index 9d33f6b..cbd754f 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Ձեր սարքը ջնջվելու է"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Հնարավոր չէ օգտագործել ադմինիստրատորի հավելվածը։ Ձեր սարքից բոլոր տվյալները կջնջվեն։\n\nՀարցեր ունենալու դեպքում դիմեք ձեր կազմակերպության ադմինիստրատորին։"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Տպումն անջատված է <xliff:g id="OWNER_APP">%s</xliff:g> հավելվածի կողմից։"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Անձնական հավելվածները կասեցվել են ադմինիստրատորի կողմից"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Հպեք այստեղ, որպեսզի ստուգեք՝ արդյոք որևէ կանոն չի խախտվել։"</string>
<string name="me" msgid="6207584824693813140">"Իմ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Պլանշետի ընտրանքները"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-ի կարգավորումներ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Դուք <xliff:g id="NUMBER_0">%1$d</xliff:g> անգամ սխալ եք հավաքել ձեր ապակողպման նմուշը: <xliff:g id="NUMBER_1">%2$d</xliff:g> անգամից ավել անհաջող փորձերից հետո ձեզ կառաջարկվի ապակողպել ձեր հեռախոսը` օգտագործելով էլփոստի հաշիվ:\n\n Փորձեք կրկին <xliff:g id="NUMBER_2">%3$d</xliff:g> վայրկյանից:"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Հեռացնել"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ֆոնային ռեժիմում <xliff:g id="PACKAGENAME">%1$s</xliff:g>-ից գործարկված առաջին պլանի ծառայությունը հետագա R կառուցումներում թույլտվություն չի ունենա օգտագործման ընթացքում։ Անցեք go/r-bg-fgs-restriction էջ և հաղորդեք վրիպակի մասին։"</string>
<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="8306239551412868396">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է։\n\n Մատչելիության ակտիվ գործառույթը՝\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Գործառույթը կարող եք փոփոխել՝ անցնելով Կարգավորումներ > Հատուկ գործառույթներ։"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Հավելվածը հասանելի չէ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> հավելվածը հասանելի չէ։ Դրա աշխատանքը սահմանափակում է <xliff:g id="APP_NAME_1">%2$s</xliff:g> հավելվածը։"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Մանրամասն"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Չեղարկել դադարեցումը"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Միացնե՞լ աշխատանքային պրոֆիլը"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Ձեր աշխատանքային հավելվածները, ծանուցումները, տվյալները և աշխատանքային պրոֆիլի մյուս գործառույթները կմիանան"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Միացնել"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Միացնել/անջատել էկրանի տրոհումը"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Կողպէկրան"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Սքրինշոթ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Հատուկ գործառույթների ընտրացանկ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածի ենթագրերի գոտին։"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> փաթեթը գցվեց ՍԱՀՄԱՆԱՓԱԿՎԱԾ զամբյուղի մեջ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Անձնական"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Աշխատանքային"</string>
</resources>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4813610..f1a94ff 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Perangkat akan dihapus"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikasi admin tidak dapat digunakan. Perangkat Anda kini akan dihapus.\n\nJika ada pertanyaan, hubungi admin organisasi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Fitur pencetakan dinonaktifkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikasi pribadi telah ditangguhkan oleh admin"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ketuk di sini untuk memeriksa kepatuhan kebijakan."</string>
<string name="me" msgid="6207584824693813140">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsi tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsi Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Anda telah <xliff:g id="NUMBER_0">%1$d</xliff:g> kali salah menggambar pola pembuka kunci. Setelah <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi upaya gagal, Anda akan diminta membuka kunci ponsel menggunakan akun email.\n\nCoba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> detik."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Hapus"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Layanan latar depan yang dimulai oleh latar belakang dari <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan memiliki izin saat-sedang-digunakan pada build R masa mendatang Lihat go/r-bg-fgs-restriction dan kirim laporan bug."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Mengeraskan volume di atas tingkat yang disarankan?\n\nMendengarkan dengan volume keras dalam waktu yang lama dapat merusak pendengaran Anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Aksesibilitas?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas.\n\n Fitur aksesibilitas saat ini:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda dapat mengubah fitur di Setelan > Aksesibilitas."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikasi tidak tersedia"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> saat ini tidak tersedia. Aplikasi ini dikelola oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Pelajari lebih lanjut"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Batalkan jeda aplikasi"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Aktifkan profil kerja?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikasi kerja, notifikasi, data, dan fitur profil kerja lainnya akan diaktifkan"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktifkan"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktifkan/Nonaktifkan Layar Terpisah"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Layar Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Aksesibilitas"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Kolom teks <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah dimasukkan ke dalam bucket DIBATASI"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Pribadi"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string>
</resources>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index bf3fe87..b4cb76d3 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Tækið verður hreinsað"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Ekki er hægt að nota stjórnunarforritið. Tækinu verður eytt.\n\nEf spurningar vakna skaltu hafa samband við kerfisstjóra fyrirtækisins."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> lokaði á prentun."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Stjórnandi hefur lokað á persónuleg forrit"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ýttu hér til að sjá reglufylgni."</string>
<string name="me" msgid="6207584824693813140">"Ég"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Valkostir spjaldtölvu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Valkostir Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Þú hefur teiknað rangt opnunarmynstur <xliff:g id="NUMBER_0">%1$d</xliff:g> sinnum. Eftir <xliff:g id="NUMBER_1">%2$d</xliff:g> árangurslausar tilraunir í viðbót verður þú beðin(n) um að opna símann með tölvupóstreikningi.\n\n Reyndu aftur eftir <xliff:g id="NUMBER_2">%3$d</xliff:g> sekúndur."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjarlægja"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnsþjónusta frá <xliff:g id="PACKAGENAME">%1$s</xliff:g> sem er ræst úr bakgrunni mun ekki hafa heimild við notkun í framtíðarútgáfum R. Farðu á go/r-bg-fgs-restriction og gefðu villuskýrslu."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Hækka hljóðstyrk umfram ráðlagðan styrk?\n\nEf hlustað er á háum hljóðstyrk í langan tíma kann það að skaða heyrnina."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Viltu nota aðgengisflýtileið?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur.\n\n Virkur aðgengiseiginleiki:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Hægt er að skipta um eiginleika í Stillingar > Aðgengi."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Forritið er ekki í boði"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ekki í boði eins og er. Þessu er stjórnað með <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Nánari upplýsingar"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Halda áfram að nota"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Kveikja á vinnusniði?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Kveikt verður á vinnuforritum, tilkynningum, gögnum og öðrum eiginleikum vinnusniðsins"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Kveikja"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Breyta skjáskiptingu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lásskjár"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjámynd"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Aðgengisvalmynd"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Skjátextastika <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> var sett í flokkinn TAKMARKAÐ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Persónulegt"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Vinna"</string>
</resources>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 72ca138..23a62a8 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Il dispositivo verrà resettato"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Impossibile usare l\'app di amministrazione. Il dispositivo verrà resettato.\n\nPer eventuali domande, contatta l\'amministratore della tua organizzazione."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Stampa disattivata da <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Le app personali sono state sospese da un amministratore"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tocca qui per controllare il rispetto delle norme."</string>
<string name="me" msgid="6207584824693813140">"Io"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opzioni tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opzioni Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g> tentativi errati di inserimento della sequenza di sblocco. Dopo altri <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativi falliti, ti verrà chiesto di sbloccare il telefono con un account email.\n\n Riprova tra <xliff:g id="NUMBER_2">%3$d</xliff:g> secondi."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Rimuovi"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Il servizio in primo piano avviato in background da <xliff:g id="PACKAGENAME">%1$s</xliff:g> non avrà l\'autorizzazione \"durante l\'uso\" nelle future build R. Visita la pagina go/r-bg-fgs-restriction e invia una segnalazione di bug."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vuoi aumentare il volume oltre il livello consigliato?\n\nL\'ascolto ad alto volume per lunghi periodi di tempo potrebbe danneggiare l\'udito."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usare la scorciatoia Accessibilità?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità.\n\n Funzione di accessibilità corrente:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puoi cambiare la funzione in Impostazioni > Accessibilità."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App non disponibile"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> non è al momento disponibile. Viene gestita tramite <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Ulteriori informazioni"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Riattiva app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Attivare il profilo di lavoro?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Le tue app di lavoro, le notifiche, i dati e altri elementi del profilo di lavoro saranno attivati."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Attiva"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Attiva/disattiva schermo diviso"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Schermata di blocco"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Accessibilità"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra del titolo di <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> è stato inserito nel bucket RESTRICTED"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personale"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string>
</resources>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 9c8d0a3..4319aa8 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"תתבצע מחיקה של המכשיר"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"לא ניתן להשתמש באפליקציה של מנהל המערכת.\n\nאם יש לך שאלות, יש ליצור קשר עם מנהל המערכת של הארגון."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ההדפסה הושבתה על ידי <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"אפליקציות אישיות הושעו על ידי מנהל מערכת"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"יש להקיש כאן כדי לבדוק תאימות למדיניות."</string>
<string name="me" msgid="6207584824693813140">"אני"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"אפשרויות טאבלט"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"אפשרויות Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"שרטטת את קו ביטול הנעילה באופן שגוי <xliff:g id="NUMBER_0">%1$d</xliff:g> פעמים. לאחר <xliff:g id="NUMBER_1">%2$d</xliff:g> ניסיונות כושלים נוספים, תתבקש לבטל את נעילת הטלפון באמצעות חשבון אימייל.\n\nנסה שוב בעוד <xliff:g id="NUMBER_2">%3$d</xliff:g> שניות."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"הסר"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"לשירות שפועל בחזית מ-<xliff:g id="PACKAGENAME">%1$s</xliff:g> שהחל ברקע לא תהיה הרשאת while-in-use בגרסאות R build בעתיד. יש לעיין בכתובת go/r-bg-fgs-restriction ולהגיש דוח על באג."</string>
<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="8306239551412868396">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת השמע למשך שלוש שניות מפעילה את תכונת הנגישות.\n\n תכונת הנגישות המוגדרת כרגע:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n אפשר לשנות את התכונה בקטע \'הגדרות ונגישות\'."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"האפליקציה אינה זמינה"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"האפליקציה <xliff:g id="APP_NAME_0">%1$s</xliff:g> לא זמינה כרגע. את הזמינות שלה אפשר לנהל באפליקציה <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"מידע נוסף"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ביטול ההשהיה של האפליקציה"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"להפעיל את פרופיל העבודה?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"אפליקציות העבודה, התראות, נתונים ותכונות נוספות של פרופיל העבודה יופעלו"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"הפעל"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"החלפת מצב של מסך מפוצל"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"מסך הנעילה"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"צילום מסך"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"תפריט נגישות"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"סרגל כיתוב של <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> התווספה לקטגוריה \'מוגבל\'"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"אישי"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"עבודה"</string>
</resources>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 529d011..481af76 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"デバイスのデータが消去されます"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"管理アプリを使用できません。デバイスのデータはこれから消去されます。\n\nご不明な点がある場合は、組織の管理者にお問い合わせください。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」により印刷は無効にされています。"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"個人用アプリは管理者によって停止されています"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ポリシー コンプライアンスを確認するにはここをタップしてください。"</string>
<string name="me" msgid="6207584824693813140">"自分"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"タブレットオプション"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV のオプション"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ロック解除パターンの入力を<xliff:g id="NUMBER_0">%1$d</xliff:g>回間違えました。あと<xliff:g id="NUMBER_1">%2$d</xliff:g>回間違えると、モバイルデバイスのロック解除にメールアカウントが必要になります。\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g>秒後にもう一度お試しください。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"削除"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"今後の R ビルドでは、<xliff:g id="PACKAGENAME">%1$s</xliff:g> からバックグラウンドで開始されるフォアグラウンド サービスに「使用中のみ許可」の権限がありません。go/r-bg-fgs-restriction を確認し、バグレポートを提出してください。"</string>
<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="8306239551412868396">"ショートカットが ON の場合、両方の音量ボタンを 3 秒間押し続けるとユーザー補助機能が起動します。\n\n現在のユーザー補助機能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nユーザー補助機能は [設定] > [ユーザー補助] で変更できます。"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"このアプリは使用できません"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"現在、<xliff:g id="APP_NAME_0">%1$s</xliff:g> は使用できません。このアプリの使用は [<xliff:g id="APP_NAME_1">%2$s</xliff:g>] で管理されています。"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"詳細"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"アプリの一時停止を解除"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"仕事用プロファイルの有効化"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"仕事用のアプリ、通知、データなど、仕事用プロファイルの機能が ON になります"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ON にする"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"分割画面の切り替え"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ロック画面"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"スクリーンショット"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ユーザー補助機能メニュー"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> のキャプション バーです。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> は RESTRICTED バケットに移動しました。"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"個人用"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"仕事用"</string>
</resources>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 3f97338..c2c28e5 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"თქვენი მოწყობილობა წაიშლება"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ადმინისტრატორის აპის გამოყენება ვერ მოხერხდება. თქვენი მოწყობილობა ახლა ამოიშლება.\n\nთუ შეკითხვები გაქვთ, დაუკავშირდით თქვენი ორგანიზაციის ადმინისტრატორს."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ბეჭდვა გათიშულია <xliff:g id="OWNER_APP">%s</xliff:g>-ის მიერ."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"პირადი აპები შეჩერებულია ადმინისტრატორის მიერ"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"შეეხეთ აქ წესებთან შესაბამისობის შესამოწმებლად."</string>
<string name="me" msgid="6207584824693813140">"მე"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ტაბლეტის პარამეტრები"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ვარიანტები"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"თქვენ არასწორად დახატეთ თქვენი განბლოკვის ნიმუში <xliff:g id="NUMBER_0">%1$d</xliff:g>-ჯერ. კიდევ <xliff:g id="NUMBER_1">%2$d</xliff:g> წარუმატებელი ცდის შემდეგ, დაგჭირდებათ თქვენი ტელეფონის განბლოკვა ელფოსტის ანგარიშის გამოყენებით.\n\n ხელახლა სცადეთ <xliff:g id="NUMBER_2">%3$d</xliff:g> წამში."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ამოშლა"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-ის ფონურად დაწყებულ წინა პლანის სერვისს მომავალ R build-ებში გამოყენების პროცესში წვდომის ნებართვა არ ექნება. გთხოვთ, იხილოთ go/r-bg-fgs-restriction და გამოგზავნოთ ხარვეზის ანგარიში."</string>
<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="8306239551412868396">"მალსახმობის ჩართვის შემთხვევაში, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება.\n\n მარტივი წვდომის ამჟამინდელი ფუნქციაა:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ამ ფუნქციის შეცვლა შეგიძლიათ აქ: პარამეტრები > მარტივი წვდომა."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"აპი მიუწვდომელია"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ამჟამად მიუწვდომელია. ის იმართება <xliff:g id="APP_NAME_1">%2$s</xliff:g>-ის მიერ."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"შეიტყვეთ მეტი"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"აპის დაპაუზების გაუქმება"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ჩაირთოს სამსახურის პროფილი?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"თქვენი სამსახურის აპები, შეტყობინებები, მონაცემები და სამსახურის პროფილის ყველა სხვა ფუნქცია ჩაირთვება"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ჩართვა"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"გაყოფილი ეკრანის გადართვა"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ჩაკეტილი ეკრანი"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ეკრანის ანაბეჭდი"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"მარტივი წვდომის მენიუ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის სუბტიტრების ზოლი."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> მოთავსდა კალათაში „შეზღუდული“"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"პირადი"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"სამსახური"</string>
</resources>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index bccd3f4b..7cb0512 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Құрылғыңыздағы деректер өшіріледі"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Әкімші қолданбасын пайдалану мүмкін емес. Қазір құрылғыдағы деректер өшіріледі\n\nСұрақтарыңыз болса, ұйым әкімшісіне хабарласыңыз."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып шығаруды <xliff:g id="OWNER_APP">%s</xliff:g> өшірді."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Әкімші жеке қолданбаларды уақытша тоқтатты"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Саясат талаптарының сай келуін тексеру үшін осы жерді түртіңіз."</string>
<string name="me" msgid="6207584824693813140">"Мен"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет опциялары"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV опциялары"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Бекітпені ашу кескінін <xliff:g id="NUMBER_0">%1$d</xliff:g> рет қате сыздыңыз. <xliff:g id="NUMBER_1">%2$d</xliff:g> сәтсіз әрекеттен кейін телефоныңызды есептік жазба арқылы ашу өтінішін аласыз. \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундтан кейін қайта әрекеттеніңіз."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Алып тастау"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондық режимде іске қосылған <xliff:g id="PACKAGENAME">%1$s</xliff:g> белсенді пакетінің алдағы R құрамаларында \"Пайдаланғанда ғана рұқсат ету\" рұқсаты болмайды. go/r-bg-fgs-restriction бетіне өтіп, қате туралы есеп жіберіңіз."</string>
<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="8306239551412868396">"Бұл төте жол қосулы кезде дыбыс деңгейі түймелерінің екеуін де 3 секунд бойы басқанда арнайы мүмкіндік іске қосылады.\n\n Ағымдағы арнайы мүмкіндік:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Бұл мүмкіндікті \"Параметрлер\" > \"Арнайы мүмкіндіктер\" тармағында өзгертуге болады."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Қолданба қолжетімді емес"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> дәл қазір қолжетімді емес. Ол <xliff:g id="APP_NAME_1">%2$s</xliff:g> арқылы басқарылады."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Толығырақ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Қолданбаны қайта қосу"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Жұмыс профилі қосылсын ба?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Жұмыс қолданбалары, хабарландырулар, деректер және басқа да жұмыс профильдерінің мүмкіндіктері қосылады"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Қосу"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлу мүмкіндігін қосу/өшіру"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Құлып экраны"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Арнайы мүмкіндіктер мәзірі"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасының жазу жолағы."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ШЕКТЕЛГЕН себетке салынды."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Жұмыс"</string>
</resources>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index ee451e9..e0267d3 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ឧបករណ៍របស់អ្នកនឹងត្រូវបានលុប"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"មិនអាចប្រើកម្មវិធីអ្នកគ្រប់គ្រងបានទេ។ ឧបករណ៍របស់អ្នកនឹងលុបឥឡូវនេះ។\n\nប្រសិនបើអ្នកមានសំណួរផ្សេងៗ សូមទាក់ទងទៅអ្នកគ្រប់គ្រងស្ថាប័នរបស់អ្នក។"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ការបោះពុម្ពត្រូវបានបិទដោយ <xliff:g id="OWNER_APP">%s</xliff:g> ។"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"អ្នកគ្រប់គ្រងបានផ្អាកកម្មវិធីផ្ទាល់ខ្លួន"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ចុចត្រង់នេះ ដើម្បីពិនិត្យមើលការអនុលោមតាមគោលការណ៍។"</string>
<string name="me" msgid="6207584824693813140">"ខ្ញុំ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ជម្រើសកុំព្យូទ័របន្ទះ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ជម្រើស Android TV"</string>
@@ -1615,8 +1613,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"អ្នកបានគូរលំនាំដោះសោរបស់អ្នកមិនត្រឹមត្រូវចំនួន <xliff:g id="NUMBER_0">%1$d</xliff:g> ដង។ បន្ទាប់ពីការព្យាយាមមិនជោគជ័យច្រើនជាង <xliff:g id="NUMBER_1">%2$d</xliff:g> ដង អ្នកនឹងត្រូវបានស្នើឲ្យដោះសោទូរស័ព្ទរបស់អ្នកដោយប្រើគណនីអ៊ីមែល។\n\n ព្យាយាមម្ដងទៀតក្នុងរយៈពេល <xliff:g id="NUMBER_2">%3$d</xliff:g> វិនាទី។"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"លុបចេញ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"សេវាកម្មផ្ទៃខាងមុខដែលចាប់ផ្ដើមដោយផ្ទៃខាងក្រោយពី <xliff:g id="PACKAGENAME">%1$s</xliff:g> នឹងមិនមានការអនុញ្ញាតខណៈពេលកំពុងប្រើប្រាស់ទេ នៅក្នុងកំណែបង្កើត R នៅពេលអនាគត។ សូមមើល go/r-bg-fgs-restriction និងផ្ញើរបាយការណ៍អំពីបញ្ហា។"</string>
<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="8306239551412868396">"នៅពេលផ្លូវកាត់នេះបើក ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីរឲ្យជាប់រយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយស្រួល។\n\n មុខងារភាពងាយស្រួលបច្ចុប្បន្ន៖\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n អ្នកអាចផ្លាស់ប្តូរមុខងារនេះបាននៅក្នុងការ កំណត់ > ភាពងាយស្រួល។"</string>
@@ -1854,8 +1851,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"កម្មវិធីមិនអាចប្រើបានទេ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> មិនអាចប្រើបានទេនៅពេលនេះ។ វាស្ថិតក្រោមការគ្រប់គ្រងរបស់ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ។"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ស្វែងយល់បន្ថែម"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ឈប់ផ្អាកកម្មវិធី"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"បើកកម្រងព័ត៌មានការងារ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"កម្មវិធីការងារ ការជូនដំណឹង ទិន្នន័យ និងមុខងារកម្រងព័ត៌មានការងារផ្សេងទៀតរបស់អ្នកនឹងត្រូវបានបើក"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"បើក"</string>
@@ -2009,12 +2005,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"បិទ/បើកមុខងារបំបែកអេក្រង់"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"អេក្រង់ចាក់សោ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"រូបថតអេក្រង់"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ម៉ឺនុយភាពងាយស្រួល"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"របារពណ៌នាអំពី <xliff:g id="APP_NAME">%1$s</xliff:g>។"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ត្រូវបានដាក់ទៅក្នុងធុងដែលបានដាក់កំហិត"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ផ្ទាល់ខ្លួន"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ការងារ"</string>
</resources>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 7528284..4a2bc72 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ನಿಮ್ಮ ಸಾಧನವನ್ನು ಅಳಿಸಲಾಗುತ್ತದೆ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ನಿರ್ವಹಣೆ ಅಪ್ಲಿಕೇಶನ್ ಬಳಸಲು ಸಾಧ್ಯವಿಲ್ಲ. ನಿಮ್ಮ ಸಾಧನವನ್ನು ಇದೀಗ ಅಳಿಸಲಾಗುತ್ತದೆ.\n\nನಿಮ್ಮಲ್ಲಿ ಪ್ರಶ್ನೆಗಳಿದ್ದರೆ, ನಿಮ್ಮ ಸಂಸ್ಥೆಯ ನಿರ್ವಾಹಕರನ್ನು ಸಂಪರ್ಕಿಸಿ."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ಮೂಲಕ ಪ್ರಿಂಟಿಂಗ್ ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ವೈಯಕ್ತಿಕ ಆ್ಯಪ್ಗಳನ್ನು ನಿರ್ವಾಹಕರು ಅಮಾನತುಗೊಳಿಸಿದ್ದಾರೆ"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ಕಾರ್ಯನೀತಿ ಅನುಸರಣೆಯನ್ನು ಪರಿಶೀಲಿಸಲು ಇಲ್ಲಿ ಟ್ಯಾಪ್ ಮಾಡಿ."</string>
<string name="me" msgid="6207584824693813140">"ನಾನು"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ಟ್ಯಾಬ್ಲೆಟ್ ಆಯ್ಕೆಗಳು"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ಆಯ್ಕೆಗಳು"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ನಿಮ್ಮ ಅನ್ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಅನ್ನು ನೀವು <xliff:g id="NUMBER_0">%1$d</xliff:g> ಬಾರಿ ತಪ್ಪಾಗಿ ಡ್ರಾ ಮಾಡಿರುವಿರಿ. <xliff:g id="NUMBER_1">%2$d</xliff:g> ಹೆಚ್ಚಿನ ವಿಫಲ ಪ್ರಯತ್ನಗಳ ಬಳಿಕ, ನಿಮ್ಮ ಇಮೇಲ್ ಖಾತೆಯನ್ನು ಬಳಸಿಕೊಂಡು ನಿಮ್ಮ ಫೋನ್ ಅನ್ಲಾಕ್ ಮಾಡುವಂತೆ ನಿಮ್ಮಲ್ಲಿ ಕೇಳಿಕೊಳ್ಳಲಾಗುತ್ತದೆ.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ಸೆಕೆಂಡುಗಳಲ್ಲಿ ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ತೆಗೆದುಹಾಕು"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ನಿಂದ ಹಿನ್ನೆಲೆಯಲ್ಲಿ ಪ್ರಾರಂಭಿಸಲಾದ ಮುನ್ನೆಲೆ ಸೇವೆ ಭವಿಷ್ಯದ R ಬಿಲ್ಡ್ಗಳಿಂದ ಬಳಕೆಯಲ್ಲಿರುವಾಗ ಅನುಮತಿಯನ್ನು ಪಡೆಯುವುದಿಲ್ಲ. go/r-bg-fgs-restriction ಅನ್ನು ನೋಡಿ ಮತ್ತು ದೋಷವರದಿಯನ್ನು ಫೈಲ್ ಮಾಡಿ."</string>
<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="8306239551412868396">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ ಆನ್ ಮಾಡಲು, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು ನೀವು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಬೇಕು.\n\nಪ್ರಸ್ತುತ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯ: \n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಪ್ರವೇಶಿಸುವಿಕೆಯಲ್ಲಿ ನೀವು ವೈಶಿಷ್ಟ್ಯವನ್ನು ಬದಲಾಯಿಸಬಹುದು."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ಅಪ್ಲಿಕೇಶನ್ ಲಭ್ಯವಿಲ್ಲ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ಅಪ್ಲಿಕೇಶನ್ ಸದ್ಯಕ್ಕೆ ಲಭ್ಯವಿಲ್ಲ. ಇದನ್ನು <xliff:g id="APP_NAME_1">%2$s</xliff:g> ನಲ್ಲಿ ನಿರ್ವಹಿಸಲಾಗುತ್ತಿದೆ."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ಇನ್ನಷ್ಟು ತಿಳಿಯಿರಿ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ಆ್ಯಪ್ ವಿರಾಮ ನಿಲ್ಲಿಸಿ"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ ಆನ್ ಮಾಡುವುದೇ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ನಿಮ್ಮ ಕೆಲಸದ ಅಪ್ಲಿಕೇಶನ್ಗಳು, ಅಧಿಸೂಚನೆಗಳು, ಡೇಟಾ ಮತ್ತು ಉದ್ಯೋಗ ಪ್ರೊಫೈಲ್ನ ಇತರ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ಆನ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ಆನ್ ಮಾಡಿ"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ಸ್ಪ್ಲಿಟ್-ಸ್ಕ್ರೀನ್ ಟಾಗಲ್ ಮಾಡಿ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ಲಾಕ್ ಸ್ಕ್ರೀನ್"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ಪ್ರವೇಶಿಸುವಿಕೆ ಮೆನು"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಆ್ಯಪ್ನ ಶೀರ್ಷಿಕೆಯ ಪಟ್ಟಿ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ಅನ್ನು ನಿರ್ಬಂಧಿತ ಬಕೆಟ್ಗೆ ಹಾಕಲಾಗಿದೆ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ವೈಯಕ್ತಿಕ"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ಕೆಲಸ"</string>
</resources>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index d5b4507..0ac7a14 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"기기가 삭제됩니다."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"관리자 앱을 사용할 수 없습니다. 곧 기기가 삭제됩니다.\n\n궁금한 점이 있으면 조직의 관리자에게 문의하세요."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g>에 의해 사용 중지되었습니다."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"관리자가 개인 앱을 정지함"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"정책 준수를 확인하려면 여기를 탭하세요."</string>
<string name="me" msgid="6207584824693813140">"나"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"태블릿 옵션"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 옵션"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"잠금해제 패턴을 <xliff:g id="NUMBER_0">%1$d</xliff:g>회 잘못 그렸습니다. <xliff:g id="NUMBER_1">%2$d</xliff:g>회 더 실패하면 이메일 계정을 사용하여 휴대전화를 잠금해제해야 합니다.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g>초 후에 다시 시도해 주세요."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"삭제"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"향후 R 빌드에서는 백그라운드에서 시작된 <xliff:g id="PACKAGENAME">%1$s</xliff:g>의 포그라운드 서비스에 더 이상 사용 중인 상태에서 필요한 권한이 부여되지 않습니다. go/r-bg-fgs-restriction 페이지에서 버그 신고를 제출하세요."</string>
<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="8306239551412868396">"단축키가 사용 설정된 경우 두 개의 볼륨 버튼을 3초간 누르면 접근성 기능이 시작됩니다.\n\n 현재 접근성 기능:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n \'설정 > 접근성\'에서 기능을 변경할 수 있습니다."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"앱을 사용할 수 없음"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>은(는) 현재 사용할 수 없습니다. <xliff:g id="APP_NAME_1">%2$s</xliff:g>에서 관리하는 앱입니다."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"자세히 알아보기"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"앱 일시중지 해제"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"직장 프로필을 사용 설정하시겠어요?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"업무용 앱, 알림, 데이터 및 기타 직장 프로필 기능이 사용 설정됩니다."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"사용 설정"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"화면 분할 모드 전환"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"잠금 화면"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"스크린샷"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"접근성 메뉴"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>의 자막 표시줄입니다."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 항목이 RESTRICTED 버킷으로 이동함"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"개인"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"직장"</string>
</resources>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 533e0b8..88e36ff 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Түзмөгүңүз тазаланат"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Түзмөктү башкаруучу колдонмо жараксыз. Түзмөгүңүз азыр тазаланат.\n\nСуроолоруңуз болсо, ишканаңыздын администраторуна кайрылыңыз."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Басып чыгаруу <xliff:g id="OWNER_APP">%s</xliff:g> тарабынан өчүрүлдү."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Жеке колдонмолорду администратор убактылуу токтотту"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Саясатка ылайыктуулугун текшерүү үчүн бул жерди таптап коюңуз"</string>
<string name="me" msgid="6207584824693813140">"Мен"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Планшет мүмкүнчүлүктөрү"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV параметрлери"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Графикалык ачкычты <xliff:g id="NUMBER_0">%1$d</xliff:g> жолу туура эмес көрсөттүңүз. <xliff:g id="NUMBER_1">%2$d</xliff:g> жолу туура эмес көрсөтүлгөндөн кийин, телефондун кулпусун ачуу үчүн Google аккаунтуңузга кирүүгө туура келет.\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> секундадан кийин кайталап көрсөңүз болот."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Алып салуу"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Фондогу <xliff:g id="PACKAGENAME">%1$s</xliff:g> кызматы активдүү режимде иштеп баштап, кийинки R курамаларында колдонуу учурунда уруксаты болбойт. Төмөнкү бөлүмгө өтүп, мүчүлүштүк тууралуу кабарды тапшырыңыз: go/r-bg-fgs-restriction."</string>
<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="8306239551412868396">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн, ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең үч секунддай кое бербей басып туруңуз.\n\n Учурдагы атайын мүмкүнчүлүктөрдүн жөндөөлөрү:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nЖөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнөн өзгөртө аласыз."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Колдонмо жеткиликсиз"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> колдонмосу учурда жеткиликсиз. Анын жеткиликтүүлүгү <xliff:g id="APP_NAME_1">%2$s</xliff:g> тарабынан башкарылат."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Кеңири маалымат"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Колдонмону иштетүү"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Жумуш профили күйгүзүлсүнбү?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Жумуш колдонмолоруңуз, эскертмелериңиз, дайын-даректериңиз жана жумуш профилинин башка функциялары күйгүзүлөт."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Күйгүзүү"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Экранды бөлүүнү күйгүзүү же өчүрүү"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Кулпуланган экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Атайын мүмкүнчүлүктөр менюсу"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> колдонмосунун маалымат тилкеси."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ЧЕКТЕЛГЕН чакага коюлган"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Жеке"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Жумуш"</string>
</resources>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index 7a3e85e..63b87ac 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ອຸປະກອນຂອງທ່ານຈະຖືກລຶບ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ບໍ່ສາມາດໃຊ້ແອັບຜູ້ເບິ່ງແຍງລະບົບໄດ້. ອຸປະກອນຂອງທ່ານຈະຖືກລຶບຂໍ້ມູນໃນຕອນນີ້.\n\nຫາກທ່ານມີຄຳຖາມ, ໃຫ້ຕິດຕໍ່ຜູ້ເບິ່ງແຍງລະບົບອົງກອນຂອງທ່ານ."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ການພິມຖືກປິດໄວ້ໂດຍ <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ແອັບສ່ວນຕົວຖືກລະງັບໄວ້ໂດຍຜູ້ເບິ່ງແຍງ"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ແຕະບ່ອນນີ້ເພື່ອກວດສອບການປະຕິບັດຕາມນະໂຍບາຍ."</string>
<string name="me" msgid="6207584824693813140">"ຂ້າພະເຈົ້າ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ໂຕເລືອກແທັບເລັດ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ຕົວເລືອກ Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ທ່ານແຕ້ມຮູບແບບປົດລັອກຂອງທ່ານຜິດ <xliff:g id="NUMBER_0">%1$d</xliff:g> ເທື່ອແລ້ວ. ຫຼັງຈາກຄວາມພະຍາຍາມອີກ <xliff:g id="NUMBER_1">%2$d</xliff:g> ເທື່ອ ທ່ານຈະຖືກຖາມໃຫ້ປົດລັອກໂທລະສັບຂອງທ່ານດ້ວຍບັນຊີອີເມວ.\n\n ລອງໃໝ່ອີກຄັ້ງໃນ <xliff:g id="NUMBER_2">%3$d</xliff:g> ວິນາທີ."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ລຶບອອກ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ບໍລິການພື້ນໜ້າທີ່ເລີ່ມຕົ້ນຈາກພື້ນຫຼັງຈາກ <xliff:g id="PACKAGENAME">%1$s</xliff:g> ຈະບໍ່ມີສິດອະນຸຍາດໃນຂະນະທີ່ໃຊ້ໃນ R builds ໃນອະນາຄົດ. ກະລຸນາອ່ານ go/r-bg-fgs-restriction ແລະ ລາຍງານຂໍ້ຜິດພາດ."</string>
<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="8306239551412868396">"ເມື່ອເປີດໃຊ້ປຸ່ມລັດແລ້ວ, ໃຫ້ກົດປຸ່ມສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີເພື່ອເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ.\n\n ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງປັດຈຸບັນ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ທ່ານສາມາດປ່ຽນຄຸນສົມບັດໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ບໍ່ສາມາດໃຊ້ແອັບໄດ້"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ບໍ່ສາມາດໃຊ້ໄດ້ໃນຕອນນີ້. ມັນຖືກຈັດການໂດຍ <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ສຶກສາເພີ່ມເຕີມ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ຍົກເລີກການຢຸດແອັບຊົ່ວຄາວ"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ເປີດໃຊ້ໂປຣໄຟລ໌ບ່ອນເຮັດວຽກບໍ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ແອັບວຽກຂອງທ່ານ, ການແຈ້ງເຕືອນ, ຂໍ້ມູນ ແລະ ຄຸນສົມບັດໂປຣໄຟລ໌ວຽກຈະຖືກເປີດໃຊ້"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ເປີດ"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ເປີດ/ປິດການແບ່ງໜ້າຈໍ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ໜ້າຈໍລັອກ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ຮູບໜ້າຈໍ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ເມນູການຊ່ວຍເຂົ້າເຖິງ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"ແຖບຄຳບັນຍາຍຂອງ <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ຖືກວາງໄວ້ໃນກະຕ່າ \"ຈຳກັດ\" ແລ້ວ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ສ່ວນຕົວ"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ວຽກ"</string>
</resources>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 265c97e..b8d848e 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Įrenginys bus ištrintas"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratoriaus programos negalima naudoti. Dabar įrenginio duomenys bus ištrinti.\n\nJei turite klausimų, susisiekite su organizacijos administratoriumi."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Neleidžiama spausdinti (<xliff:g id="OWNER_APP">%s</xliff:g>)."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administratorius laikinai sustabdė asmenines programas"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Palieskite čia, kad patikrintumėte, ar laikomasi politikos."</string>
<string name="me" msgid="6207584824693813140">"Aš"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetinio kompiuterio parinktys"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"„Android TV“ parinktys"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Netinkamai nupiešėte atrakinimo piešinį <xliff:g id="NUMBER_0">%1$d</xliff:g> k. Po dar <xliff:g id="NUMBER_1">%2$d</xliff:g> nesėkm. band. būsite paprašyti atrakinti telefoną naudodami „Google“ prisijungimo duomenis.\n\n Bandykite dar kartą po <xliff:g id="NUMBER_2">%3$d</xliff:g> sek."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Pašalinti"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fone pradėtai priekinio plano paslaugai iš „<xliff:g id="PACKAGENAME">%1$s</xliff:g>“ nebus suteiktas leidimas naudojimo metu būsimose R versijose. Apsilankykite go/r-bg-fgs-restriction ir pateikite pranešimą apie riktą."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Padidinti garsą daugiau nei rekomenduojamas lygis?\n\nIlgai klausydami dideliu garsu galite pažeisti klausą."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Naudoti spartųjį pritaikymo neįgaliesiems klavišą?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kai spartusis klavišas įjungtas, spaudžiant abu garsumo mygtukus 3 sekundes bus paleista pritaikymo neįgaliesiems funkcija.\n\n Dabartinė pritaikymo neįgaliesiems funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>„\n“\n Funkciją galite pakeisti skiltyje „Nustatymai“ > „Pritaikymas neįgaliesiems“."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Programa nepasiekiama"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Programa „<xliff:g id="APP_NAME_0">%1$s</xliff:g>“ šiuo metu nepasiekiama. Tai tvarkoma naudojant programą „<xliff:g id="APP_NAME_1">%2$s</xliff:g>“."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Sužinoti daugiau"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Atšaukti programos pristabdymą"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Įjungti darbo profilį?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Darbo programos, pranešimai, duomenys ir kitos darbo profilio funkcijos bus išjungtos"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Įjungti"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Perjungti išskaidyto ekrano režimą"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Užrakinimo ekranas"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrano kopija"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Pritaikomumo meniu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Programos „<xliff:g id="APP_NAME">%1$s</xliff:g>“ antraštės juosta."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"„<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>“ įkeltas į grupę APRIBOTA"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Asmeninė"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Darbo"</string>
</resources>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index a535f6d..f168bb4 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Jūsu ierīces dati tiks dzēsti"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratora lietotni nevar izmantot. Ierīcē saglabātie dati tiks dzēsti.\n\nJa jums ir kādi jautājumi, sazinieties ar savas organizācijas administratoru."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukāšanu atspējoja <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administrators apturēja privāto lietotņu darbību"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Pieskarieties šeit, lai noskaidrotu atbilstību politikai."</string>
<string name="me" msgid="6207584824693813140">"Man"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planšetdatora opcijas"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV opcijas"</string>
@@ -1635,8 +1633,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Jūs nepareizi norādījāt atbloķēšanas kombināciju <xliff:g id="NUMBER_0">%1$d</xliff:g> reizes. Pēc vēl <xliff:g id="NUMBER_1">%2$d</xliff:g> neveiksmīgiem mēģinājumiem tālrunis būs jāatbloķē, izmantojot e-pasta kontu.\n\nMēģiniet vēlreiz pēc <xliff:g id="NUMBER_2">%3$d</xliff:g> sekundēm."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Noņemt"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonā sāktam priekšplāna pakalpojumam no pakotnes <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebūs atļaujas “while-in-use” turpmākajās R versijās. Lūdzu, skatiet vietni go/r-bg-fgs-restriction un iesniedziet kļūdas pārskatu."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vai palielināt skaļumu virs ieteicamā līmeņa?\n\nIlgstoši klausoties skaņu lielā skaļumā, var tikt bojāta dzirde."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vai izmantot pieejamības saīsni?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ja saīsne ir iespējota, vienlaikus nospiežot abas skaļuma regulēšanas pogas un trīs sekundes turot tās, tiks palaista pieejamības funkcija.\n\n Pašreiz iestatītā pieejamības funkcija:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Šo funkciju var mainīt sadaļā Iestatījumi > Pieejamība."</string>
@@ -1884,8 +1881,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Lietotne nav pieejama"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> pašlaik nav pieejama. Šo darbību pārvalda <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Uzzināt vairāk"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Atsākt lietotnes darbību"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Vai ieslēgt darba profilu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Tiks ieslēgtas jūsu darba lietotnes, paziņojumi, dati un citas darba profila funkcijas."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ieslēgt"</string>
@@ -2041,12 +2037,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Pārslēgt ekrāna sadalīšanu"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloķēt ekrānu"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekrānuzņēmums"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Pieejamības izvēlne"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Lietotnes <xliff:g id="APP_NAME">%1$s</xliff:g> subtitru josla."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Pakotne “<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>” ir ievietota ierobežotā kopā."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Privātais profils"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Darba profils"</string>
</resources>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 2f75269..f94d191 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Уредот ќе се избрише"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Апликацијата на администраторот не може да се користи. Уредот ќе се избрише сега.\n\nАко имате прашања, контактирајте со администраторот на организацијата."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Печатењето е оневозможено од <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Администраторот ги суспендирал личните апликации"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Допрете тука за да ја проверите усогласеноста со правилата."</string>
<string name="me" msgid="6207584824693813140">"Јас"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опции на таблет"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опции на Android TV"</string>
@@ -1615,8 +1613,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Погрешно сте ја употребиле вашата шема на отклучување <xliff:g id="NUMBER_0">%1$d</xliff:g> пати. По <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешни обиди, ќе побараат од вас да го отклучите телефонот со користење сметка на е-пошта.\n\n Обидете се повторно за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунди."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Отстрани"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услугата од преден план започната во заднина од <xliff:g id="PACKAGENAME">%1$s</xliff:g> нема да има дозола за „додека се користи“ во идните R-верзии. Погледнете на go/r-bg-fgs-restriction и испратете извештај за грешка."</string>
<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="8306239551412868396">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција на пристапност.\n\n Тековна функција на пристапност:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Функцијата може да ја промените во „Поставки“ > „Пристапност“."</string>
@@ -1854,8 +1851,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Апликацијата не е достапна"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Апликацијата <xliff:g id="APP_NAME_0">%1$s</xliff:g> не е достапна во моментов. Со ова управува <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Дознај повеќе"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Прекини ја паузата"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Да се вклучи работниот профил?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Вашите работни апликации, известувања, податоци и други функции на работниот профил ќе бидат вклучени"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Вклучи"</string>
@@ -2009,12 +2005,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Вклучи/исклучи поделен екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заклучен екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Слика од екранот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Мени за пристапност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Насловна лента на <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> е ставен во корпата ОГРАНИЧЕНИ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Службени"</string>
</resources>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 25d7212..1efd211 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"നിങ്ങളുടെ ഉപകരണം മായ്ക്കും"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"അഡ്മിൻ ആപ്പ് ഉപയോഗിക്കാനാകില്ല. നിങ്ങളുടെ ഉപകരണം ഇപ്പോൾ മായ്ക്കപ്പെടും.\n\nനിങ്ങൾക്ക് ചോദ്യങ്ങൾ ഉണ്ടെങ്കിൽ, നിങ്ങളുടെ സ്ഥാപനത്തിന്റെ അഡ്മിനെ ബന്ധപ്പെടുക."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> പ്രിന്റിംഗ് പ്രവർത്തനരഹിതമാക്കി."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"വ്യക്തഗത ആപ്പുകൾ ഒരു അഡ്മിൻ താൽക്കാലികമായി റദ്ദാക്കിയിരിക്കുന്നു"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"നയത്തിന് അനുസൃതമാണോ എന്ന് പരിശോധിക്കാൻ ഇവിടെ ടാപ്പ് ചെയ്യുക."</string>
<string name="me" msgid="6207584824693813140">"ഞാന്"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ടാബ്ലെറ്റ് ഓപ്ഷനുകൾ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ടിവി ഓപ്ഷനുകൾ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"നിങ്ങളുടെ അൺലോക്ക് പാറ്റേൺ <xliff:g id="NUMBER_0">%1$d</xliff:g> തവണ തെറ്റായി വരച്ചു. <xliff:g id="NUMBER_1">%2$d</xliff:g> ശ്രമങ്ങൾ കൂടി വിജയിച്ചില്ലെങ്കിൽ, ഒരു ഇമെയിൽ അക്കൗണ്ട് ഉപയോഗിച്ച് ഫോൺ അൺലോക്ക് ചെയ്യാൻ നിങ്ങളോട് ആവശ്യപ്പെടും.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> സെക്കൻഡിനുള്ള വീണ്ടും ശ്രമിക്കുക."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"നീക്കംചെയ്യുക"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> എന്നതിൽ നിന്നുള്ള പശ്ചാത്തലത്തിൽ ആരംഭിച്ച് ഫോർഗ്രൗണ്ടിൽ വരുന്ന സേവനത്തിന് ഭാവി R ബിൽഡുകളിൽ, \'ഉപയോഗിക്കുമ്പോൾ മാത്രമുള്ള അനുമതി\' ഉണ്ടായിരിക്കില്ല. go/r-bg-fgs-restriction കണ്ട് ബഗ് റിപ്പോർട്ട് ഫയൽ ചെയ്യുക."</string>
<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="8306239551412868396">"കുറുക്കുവഴി ഓണാണെങ്കിൽ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും.\n\n നിലവിലെ ഉപയോഗസഹായി ഫീച്ചർ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ക്രമീകരണം > ഉപയോഗസഹായി എന്നതിൽ ഏത് സമയത്തും നിങ്ങൾക്ക് ഫീച്ചർ മാറ്റാവുന്നതാണ്."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ആപ്പ് ലഭ്യമല്ല"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ഇപ്പോൾ ലഭ്യമല്ല. <xliff:g id="APP_NAME_1">%2$s</xliff:g> ആണ് ഇത് മാനേജ് ചെയ്യുന്നത്."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"കൂടുതലറിയുക"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ആപ്പ് പുനഃരാംഭിക്കുക"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ഔദ്യോഗിക പ്രൊഫൈൽ ഓണാക്കണോ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"നിങ്ങളുടെ ഔദ്യോഗിക ആപ്പുകൾ, അറിയിപ്പുകൾ, ഡാറ്റ, മറ്റ് ഔദ്യോഗിക പ്രൊഫൈൽ ഫീച്ചറുകൾ എന്നിവ ഓണാക്കും"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ഓണാക്കുക"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"സ്ക്രീൻ വിഭജന മോഡ് മാറ്റുക"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ലോക്ക് സ്ക്രീൻ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"സ്ക്രീൻഷോട്ട്"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ഉപയോഗസഹായി മെനു"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> എന്നതിന്റെ അടിക്കുറിപ്പ് ബാർ."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> നിയന്ത്രിത ബക്കറ്റിലേക്ക് നീക്കി"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"വ്യക്തിപരമായത്"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ജോലിസ്ഥലം"</string>
</resources>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 3acdb72..cc03175 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Таны төхөөрөмж устах болно."</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Админ аппыг ашиглах боломжгүй. Таны төхөөрөмжийг одоо устгана.\n\nХэрэв танд асуулт байгаа бол байгууллагынхаа админтай холбогдоно уу."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> хэвлэх үйлдлийг идэвхгүй болгосон."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Хувийн аппуудыг админ түр хаасан байна"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Удирдамжийн нийцлийг шалгахын тулд энд товшино уу."</string>
<string name="me" msgid="6207584824693813140">"Би"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Таблетын сонголтууд"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ТВ-н сонголт"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Та тайлах хээг <xliff:g id="NUMBER_0">%1$d</xliff:g> удаа буруу зурлаа. <xliff:g id="NUMBER_1">%2$d</xliff:g> удаа дахин буруу оруулбал, та утсаа тайлахын тулд имэйл бүртгэлээ ашиглах шаардлагатай болно.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> секундын дараа дахин оролдоно уу."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Устгах"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g>-н дэлгэц дээрх үйлчилгээг эхлүүлдэг дэвсгэр нь цаашид R хийцийн ашиглах үеийн зөвшөөрөлгүй болно. go/r-bg-fgs-restriction-г үзэж, алдааны мэдээ илгээнэ үү."</string>
<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="8306239551412868396">"Товчлолыг асаасан үед дуун товчлуурыг 3 секунд дарснаар хүртээмжийн онцлогийг эхлүүлнэ.\n\n Одоогийн хүртээмжийн онцлог:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Онцлогийг Тохиргоо > Хүртээмж хэсэгт өөрчлөх боломжтой."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Апп боломжгүй байна"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> одоогоор боломжгүй байна. Үүнийг <xliff:g id="APP_NAME_1">%2$s</xliff:g>-р удирддаг."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Дэлгэрэнгүй үзэх"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Аппыг түр зогсоохоо болих"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ажлын профайлыг асаах уу?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Таны ажлын апп, мэдэгдэл, өгөгдөл болон бусад ажлын профайлын онцлогийг асаана"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Асаах"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Дэлгэц хуваахыг унтраах/асаах"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Дэлгэцийг түгжих"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Дэлгэцийн зураг дарах"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Хандалтын цэс"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>-н гарчгийн талбар."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>-г ХЯЗГААРЛАСАН сагс руу орууллаа"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Хувийн"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Ажил"</string>
</resources>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index ff9f3e7..cd9b6fc 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"तुमचे डिव्हाइस मिटविले जाईल"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"प्रशासक अॅप वापरता येणार नाही. तुमचे डिव्हाइस आता साफ केले जाईल.\n\nतुम्हाला कुठलेही प्रश्न असल्यास, तुमच्या संस्थेच्या प्रशासकाशी संपर्क साधा."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> नी प्रिंट करणे बंद केले आहे."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ॲडमिनद्वारे वैयक्तिक ॲप निलंबित केले गेले आहेत"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"धोरणाचे पालन तपासण्यासाठी येथे टॅप करा."</string>
<string name="me" msgid="6207584824693813140">"मी"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"टॅबलेट पर्याय"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV पर्याय"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तुम्ही तुमचा अनलॉक पॅटर्न <xliff:g id="NUMBER_0">%1$d</xliff:g> वेळा अयोग्यपणे काढला आहे. आणखी <xliff:g id="NUMBER_1">%2$d</xliff:g> अयशस्वी प्रयत्नांनंतर, तुम्हाला ईमेल खाते वापरून तुमचा फोन अनलॉक करण्यास सांगितले जाईल.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकंदांमध्ये पुन्हा प्रयत्न करा."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"काढा"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> कडून बॅकग्राउंडने फोरग्राउंडमध्ये सुरू केलेल्या सेवेला भविष्यातील आर बिल्डमध्ये वापर करते वेळची परवानगी नसेल. कृपया go/r-bg-fgs-restriction पहा आणि बगची तक्रार नोंदवा."</string>
<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="8306239551412868396">"शॉर्टकट चालू असताना, दोन्ही आवाज बटणे 3 सेकंद दाबल्याने प्रवेशयोग्यता वैशिष्ट्य सुरू होईल.\n\n वर्तमान प्रवेशयोग्यता वैशिष्ट्य:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तुम्ही सेटिंग्ज > प्रवेशयोग्यता मध्ये वैशिष्ट्य बदलू शकता."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"अॅप उपलब्ध नाही"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> आत्ता उपलब्ध नाही. हे <xliff:g id="APP_NAME_1">%2$s</xliff:g> कडून व्यवस्थापित केले जाते."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"अधिक जाणून घ्या"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"अॅप उघडा"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल चालू ठेवायची?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"तुमची कार्य अॅप्स, सूचना, डेटा आणि अन्य कार्य प्रोफाइल वैशिष्ट्ये चालू केली जातील"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"चालू करा"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रीन टॉगल करा"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"स्क्रीन लॉक करा"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रीनशॉट"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"अॅक्सेसिबिलिटी मेनू"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> चा शीर्षक बार."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> हे प्रतिबंधित बादलीमध्ये ठेवण्यात आले आहे"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"वैयक्तिक"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ऑफिस"</string>
</resources>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index e436408..0a40735 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Peranti anda akan dipadam"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Apl pentadbir tidak dapat digunakan. Peranti anda akan dipadamkan sekarang.\n\nJika anda ingin mengemukakan soalan, hubungi pentadbir organisasi anda."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Pencetakan dilumpuhkan oleh <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Apl peribadi telah digantung oleh pentadbir"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Ketik di sini untuk menyemak pematuhan dasar."</string>
<string name="me" msgid="6207584824693813140">"Saya"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Pilihan tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Pilihan Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Anda telah tersilap lukis corak buka kunci sebanyak <xliff:g id="NUMBER_0">%1$d</xliff:g> kali. Selepas <xliff:g id="NUMBER_1">%2$d</xliff:g> lagi percubaan yang tidak berjaya, anda akan diminta membuka kunci telefon anda menggunakan log masuk Google anda.\n\n Cuba lagi dalam <xliff:g id="NUMBER_2">%3$d</xliff:g> saat."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Alih keluar"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Perkhidmatan latar depan dimulakan latar belakang daripada <xliff:g id="PACKAGENAME">%1$s</xliff:g> tidak akan mempunyai kebenaran semasa-dalam-penggunaan dalam binaan R akan datang. Sila lihat go/r-bg-fgs-restriction dan failkan laporan pepijat."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Naikkan kelantangan melebihi paras yang disyokorkan?\n\nMendengar pada kelantangan yang tinggi untuk tempoh yang lama boleh merosakkan pendengaran anda."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gunakan Pintasan Kebolehaksesan?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan.\n\n Ciri kebolehaksesan semasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Anda boleh menukar ciri itu dalam Tetapan > Kebolehaksesan."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Apl tidak tersedia"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> tidak tersedia sekarang. Ini diurus oleh <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Ketahui lebih lanjut"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Nyahjeda apl"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Hidupkan profil kerja?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Apl kerja, pemberitahuan, data dan ciri profil kerja anda yang lain akan dihidupkan"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Hidupkan"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Togol Skrin Pisah"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrin Kunci"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Tangkapan skrin"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Kebolehaksesan"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bar kapsyen <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> telah diletakkan dalam baldi TERHAD"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Peribadi"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Kerja"</string>
</resources>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 56f49c2..9e04841 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"သင့်ကိရိယာအား ပယ်ဖျက်လိမ့်မည်"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"စီမံခန့်ခွဲမှု အက်ပ်ကို သုံး၍မရပါ။ သင်၏ စက်ပစ္စည်းအတွင်းရှိ အရာများကို ဖျက်လိုက်ပါမည်\n\nမေးစရာများရှိပါက သင့်အဖွဲ့အစည်း၏ စီမံခန့်ခွဲသူကို ဆက်သွယ်ပါ။"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> က ပုံနှိပ်ထုတ်ယူခြင်းကို ပိတ်ထားသည်။"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ကိုယ်ပိုင်အက်ပ်များကို စီမံခန့်ခွဲသူက ဆိုင်းငံ့ထားသည်"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"မူဝါဒလိုက်နာမှုကို စစ်ဆေးရန် ဤနေရာကို တို့ပါ။"</string>
<string name="me" msgid="6207584824693813140">"ကျွန်ုပ်"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletဆိုင်ရာရွေးချယ်မှုများ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ရွေးချယ်စရာများ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"သင် ပုံဖော်၍သော့ဖွင့်ခြင်းကို <xliff:g id="NUMBER_0">%1$d</xliff:g> အကြိမ် မှန်ကန်စွာ မပြုလုပ်နိုင်ပါ။ နောက်ထပ် <xliff:g id="NUMBER_1">%2$d</xliff:g> အကြိမ် မမှန်ကန်ပါက သင့်ဖုန်းအား အီးမေးလ်အသုံးပြု၍ သော့ဖွင့်ရန် တောင်းဆိုပါလိမ့်မည်။ \n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> စက္ကန့်အကြာတွင် ပြန်လည် ကြိုးစားပါ"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ဖယ်ရှားရန်"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> တွင် မှ စတင်သည့် foreground ဝန်ဆောင်မှုသည် နောက်ထွက်ရှိမည့် R စုပေါင်းစပ်ပေါင်း ပရိုဂရမ်များတွင် အသုံးပြုစဉ်အတွင်း ခွင့်ပြုချက် ရရှိမည်မဟုတ်ပါ။ go/r-bg-fgs-ကန့်သတ်ချက်များကို ကြည့်ပြီး အမှားသတင်းပို့ချက်တစ်ခု တင်သွင်းပါ။"</string>
<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="8306239551412868396">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံအတိုးအလျှော့ခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။\n\n လက်ရှိ အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှု−\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ဝန်ဆောင်မှုကို ဆက်တင်များ > အများသုံးစွဲနိုင်မှုတွင် ပြောင်းလဲနိုင်ပါသည်။"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"အက်ပ်ကို မရရှိနိုင်ပါ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ကို လောလောဆယ် မရနိုင်ပါ။ ၎င်းကို <xliff:g id="APP_NAME_1">%2$s</xliff:g> က စီမံထားပါသည်။"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ပိုမိုလေ့လာရန်"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"အက်ပ်ကို ခဏမရပ်တော့ရန်"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"အလုပ်ပရိုဖိုင် ဖွင့်လိုသလား။"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"သင်၏ အလုပ်အက်ပ်၊ အကြောင်းကြားချက်၊ ဒေတာနှင့် အခြားအလုပ်ပရိုဖိုင် ဝန်ဆောင်မှုများကို ဖွင့်လိုက်ပါမည်"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ဖွင့်ပါ"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"မျက်နှာပြင် ခွဲ၍ပြသခြင်းကို နှိပ်ပါ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"လော့ခ်မျက်နှာပြင်"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ဖန်သားပြင်ဓာတ်ပုံ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"အများသုံးစွဲနိုင်မှု မီနူး"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>၏ ခေါင်းစီး ဘား။"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ကို တားမြစ်ထားသော သိမ်းဆည်းမှုအတွင်းသို့ ထည့်ပြီးပါပြီ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ကိုယ်ပိုင်"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"အလုပ်"</string>
</resources>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index bb3d52f..45ab3e5 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten blir slettet"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administratorappen kan ikke brukes. Enheten din blir nå tømt.\n\nTa kontakt med administratoren for organisasjonen din hvis du har spørsmål."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> har slått av utskrift."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Personlige apper er sperret midlertidig av en administrator"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Trykk her for å sjekke overholdelse av retningslinjer."</string>
<string name="me" msgid="6207584824693813140">"Meg"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Innstillinger for nettbrettet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV-alternativer"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har tegnet opplåsningsmønsteret feil <xliff:g id="NUMBER_0">%1$d</xliff:g> ganger. Etter ytterligere <xliff:g id="NUMBER_1">%2$d</xliff:g> gale forsøk, blir du bedt om å låse opp telefonen via en e-postkonto.\n\n Prøv på nytt om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Fjern"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Forgrunnstjenesten fra <xliff:g id="PACKAGENAME">%1$s</xliff:g>, som ble startet i bakgrunnen, kommer ikke til å ha tillatelser mens den er i bruk i fremtidige R-delversjoner. Les go/r-bg-fgs-restriction og send inn en feilrapport."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vil du øke volumet til over anbefalt nivå?\n\nHvis du hører på et høyt volum over lengre perioder, kan det skade hørselen din."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vil du bruke tilgjengelighetssnarveien?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder.\n\n Nåværende tilgjengelighetsfunksjon:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan endre funksjonen i Innstillinger > Tilgjengelighet."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Appen er ikke tilgjengelig"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> er ikke tilgjengelig akkurat nå. Dette administreres av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Finn ut mer"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Opphev pause for appen"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Vil du slå på jobbprofilen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappene dine samt varsler, data og andre funksjoner i jobbprofilen din blir slått på"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Slå på"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Slå delt skjerm av/på"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låseskjerm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skjermdump"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Tilgjengelighet-meny"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Tekstingsfelt i <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> er blitt plassert i TILGANGSBEGRENSET-toppmappen"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personlig"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string>
</resources>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index b3d6cde..11033a7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"तपाईंको यन्त्र मेटिनेछ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"प्रशासकको अनुप्रयोग प्रयोग गर्न मिल्दैन। तपाईंको यन्त्रको डेटा अब मेटाइने छ।\n\nतपाईंसँग प्रश्नहरू भएका खण्डमा आफ्नो संगठनका प्रशासकसँग सम्पर्क गर्नुहोस्।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ले छाप्ने कार्यलाई असक्षम पार्यो।"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"व्यक्तिगत एपहरू एकजना प्रशासकले निलम्बन गरिरहनुभएको छ"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"नीति पालनाबारे जाँच गर्न यहाँ ट्याप गर्नुहोस्।"</string>
<string name="me" msgid="6207584824693813140">"मलाई"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ट्याब्लेट विकल्पहरू"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV सम्बन्धी विकल्पहरू"</string>
@@ -1619,8 +1617,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"तपाईँले आफ्नो अनलक ढाँचा गलत रूपमा <xliff:g id="NUMBER_0">%1$d</xliff:g> पटक तान्नु भएको छ। <xliff:g id="NUMBER_1">%2$d</xliff:g> धेरै असफल प्रयासहरूपछि, तपाईँलाई एउटा इमेल खाताको प्रयोग गरेर तपाईँको फोन अनलक गर्न सोधिने छ।\n\n फेरि <xliff:g id="NUMBER_2">%3$d</xliff:g> सेकेन्डमा प्रयास गर्नुहोस्।"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"हटाउनुहोस्"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> को पृष्ठभूमिबाट सुरु गरिने अग्रभूमि सेवाका भविष्यमा आउने R बिल्डहरूमा चलाउँदै गर्दा प्रयोग गर्ने अनुमतिको दिइने छैन। कृपया go/r-bg-fgs-restriction हेर्नुहोस् र कुनै बगसम्बन्धी रिपोर्ट फाइल गर्नुहोस्।"</string>
<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="8306239551412868396">"सर्टकट सक्रिय हुँदा, भोल्युमका दुवै बटनहरूलाई ३ सेकेन्डसम्म थिची राख्नाले पहुँच सम्बन्धी कुनै सुविधा सुरु हुनेछ।\n\n हाल व्यवहारमा रहेको पहुँच सम्बन्धी सुविधा:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n तपाईं सेटिङहरू अन्तर्गतको पहुँच सम्बन्धी विकल्पमा गई उक्त सुविधालाई बदल्न सक्नुहुन्छ।"</string>
@@ -1858,8 +1855,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"अनुप्रयोग उपलब्ध छैन"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> अहिले उपलब्ध छैन। यो <xliff:g id="APP_NAME_1">%2$s</xliff:g> द्वारा व्यवस्थित छ।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"थप जान्नुहोस्"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"एपको पज हटाउनुहोस्"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"कार्य प्रोफाइल सक्रिय गर्ने?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"तपाईंका कार्यसम्बन्धी अनुप्रयोग, सूचना, डेटा र कार्य प्रोफाइलका अन्य सुविधाहरू सक्रिय गरिने छन्"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"सक्रिय गर्नुहोस्"</string>
@@ -2013,12 +2009,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"विभाजित स्क्रिन टगल गर्नुहोस्"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"लक स्क्रिन"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"स्क्रिनसट"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"पहुँचसम्बन्धी मेनु"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> को क्याप्सन बार।"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> लाई प्रतिबन्धित बाल्टीमा राखियो"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"व्यक्तिगत"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"काम"</string>
</resources>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 47de950..13f6725 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Je apparaat wordt gewist"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"De beheer-app kan niet worden gebruikt. Je apparaat wordt nu gewist.\n\nNeem contact op met de beheerder van je organisatie als je vragen hebt."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Afdrukken uitgeschakeld door <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Persoonlijke apps zijn opgeschort door een beheerder"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tik hier om beleidsnaleving te controleren."</string>
<string name="me" msgid="6207584824693813140">"Ik"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tabletopties"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opties voor Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Je hebt je ontgrendelingspatroon <xliff:g id="NUMBER_0">%1$d</xliff:g> keer onjuist getekend. Na nog eens <xliff:g id="NUMBER_1">%2$d</xliff:g> mislukte pogingen wordt u gevraagd je telefoon te ontgrendelen via een e-mailaccount.\n\n Probeer het over <xliff:g id="NUMBER_2">%3$d</xliff:g> seconden opnieuw."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Verwijderen"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"De op de achtergrond gestarte voorgrondservice van <xliff:g id="PACKAGENAME">%1$s</xliff:g> heeft geen rechten tijdens gebruik in toekomstige R-builds. Ga naar go/r-bg-fgs-restriction en dien een bugrapport in."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Volume verhogen tot boven het aanbevolen niveau?\n\nAls je langere tijd op hoog volume naar muziek luistert, raakt je gehoor mogelijk beschadigd."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Snelkoppeling toegankelijkheid gebruiken?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Wanneer de snelkoppeling is ingeschakeld, kun je drie seconden op beide volumeknoppen drukken om een toegankelijkheidsfunctie te starten.\n\n Huidige toegankelijkheidsfunctie:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Je kunt de functie wijzigen in Instellingen > Toegankelijkheid."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"App is niet beschikbaar"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> is nu niet beschikbaar. Dit wordt beheerd door <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Meer info"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"App niet meer onderbreken"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Werkprofiel inschakelen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Je werk-apps, meldingen, gegevens en andere functies van je werkprofiel worden uitgeschakeld"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Inschakelen"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Gesplitst scherm schakelen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Scherm vergrendelen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Toegankelijkheidsmenu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ondertitelingsbalk van <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> is in de bucket RESTRICTED geplaatst"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Persoonlijk"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Werk"</string>
</resources>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 1242188..4424af7 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ଆପଣଙ୍କ ଡିଭାଇସ୍ ବର୍ତ୍ତମାନ ଲିଭାଯିବ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ଆଡମିନ୍ ଆପ୍ ବ୍ୟବହାର କରାଯାଇପାରିବ ନାହିଁ। ଆପଣଙ୍କ ଡିଭାଇସ୍ର ସମସ୍ତ ଡାଟାକୁ ବର୍ତ୍ତମାନ ଲିଭାଇଦିଆଯିବ। \n\nଯଦି ଆପଣଙ୍କର କୌଣସି ପ୍ରଶ୍ନ ରହିଥାଏ, ଆପଣଙ୍କ ସଂସ୍ଥାର ଆଡମିନ୍ଙ୍କ ସହ ଯୋଗାଯୋଗ କରନ୍ତୁ।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ଦ୍ଵାରା ପ୍ରିଣ୍ଟିଙ୍ଗ ଅକ୍ଷମ କରାଯାଇଛି"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ବ୍ୟକ୍ତିଗତ ଆପଗୁଡ଼ିକୁ ଆଡମିନଙ୍କ ଦ୍ୱାରା ସାମୟିକ ଭାବରେ ବନ୍ଦ କରାଯାଇଛି"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ନୀତି ଅନୁପାଳନର ଯାଞ୍ଚ କରିବା ପାଇଁ ଏଠାରେ ଟାପ୍ କରନ୍ତୁ।"</string>
<string name="me" msgid="6207584824693813140">"ମୁଁ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ଟାବଲେଟ୍ର ବିକଳ୍ପ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android ଟିଭିର ବିକଳ୍ପଗୁଡ଼ିକ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ଆପଣଙ୍କ ଅନଲକ୍ ପାଟର୍ନକୁ ଆପଣ <xliff:g id="NUMBER_0">%1$d</xliff:g> ଥର ଭୁଲ ଭାବେ ଅଙ୍କନ କରିଛନ୍ତି। ଆଉ <xliff:g id="NUMBER_1">%2$d</xliff:g>ଟି ଭୁଲ ପ୍ରୟାସ ପରେ ଏକ ଇମେଲ୍ ଆକାଉଣ୍ଟ ବ୍ୟବହାର କରି ନିଜ ଫୋନ୍କୁ ଅନଲକ୍ କରିବା ପାଇଁ କୁହାଯିବ।\n\n<xliff:g id="NUMBER_2">%3$d</xliff:g> ସେକେଣ୍ଡ ପରେ ପୁଣି ଚେଷ୍ଟା କରନ୍ତୁ।"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ବାହାର କରନ୍ତୁ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"ପୃଷ୍ଠଭୂମିରେ <xliff:g id="PACKAGENAME">%1$s</xliff:g>ରୁ ଆରମ୍ଭ ହୋଇଥିବା ସମ୍ମୁଖଭାଗ ସେବା ପାଇଁ ଭବିଷ୍ୟତର R ବିଲ୍ଡଗୁଡ଼ିକରେ ବ୍ୟବହାର କରାଯିବା ସମୟରେ ଅନୁମତି ସୁବିଧା ରହିବ ନାହିଁ। ଦୟାକରି go/r-bg-fgs-restriction ଦେଖନ୍ତୁ ଏବଂ ଏକ ବଗରିପୋର୍ଟ ଫାଇଲ୍ କରନ୍ତୁ।"</string>
<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="8306239551412868396">"ସର୍ଟକଟ୍ ଅନ୍ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ ଆରମ୍ଭ ହେବ।\n\n ସମ୍ପ୍ରତି ଆକ୍ସେସବିଲିଟି ବୈଶିଷ୍ଟ୍ୟ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ସେଟିଙ୍ଗ ଓ ଆକ୍ସେସବିଲିଟିରେ ଆପଣ ବୈଶିଷ୍ଟ୍ୟ ବଦଳାଇ ପାରିବେ।"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ଆପ୍ ଉପଲବ୍ଧ ନାହିଁ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"ବର୍ତ୍ତମାନ <xliff:g id="APP_NAME_0">%1$s</xliff:g> ଉପଲବ୍ଧ ନାହିଁ। ଏହା <xliff:g id="APP_NAME_1">%2$s</xliff:g> ଦ୍ଵାରା ପରିଚାଳିତ ହେଉଛି।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ଅଧିକ ଜାଣନ୍ତୁ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ଆପ୍ ଅନପଜ୍ କରନ୍ତୁ"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ୱର୍କ ପ୍ରୋଫାଇଲ୍କୁ ଚାଲୁ କରିବେ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ଆପଣଙ୍କର କାର୍ଯ୍ୟକାରୀ ଆପ୍, ବିଜ୍ଞପ୍ତି, ଡାଟା ଓ ଅନ୍ୟ ୱର୍କ ପ୍ରୋଫାଇଲ୍ଗୁଡ଼ିକ ଚାଲୁ ହୋଇଯିବ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ଅନ୍ କରନ୍ତୁ"</string>
@@ -1989,8 +1985,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ସ୍ପ୍ରେଡ୍ସିଟ୍"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"ଉପସ୍ଥାପନା"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ଉପସ୍ଥାପନା"</string>
- <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) -->
- <skip />
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ଏୟାରପ୍ଲେନ୍ ମୋଡରେ ବ୍ଲୁଟୁଥ୍ ଚାଲୁ ରହିବ"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"ଲୋଡ୍ ହେଉଛି"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="other"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g>ଟି ଫାଇଲ୍</item>
@@ -2008,13 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ଦୁଇଟି ସ୍କ୍ରିନ୍ ମଧ୍ୟରେ ଟୋଗଲ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ସ୍କ୍ରିନ୍ ଲକ୍ କରନ୍ତୁ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ଆକ୍ସେସିବିଲିଟୀ ମେନୁ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>ର କ୍ୟାପ୍ସନ୍ ବାର୍।"</string>
- <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) -->
- <skip />
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>କୁ ପ୍ରତିବନ୍ଧିତ ବକେଟରେ ରଖାଯାଇଛି"</string>
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ବ୍ୟକ୍ତିଗତ"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"କାର୍ଯ୍ୟ"</string>
</resources>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index b6513c3..8c87581 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ਤੁਹਾਡਾ ਡੀਵਾਈਸ ਮਿਟਾਇਆ ਜਾਏਗਾ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ਪ੍ਰਸ਼ਾਸਕ ਐਪ ਵਰਤੀ ਨਹੀਂ ਜਾ ਸਕਦੀ। ਹੁਣ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦਾ ਡਾਟਾ ਮਿਟਾਇਆ ਜਾਵੇਗਾ।\n\nਜੇਕਰ ਤੁਹਾਡੇ ਕੋਲ ਕੋਈ ਸਵਾਲ ਹਨ, ਤਾਂ ਆਪਣੀ ਸੰਸਥਾ ਦੇ ਪ੍ਰਸ਼ਾਸਕ ਨੂੰ ਸੰਪਰਕ ਕਰੋ।"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ਵੱਲੋਂ ਪ੍ਰਿੰਟ ਕਰਨਾ ਬੰਦ ਕੀਤਾ ਗਿਆ।"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ਨਿੱਜੀ ਐਪਾਂ ਨੂੰ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮੁਅੱਤਲ ਕਰ ਦਿੱਤਾ ਗਿਆ ਹੈ"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ਨੀਤੀ ਦੀ ਪਾਲਣਾ ਨੂੰ ਦੇਖਣ ਲਈ ਇੱਥੇ ਟੈਪ ਕਰੋ।"</string>
<string name="me" msgid="6207584824693813140">"ਮੈਂ"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ਟੈਬਲੈੱਟ ਵਿਕਲਪ"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ਦੇ ਵਿਕਲਪ"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ਤੁਸੀਂ <xliff:g id="NUMBER_0">%1$d</xliff:g> ਵਾਰ ਆਪਣਾ ਅਣਲਾਕ ਪੈਟਰਨ ਗਲਤ ਢੰਗ ਨਾਲ ਡ੍ਰਾ ਕੀਤਾ ਹੈ। <xliff:g id="NUMBER_1">%2$d</xliff:g> ਹੋਰ ਅਸਫਲ ਕੋਸ਼ਿਸ਼ਾਂ ਤੋਂ ਬਾਅਦ, ਤੁਹਾਨੂੰ ਇੱਕ ਈਮੇਲ ਖਾਤਾ ਵਰਤਦੇ ਹੋਏ ਆਪਣਾ ਫ਼ੋਨ ਅਣਲਾਕ ਕਰਨ ਲਈ ਕਿਹਾ ਜਾਏਗਾ।\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> ਸਕਿੰਟਾਂ ਵਿੱਚ ਦੁਬਾਰਾ ਕੋਸ਼ਿਸ਼ ਕਰੋ।"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ਹਟਾਓ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> ਤੋਂ ਬੈਕਗ੍ਰਾਊਂਡ ਵਿੱਚ ਸ਼ੁਰੂ ਕੀਤੀ ਗਈ ਫੋਰਗ੍ਰਾਊਂਡ ਸੇਵਾ ਲਈ ਭਵਿੱਖੀ R ਬਿਲਡ ਵਿੱਚ \'ਵਰਤੋਂ ਵਿੱਚ ਹੋਣ \'ਤੇ ਇਜਾਜ਼ਤ\' ਵਿਸ਼ੇਸ਼ਤਾ ਨਹੀਂ ਹੋਵੇਗੀ। ਕਿਰਪਾ ਕਰਕੇ go/r-bg-fgs-restriction ਦੇਖੋ ਅਤੇ ਬੱਗ ਰਿਪੋਰਟ ਫ਼ਾਈਲ ਕਰੋ।"</string>
<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="8306239551412868396">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।\n\n ਵਰਤਮਾਨ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n ਤੁਸੀਂ ਸੈਟਿੰਗਾਂ > ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ਐਪ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ਐਪ ਫਿਲਹਾਲ ਉਪਲਬਧ ਨਹੀਂ ਹੈ। ਇਸਦਾ ਪ੍ਰਬੰਧਨ <xliff:g id="APP_NAME_1">%2$s</xliff:g> ਵੱਲੋਂ ਕੀਤਾ ਜਾਂਦਾ ਹੈ।"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ਹੋਰ ਜਾਣੋ"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ਐਪ ਤੋਂ ਰੋਕ ਹਟਾਓ"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"ਕੀ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਚਾਲੂ ਕਰਨੀ ਹੈ?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ਤੁਹਾਡੀਆਂ ਕਾਰਜ-ਸਥਾਨ ਐਪਾਂ, ਸੂਚਨਾਵਾਂ, ਡਾਟਾ ਅਤੇ ਹੋਰ ਕਾਰਜ ਪ੍ਰੋਫਾਈਲ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਚਾਲੂ ਕੀਤੀਆਂ ਜਾਣਗੀਆਂ"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ਚਾਲੂ ਕਰੋ"</string>
@@ -1989,8 +1985,7 @@
<string name="mime_type_spreadsheet_ext" msgid="8720173181137254414">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਸਪਰੈੱਡਸ਼ੀਟ"</string>
<string name="mime_type_presentation" msgid="1145384236788242075">"ਪੇਸ਼ਕਾਰੀ"</string>
<string name="mime_type_presentation_ext" msgid="8761049335564371468">"<xliff:g id="EXTENSION">%1$s</xliff:g> ਪੇਸ਼ਕਾਰੀ"</string>
- <!-- no translation found for bluetooth_airplane_mode_toast (2066399056595768554) -->
- <skip />
+ <string name="bluetooth_airplane_mode_toast" msgid="2066399056595768554">"ਹਵਾਈ-ਜਹਾਜ਼ ਮੋਡ ਵੇਲੇ ਬਲੂਟੁੱਥ ਹਾਲੇ ਵੀ ਚਾਲੂ ਹੋ ਜਾਵੇਗਾ"</string>
<string name="car_loading_profile" msgid="8219978381196748070">"ਲੋਡ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
<plurals name="file_count" formatted="false" msgid="7063513834724389247">
<item quantity="one"><xliff:g id="FILE_NAME_2">%s</xliff:g> + <xliff:g id="COUNT_3">%d</xliff:g> ਫ਼ਾਈਲ</item>
@@ -2008,13 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"ਸਪਲਿਟ ਸਕ੍ਰੀਨ ਨੂੰ ਟੌਗਲ ਕਰੋ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"ਲਾਕ ਸਕ੍ਰੀਨ"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ਪਹੁੰਚਯੋਗਤਾ ਮੀਨੂ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਦੀ ਸੁਰਖੀ ਪੱਟੀ।"</string>
- <!-- no translation found for as_app_forced_to_restricted_bucket (8233871289353898964) -->
- <skip />
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ਨੂੰ ਪ੍ਰਤਿਬੰਧਿਤ ਖਾਨੇ ਵਿੱਚ ਪਾਇਆ ਗਿਆ ਹੈ"</string>
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ਨਿੱਜੀ"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"ਕੰਮ"</string>
</resources>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 964c973..5efbfbe 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -95,7 +95,7 @@
<string name="notification_channel_mobile_data_status" msgid="1941911162076442474">"Stan mobilnej transmisji danych"</string>
<string name="notification_channel_sms" msgid="1243384981025535724">"SMS-y"</string>
<string name="notification_channel_voice_mail" msgid="8457433203106654172">"Wiadomości poczty głosowej"</string>
- <string name="notification_channel_wfc" msgid="9048240466765169038">"Połączenia przez Wi-Fi"</string>
+ <string name="notification_channel_wfc" msgid="9048240466765169038">"Połączenie przez Wi-Fi"</string>
<string name="notification_channel_sim" msgid="5098802350325677490">"Stan karty SIM"</string>
<string name="notification_channel_sim_high_prio" msgid="642361929452850928">"Stan karty SIM – wysoki priorytet"</string>
<string name="peerTtyModeFull" msgid="337553730440832160">"Drugie urządzenie zażądało trybu „TTY pełny”"</string>
@@ -133,14 +133,14 @@
</string-array>
<!-- no translation found for wfcSpnFormat_spn (2982505428519096311) -->
<skip />
- <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string>
+ <string name="wfcSpnFormat_spn_wifi_calling" msgid="3165949348000906194">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez Wi-Fi"</string>
<string name="wfcSpnFormat_spn_wifi_calling_vo_hyphen" msgid="3836827895369365298">"<xliff:g id="SPN">%s</xliff:g>, połączenia przez Wi-Fi"</string>
<string name="wfcSpnFormat_wlan_call" msgid="4895315549916165700">"Połączenie przez WLAN"</string>
<string name="wfcSpnFormat_spn_wlan_call" msgid="255919245825481510">"<xliff:g id="SPN">%s</xliff:g>, połączenie przez WLAN"</string>
<string name="wfcSpnFormat_spn_wifi" msgid="7232899594327126970">"<xliff:g id="SPN">%s</xliff:g>, Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_bar_spn" msgid="8383917598312067365">"Połączenia przez Wi-Fi | <xliff:g id="SPN">%s</xliff:g>"</string>
<string name="wfcSpnFormat_spn_vowifi" msgid="6865214948822061486">"<xliff:g id="SPN">%s</xliff:g>, VoWifi"</string>
- <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Połączenia przez Wi-Fi"</string>
+ <string name="wfcSpnFormat_wifi_calling" msgid="6178935388378661755">"Połączenie przez Wi-Fi"</string>
<string name="wfcSpnFormat_wifi" msgid="1376356951297043426">"Wi-Fi"</string>
<string name="wfcSpnFormat_wifi_calling_wo_hyphen" msgid="7178561009225028264">"Połączenia przez Wi-Fi"</string>
<string name="wfcSpnFormat_vowifi" msgid="8371335230890725606">"VoWifi"</string>
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Twoje urządzenie zostanie wyczyszczone"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Nie można użyć aplikacji administratora. Dane z urządzenia zostaną wykasowane.\n\nJeśli masz pytania, skontaktuj się z administratorem organizacji."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Drukowanie wyłączone przez: <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikacje osobiste zostały zawieszone przez administratora"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Kliknij tutaj, by sprawdzić zgodność z zasadami."</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opcje tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opcje Androida TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Po raz <xliff:g id="NUMBER_0">%1$d</xliff:g> nieprawidłowo narysowałeś wzór odblokowania. Po kolejnych <xliff:g id="NUMBER_1">%2$d</xliff:g> nieudanych próbach konieczne będzie odblokowanie telefonu przy użyciu danych logowania na konto Google.\n\n Spróbuj ponownie za <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Usuń"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Uruchomiona w tle usługa działająca w pierwszym planie z pakietu <xliff:g id="PACKAGENAME">%1$s</xliff:g> nie będzie miała uprawnień obowiązujących podczas używania w przyszłych kompilacjach R. Zapoznaj się z ograniczeniem go/r-bg-fgs-restriction i zgłoś błąd."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zwiększyć głośność ponad zalecany poziom?\n\nSłuchanie głośno przez długi czas może uszkodzić Twój słuch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Użyć skrótu do ułatwień dostępu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Gdy skrót jest włączony, jednoczesne naciśnięcie przez trzy sekundy obu klawiszy sterowania głośnością uruchomi funkcję ułatwień dostępu.\n\nBieżąca funkcja ułatwień dostępu:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nFunkcję możesz zmienić, wybierając Ustawienia > Ułatwienia dostępu."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacja niedostępna"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacja <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie jest teraz dostępna. Zarządza tym aplikacja <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Więcej informacji"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Wznów działanie aplikacji"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Włączyć profil służbowy?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacje do pracy, powiadomienia, dane i inne funkcje profilu do pracy zostaną włączone"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Włącz"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Przełącz podzielony ekran"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran blokady"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Zrzut ekranu"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu ułatwień dostępu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Pasek napisów w aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Umieszczono pakiet <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> w zasobniku danych RESTRICTED"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobiste"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Do pracy"</string>
</resources>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index a6fd0fe..db48441 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Os apps pessoais foram suspensos por um administrador"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para ver a conformidade com a política."</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu de acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
- <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
</resources>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 81f5ced..04296fe 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"O seu dispositivo será apagado"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível utilizar a aplicação de administrador. O seu dispositivo será agora apagado.\n\nSe tiver questões, contacte o administrador da entidade."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"As apps pessoais foram suspensas por um administrador"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para verificar a conformidade da política."</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Desenhou o padrão de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Depois de mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas sem sucesso, ser-lhe-á pedido para desbloquear o telemóvel através de uma conta de email.\n\n Tente novamente dentro de <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano de <xliff:g id="PACKAGENAME">%1$s</xliff:g> não terá a autorização durante a utilização em compilações R futuras. Aceda a go/r-bg-fgs-restriction e envie um relatório de erros."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir com um volume elevado durante longos períodos poderá ser prejudicial para a sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Pretende utilizar o atalho de acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade.\n\n Funcionalidade de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Pode alterar a funcionalidade em Definições > Acessibilidade."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"A aplicação não está disponível"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"A aplicação <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível neste momento. A aplicação <xliff:g id="APP_NAME_1">%2$s</xliff:g> gere esta definição."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"As aplicações de trabalho, as notificações, os dados e outras funcionalidades do perfil de trabalho serão desativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar/desativar o ecrã dividido"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecrã de bloqueio"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captura de ecrã"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu Acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas da aplicação <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no contentor RESTRITO."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
</resources>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index a6fd0fe..db48441 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Seu dispositivo será limpo"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Não é possível usar o aplicativo para administrador. Seu dispositivo passará por uma limpeza agora.\n\nEm caso de dúvidas, entre em contato com o administrador da sua organização."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Impressão desativada por <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Os apps pessoais foram suspensos por um administrador"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Toque aqui para ver a conformidade com a política."</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opções do tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opções do Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Você desenhou sua sequência de desbloqueio incorretamente <xliff:g id="NUMBER_0">%1$d</xliff:g> vezes. Se fizer mais <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativas incorretas, será solicitado que você use o login do Google para desbloquear.\n\n Tente novamente em <xliff:g id="NUMBER_2">%3$d</xliff:g> segundos."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Remover"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"O serviço em primeiro plano iniciado em segundo plano por <xliff:g id="PACKAGENAME">%1$s</xliff:g> não receberá uma permissão durante o uso em futuras versões R. Consulte go/r-bg-fgs-restriction e crie um relatório de bug."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Aumentar o volume acima do nível recomendado?\n\nOuvir em volume alto por longos períodos pode danificar sua audição."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Usar atalho de Acessibilidade?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Quando o atalho está ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade.\n\n Recurso de acessibilidade atual:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n É possível alterar o recurso em Configurações > Acessibilidade."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"O app não está disponível"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"O app <xliff:g id="APP_NAME_0">%1$s</xliff:g> não está disponível no momento. Isso é gerenciado pelo app <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Saiba mais"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Retomar app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ativar o perfil de trabalho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Seus apps, notificações, dados e outros recursos do perfil de trabalho serão ativados"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Ativar"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ativar tela dividida"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Bloquear tela"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Capturar tela"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu de acessibilidade"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Barra de legendas do app <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
- <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo RESTRITO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> foi colocado no intervalo \"RESTRITO\""</string>
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Pessoal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabalho"</string>
</resources>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index cb8d3fe..030e76a2 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Datele de pe dispozitiv vor fi șterse"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplicația de administrare nu poate fi utilizată. Dispozitivul va fi șters.\n\nDacă aveți întrebări, contactați administratorul organizației dvs."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printare dezactivată de <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplicațiile personale au fost suspendate de un administrator"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Atingeți aici ca să verificați conformitatea cu politicile."</string>
<string name="me" msgid="6207584824693813140">"Eu"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opțiuni tablet PC"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opțiuni pentru Android TV"</string>
@@ -1635,8 +1633,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ați desenat incorect modelul pentru deblocare de <xliff:g id="NUMBER_0">%1$d</xliff:g> ori. După încă <xliff:g id="NUMBER_1">%2$d</xliff:g> încercări nereușite, vi se va solicita să deblocați telefonul cu ajutorul unui cont de e-mail.\n\n Încercați din nou peste <xliff:g id="NUMBER_2">%3$d</xliff:g> secunde."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Eliminați"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Serviciul în prim-plan inițializat în fundal din <xliff:g id="PACKAGENAME">%1$s</xliff:g> nu va avea permisiunea în timpul utilizării în versiunile R viitoare. Consultați go/r-bg-fgs-restriction și trimiteți un raport de eroare."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ridicați volumul mai sus de nivelul recomandat?\n\nAscultarea la volum ridicat pe perioade lungi de timp vă poate afecta auzul."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Utilizați comanda rapidă pentru accesibilitate?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de 3 secunde, veți lansa o funcție de accesibilitate.\n\n Funcția actuală de accesibilitate:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Puteți schimba funcția în Setări > Accesibilitate."</string>
@@ -1884,8 +1881,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplicația nu este disponibilă"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Momentan, aplicația <xliff:g id="APP_NAME_0">%1$s</xliff:g> nu este disponibilă. Aceasta este gestionată de <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Aflați mai multe"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulați întreruperea aplicației"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Activați profilul de serviciu?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Se vor activa aplicațiile dvs. de serviciu, notificările, datele și alte funcții ale profilului de serviciu"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Activați"</string>
@@ -2041,12 +2037,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Activați ecranul împărțit"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ecran de blocare"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Captură de ecran"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meniul Accesibilitate"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Bară cu legenda pentru <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> a fost adăugat la grupul RESTRICȚIONATE"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Serviciu"</string>
</resources>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 4821c7f..94029f5 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Все данные с устройства будут удалены"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Невозможно использовать приложение для администрирования. С устройства будут удалены все данные.\n\nЕсли у вас возникли вопросы, обратитесь к администратору."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Функция печати отключена приложением \"<xliff:g id="OWNER_APP">%s</xliff:g>\""</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Личные приложения временно заблокированы администратором"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Нажмите здесь, чтобы проверить их на соответствие правилам."</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Настройки планшетного ПК"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Настройки Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Вы <xliff:g id="NUMBER_0">%1$d</xliff:g> раз неверно указали графический ключ. После <xliff:g id="NUMBER_1">%2$d</xliff:g> неверных попыток для разблокировки телефона потребуется войти в аккаунт Google.\n\nПовтор через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Удалить"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Службы из пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, переведенные из фонового режима в активный, не будут получать разрешение while-in-use в будущих сборках на языке R. Перейдите на страницу go/r-bg-fgs-restriction и отправьте отчет об ошибке."</string>
<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="8306239551412868396">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте три секунды обе кнопки регулировки громкости.\n\nТекущая функция специальных возможностей:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\nВы можете изменить ее в разделе \"Настройки > Специальные возможности\"."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Приложение недоступно"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Приложение \"<xliff:g id="APP_NAME_0">%1$s</xliff:g>\" недоступно. Его работу ограничивает приложение \"<xliff:g id="APP_NAME_1">%2$s</xliff:g>\"."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Подробнее"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Возобновить работу приложения"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Включить рабочий профиль?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Будут включены корпоративные приложения, уведомления, данные и другие функции рабочего профиля."</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Включить"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Включить или выключить разделение экрана"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокированный экран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Скриншот"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню специальных возможностей"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Строка субтитров в приложении \"<xliff:g id="APP_NAME">%1$s</xliff:g>\"."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Приложение \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" помещено в категорию с ограниченным доступом."</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Личный"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Рабочий"</string>
</resources>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index df14036..73cf018 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ඔබගේ උපාංගය මකා දැමෙනු ඇත"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"පරිපාලක යෙදුම භාවිතා කළ නොහැකිය. ඔබේ උපාංගය දැන් මකා දමනු ඇත.\n\nඔබට ප්රශ්න තිබේ නම්, ඔබේ සංවිධානයේ පරිපාලකට අමතන්න."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> විසින් මුද්රණය කිරීම අබල කර ඇත."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"පුද්ගලික යෙදුම් පරිපාලකයෙකු විසින් අත්හිටුවා ඇත"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"ප්රතිපත්ති අනුකූලතාව පරීක්ෂා කිරීමට මෙහි තට්ටු කරන්න."</string>
<string name="me" msgid="6207584824693813140">"මම"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ටැබ්ලට විකල්ප"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV විකල්ප"</string>
@@ -1615,8 +1613,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"ඔබ වැරදියට <xliff:g id="NUMBER_0">%1$d</xliff:g> වතාවක් ඔබගේ අගුළු හැරීමේ රටාව ඇඳ ඇත. අසාර්ථක උත්සහ කිරීම් <xliff:g id="NUMBER_1">%2$d</xliff:g> න් පසුව, ඔබගේ ඊ-තැපැල් ලිපිනය භාවිතයෙන් ඔබගේ දුරකථනය අගුළු හැරීමට ඔබගෙන් අසයි.\n\n තත්පර <xliff:g id="NUMBER_2">%3$d</xliff:g> න් පසුව නැවත උත්සහ කරන්න."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ඉවත් කරන්න"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> වෙතින් පසුබිම ආරම්භ කරන ලද පෙරබිම් සේවාව අනාගත R තැනුම්වලදී භාවිතයේ අවසරය නැත. කරුණාකර go/r-bg-fgs-අවහිරතාව බලා දෝෂ වාර්තාවක් ගොනු කරන්න."</string>
<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="8306239551412868396">"කෙටිමඟ සක්රිය විට, හඬ බොත්තම් දෙකම තත්පර 3ක් අල්ලාගෙන සිටීමෙන් ප්රවේශ්යත අංගයක් ඇරඹේ.\n\n වත්මන් ප්රවේශ්යතා අංගය:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n සැකසීම් > ප්රවේශ්යතාව තුළ ඔබට අංගය වෙනස් කළ හැක."</string>
@@ -1854,8 +1851,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"යෙදුම නොතිබේ"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> මේ අවස්ථාවේදී ලබා ගත නොහැකිය. මෙය <xliff:g id="APP_NAME_1">%2$s</xliff:g> මගින් කළමනාකරණය කෙරේ."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"තව දැන ගන්න"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"යෙදුම විරාම කිරීම ඉවත් කරන්න"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"කාර්යාල පැතිකඩ ක්රියාත්මක කරන්නද?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ඔබගේ වැඩ යෙදුම්, දැනුම්දීම්, දත්ත සහ වෙනත් කාර්යාල පැතිකඩ විශේෂාංග ක්රියාත්මක කරනු ඇත"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ක්රියාත්මක කරන්න"</string>
@@ -2009,12 +2005,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"බෙදුම් තිරය ටොගල කරන්න"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"අගුලු තිරය"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"තිර රුව"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ප්රවේශ්යතා මෙනුව"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> හි සිරස්තල තීරුව."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> අවහිර කළ බාල්දියට දමා ඇත"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"පුද්ගලික"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"කාර්යාල"</string>
</resources>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index b0dc5f3..b86fc46 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Vaše zariadenie bude vymazané"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Daná aplikácia na správu sa nedá použiť. Vaše zariadenie bude vymazané.\n\nV prípade otázok kontaktujte správcu organizácie."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tlač zakázala aplikácia <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osobné aplikácie boli pozastavené správcom"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Klepnutím tu skontrolujte súlad s pravidlami."</string>
<string name="me" msgid="6207584824693813140">"Ja"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabletu"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti zariadenia Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"<xliff:g id="NUMBER_0">%1$d</xliff:g>-krát ste nesprávne nakreslili svoj bezpečnostný vzor. Po <xliff:g id="NUMBER_1">%2$d</xliff:g> ďalších neúspešných pokusoch sa zobrazí výzva na odomknutie telefónu pomocou e-mailového účtu.\n\n Skúste to znova o <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odstrániť"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Služba na popredí spustená na pozadí z balíka <xliff:g id="PACKAGENAME">%1$s</xliff:g> nebude mať v budúcich zostavách R povolenie Počas používania. Prejdite na go/r-bg-fgs-restriction a odošlite hlásenie chyby."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Zvýšiť hlasitosť nad odporúčanú úroveň?\n\nDlhodobé počúvanie pri vysokej hlasitosti môže poškodiť váš sluch."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Použiť skratku dostupnosti?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti.\n\n Aktuálna funkcia dostupnosti:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkciu môžete zmeniť v časti Nastavenia > Dostupnosť."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikácia nie je k dispozícii"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikácia <xliff:g id="APP_NAME_0">%1$s</xliff:g> nie je momentálne k dispozícii. Spravuje to aplikácia <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Ďalšie informácie"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Znova spustiť aplikáciu"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Zapnúť pracovný profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Pracovné aplikácie, upozornenia, dáta a ďalšie funkcie pracovného profilu sa zapnú"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Zapnúť"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Prepnúť rozdelenú obrazovku"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Uzamknúť obrazovku"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Snímka obrazovky"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Ponuka Dostupnosť"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Popis aplikácie <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Balík <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> bol vložený do kontajnera OBMEDZENÉ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Osobné"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Práca"</string>
</resources>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index bdd5925..bc2bc3a 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Podatki v napravi bodo izbrisani"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Skrbniške aplikacije ni mogoče uporabljati. Podatki v napravi bodo izbrisani.\n\nČe imate vprašanja, se obrnite na skrbnika organizacije."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Tiskanje je onemogočil pravilnik <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Osebne aplikacije je onemogočil skrbnik"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Dotaknite se tukaj, da preverite skladnost s pravilniki."</string>
<string name="me" msgid="6207584824693813140">"Jaz"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Možnosti tabličnega računalnika"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Možnosti naprave Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Vzorec za odklepanje ste <xliff:g id="NUMBER_0">%1$d</xliff:g>-krat napačno vnesli. Po nadaljnjih <xliff:g id="NUMBER_1">%2$d</xliff:g> neuspešnih poskusih boste pozvani, da odklenete telefon z Googlovimi podatki za prijavo.\n\nPoskusite znova čez <xliff:g id="NUMBER_2">%3$d</xliff:g> s."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Odstrani"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"V prihodnjih različicah R storitev v ospredju z zagonom iz ozadja iz paketa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ne bo imela dovoljenja med uporabo aplikacije. Oglejte si go/r-bg-fgs-restriction in pošljite poročilo o napakah."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ali želite povečati glasnost nad priporočeno raven?\n\nDolgotrajno poslušanje pri veliki glasnosti lahko poškoduje sluh."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Želite uporabljati bližnjico funkcij za ljudi s posebnimi potrebami?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami.\n\n Trenutna funkcija za ljudi s posebnimi potrebami:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Funkcijo lahko spremenite v »Nastavitve > Funkcije za ljudi s posebnimi potrebami«."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacija ni na voljo"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Aplikacija <xliff:g id="APP_NAME_0">%1$s</xliff:g> trenutno ni na voljo. To upravlja aplikacija <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Več o tem"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Prekliči začasno zaustavitev aplikacije"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Želite vklopiti delovni profil?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Vklopili boste svoje delovne aplikacije, obvestila, podatke in druge funkcije delovnega profila"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vklop"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Preklop razdeljenega zaslona"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Zaklenjen zaslon"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Posnetek zaslona"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Meni s funkcijami za ljudi s posebnimi potrebami"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Vrstica s podnapisi aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Paket <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> je bil dodan v segment OMEJENO"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Osebno"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Služba"</string>
</resources>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index fd8dda0..a353288 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Pajisja do të spastrohet"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Aplikacioni i administratorit nuk mund të përdoret. Pajisja jote tani do të fshihet.\n\nNëse ke pyetje, kontakto me administratorin e organizatës."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Printimi është çaktivizuar nga <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Aplikacionet personale janë pezulluar nga një administrator"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Trokit këtu për të kontrolluar përputhshmërinë me politikën."</string>
<string name="me" msgid="6207584824693813140">"Unë"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Opsionet e tabletit"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Opsionet e Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ke vizatuar <xliff:g id="NUMBER_0">%1$d</xliff:g> herë pa sukses motivin tënd. Pas <xliff:g id="NUMBER_1">%2$d</xliff:g> tentativave të tjera të pasuksesshme, do të të duhet ta shkyçësh telefonin duke përdorur një llogari mail-i.\n\n Provo sërish për <xliff:g id="NUMBER_2">%3$d</xliff:g> sekonda."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" - "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Hiq"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Shërbimi në plan të parë i nisur në sfond nga <xliff:g id="PACKAGENAME">%1$s</xliff:g> nuk do të ketë lejen e nevojshme gjatë përdorimit në ndërtimet e ardhshme R. Shiko go/r-bg-fgs-restriction dhe dërgo një raport të defekteve në kod."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Të ngrihet volumi mbi nivelin e rekomanduar?\n\nDëgjimi me volum të lartë për periudha të gjata mund të dëmtojë dëgjimin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Të përdoret shkurtorja e qasshmërisë?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie.\n\n Funksioni aktual i qasshmërisë:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Mund ta ndryshosh funksionin te Cilësimet > Qasshmëria."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Aplikacioni nuk ofrohet"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> nuk ofrohet në këtë moment. Kjo menaxhohet nga <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Mëso më shumë"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Anulo pauzën për aplikacionin"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Të aktivizohet profili i punës?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Aplikacionet e punës, njoftimet, të dhënat e tua dhe funksionet e tjera të profilit të punës do të aktivizohen"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivizo"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Kalo tek ekrani i ndarë"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekrani i kyçjes"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Pamja e ekranit"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menyja e qasshmërisë"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Shiriti i nëntitullit të <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> është vendosur në grupin E KUFIZUAR"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Puna"</string>
</resources>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index d82faa6..8ee644a 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -196,10 +196,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Уређај ће бити обрисан"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Не можете да користите ову апликацију за администраторе. Уређај ће сада бити обрисан.\n\nАко имате питања, контактирајте администратора организације."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Штампање је онемогућила апликација <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Администратор је суспендовао личне апликације"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Додирните овде да бисте проверили усклађеност са смерницама."</string>
<string name="me" msgid="6207584824693813140">"Ја"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Опције за таблет"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опције Android TV-а"</string>
@@ -1635,8 +1633,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Нацртали сте шаблон за откључавање нетачно <xliff:g id="NUMBER_0">%1$d</xliff:g> пута. После још <xliff:g id="NUMBER_1">%2$d</xliff:g> неуспешна(их) покушаја, од вас ће бити затражено да откључате телефон помоћу налога е-поште.\n\nПробајте поново за <xliff:g id="NUMBER_2">%3$d</xliff:g> секунде/и."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Уклони"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Услуга у првом плану са <xliff:g id="PACKAGENAME">%1$s</xliff:g> која је покренута у позадини неће имати дозволу током коришћења у будућим R верзијама. Посетите go/r-bg-fgs-restriction и пошаљите извештај о грешци."</string>
<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="8306239551412868396">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности.\n\n Актуелна функција приступачности:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Можете да промените функцију у одељку Подешавања > Приступачност."</string>
@@ -1884,8 +1881,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Апликација није доступна"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Апликација <xliff:g id="APP_NAME_0">%1$s</xliff:g> тренутно није доступна. <xliff:g id="APP_NAME_1">%2$s</xliff:g> управља доступношћу."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Сазнајте више"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Опозови паузирање апликације"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Да укључимо профил за Work?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Укључиће се пословне апликације, обавештења, подаци и друге функције профила за Work"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Укључи"</string>
@@ -2041,12 +2037,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Укључите/искључите подељени екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Закључани екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Снимак екрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Мени Приступачност"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Трака са насловима апликације <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> је додат у сегмент ОГРАНИЧЕНО"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Лични"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Пословни"</string>
</resources>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 9c7e1e5..577933e6 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Enheten kommer att rensas"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Det går inte att använda administratörsappen. Enheten rensas.\n\nKontakta organisationens administratör om du har några frågor."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Utskrift har inaktiverats av <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Administratören har stängt av privata appar"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Tryck här för att kontrollera att policyn följs."</string>
<string name="me" msgid="6207584824693813140">"Jag"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Alternativ för surfplattan"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Alternativ för Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Du har ritat ditt grafiska lösenord fel <xliff:g id="NUMBER_0">%1$d</xliff:g> gånger. Efter ytterligare <xliff:g id="NUMBER_1">%2$d</xliff:g> försök ombeds du låsa upp mobilen med hjälp av ett e-postkonto.\n\n Försök igen om <xliff:g id="NUMBER_2">%3$d</xliff:g> sekunder."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ta bort"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Förgrundstjänsten från <xliff:g id="PACKAGENAME">%1$s</xliff:g> som startades i bakgrunden får inte behörighet som gäller vid användning i framtida R-versioner. Besök go/r-bg-fgs-restriction och skicka en felrapport."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Vill du höja volymen över den rekommenderade nivån?\n\nAtt lyssna med stark volym långa stunder åt gången kan skada hörseln."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Vill du använda Aktivera tillgänglighet snabbt?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder.\n\n Aktuell tillgänglighetsfunktion:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Du kan ändra funktionen i Inställningar > Tillgänglighet."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Appen är inte tillgänglig"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> är inte tillgänglig just nu. Detta hanteras av <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Läs mer"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Återuppta app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Vill du aktivera jobbprofilen?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Jobbappar, aviseringar, data och andra funktioner i jobbprofilen aktiveras"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aktivera"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Aktivera och inaktivera delad skärm"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Låsskärm"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skärmdump"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Tillgänglighetsmenyn"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Textningsfält för <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> har placerats i hinken RESTRICTED"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Privat"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Jobb"</string>
</resources>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index f53efe0..a6ee366 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Data iliyomo kwenye kifaa chako itafutwa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Huwezi kutumia programu ya msimamizi. Sasa data iliyo kwenye kifaa chako itafutwa.\n\nIkiwa una maswali yoyote, wasiliana na msimamizi wa shirika lako."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Kipengele cha kuchapisha kimezimwa na <xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Programu za binafsi zimesimamishwa na msimamizi"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Gusa hapa ili uangalie utii wa sera."</string>
<string name="me" msgid="6207584824693813140">"Mimi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Chaguo za kompyuta ndogo"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Chaguo za Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Umekosea kuchora mchoro wako wa kufungua mara <xliff:g id="NUMBER_0">%1$d</xliff:g>. Baada ya majaribio <xliff:g id="NUMBER_1">%2$d</xliff:g> yasiyofaulu, utaombwa kufungua simu yako kwa kutumia akaunti ya barua pepe.\n\n Jaribu tena baada ya sekunde <xliff:g id="NUMBER_2">%3$d</xliff:g>."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Ondoa"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Huduma ya programu inayotumika iliyoanzishwa chinichini kwenye <xliff:g id="PACKAGENAME">%1$s</xliff:g> haitakuwa na ruhusa inapotumika katika miundo ijayo ya R. Tafadhali angalia go/r-bg-fgs-restriction na uwasilishe ripoti ya hitilafu."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ungependa kupandisha sauti zaidi ya kiwango kinachopendekezwa?\n\nKusikiliza kwa sauti ya juu kwa muda mrefu kunaweza kuharibu uwezo wako wa kusikia."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Ungependa kutumia njia ya mkato ya ufikivu?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa dakika 3 itafungua kipengele cha ufikivu.\n\n Kipengele cha ufikivu kilichopo kwa sasa:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Unaweza kubadilisha kipengele hiki katika Mipangilio > Zana za ufikivu."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Programu haipatikani"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> haipatikani kwa sasa. Inasimamiwa na <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Pata maelezo zaidi"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Acha kusimamisha programu"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ungependa kuwasha wasifu wa kazini?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Hatua hii itawasha data, arifa, programu za kazini, arifa na vipengele vingine vya wasifu wa kazini"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Washa"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Geuza Skrini Iliyogawanywa"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Skrini Iliyofungwa"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Picha ya skrini"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menyu ya Ufikivu"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Upau wa manukuu wa <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> kimewekwa katika kikundi KILICHODHIBITIWA"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Binafsi"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Kazini"</string>
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index c7c4ea3..a56465f 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"சாதனத் தரவு அழிக்கப்படும்"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"நிர்வாகி ஆப்ஸை உபயோகிக்க முடியாது. இப்போது, உங்கள் சாதனம் ஆரம்ப நிலைக்கு மீட்டமைக்கப்படும்.\n\nஏதேனும் கேள்விகள் இருப்பின், உங்கள் நிறுவனத்தின் நிர்வாகியைத் தொடர்புகொள்ளவும்."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"பிரிண்ட் செய்வதை <xliff:g id="OWNER_APP">%s</xliff:g> தடுத்துள்ளது."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"தனிப்பட்ட ஆப்ஸை நிர்வாகி ஒருவர் இடைநிறுத்தியுள்ளார்"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"கொள்கை இணக்கத்தைச் சரிபார்ப்பதற்கு இங்கே தட்டவும்."</string>
<string name="me" msgid="6207584824693813140">"நான்"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"டேப்லெட் விருப்பங்கள்"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV விருப்பத்தேர்வுகள்"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"திறப்பதற்கான வடிவத்தை <xliff:g id="NUMBER_0">%1$d</xliff:g> முறை தவறாக வரைந்துள்ளீர்கள். மேலும் <xliff:g id="NUMBER_1">%2$d</xliff:g> தோல்வி முயற்சிகளுக்குப் பிறகு, மின்னஞ்சல் கணக்கைப் பயன்படுத்தி உங்கள் மொபைலைத் திறக்கக் கேட்கப்படுவீர்கள்.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> வினாடிகள் கழித்து முயற்சிக்கவும்."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"அகற்று"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> இல் இருந்து பின்னணியில் தொடங்கப்பட்ட முன்புலச் சேவைக்கு, வரவுள்ள R பதிப்புகளில் உபயோகத்தின்போது மட்டுமான அனுமதி இருக்காது. go/r-bg-fgs-restriction என்பதைப் பார்த்து பிழை அறிக்கை ஒன்றைச் சமர்ப்பிக்கவும்."</string>
<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="8306239551412868396">"ஷார்ட்கட் இயக்கத்தில் இருந்தால், இரண்டு ஒலியளவு பொத்தான்களையும் 3 வினாடிகள் அழுத்தி, அணுகல்தன்மை அம்சத்தை இயக்கலாம்.\n\n தற்போதைய அணுகல்தன்மை அம்சம்:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n அமைப்புகள் > அணுகல்தன்மை என்பதற்குச் சென்று, அம்சத்தை மாற்றலாம்."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ஆப்ஸை உபயோகிக்க இயலாது"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"இப்போது <xliff:g id="APP_NAME_0">%1$s</xliff:g> ஆப்ஸை உபயோகிக்க இயலாது. இதை <xliff:g id="APP_NAME_1">%2$s</xliff:g> நிர்வகிக்கிறது."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"மேலும் அறிக"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ஆப்ஸ் இயக்கு"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"பணிச் சுயவிவரத்தை ஆன் செய்யவா?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"பணி ஆப்ஸ், அறிவிப்புகள், தரவு மற்றும் பிற பணிச் சுயவிவர அம்சங்கள் ஆன் செய்யப்படும்"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"இயக்கு"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"திரைப் பிரிப்பை நிலைமாற்று"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"பூட்டுத் திரை"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ஸ்கிரீன்ஷாட்"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"அணுகல்தன்மை மெனு"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸின் தலைப்புப் பட்டி."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> என்பதை வரம்பிடப்பட்ட பக்கெட்திற்குள் சேர்க்கப்பட்டது"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"தனிப்பட்ட சுயவிவரம்"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"பணிச் சுயவிவரம்"</string>
</resources>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 9c77ccd..7a0aece 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"మీ పరికరంలోని డేటా తొలగించబడుతుంది"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"నిర్వాహక యాప్ ఉపయోగించడం సాధ్యపడదు. మీ పరికరంలోని డేటా ఇప్పుడు తొలగించబడుతుంది.\n\nమీకు ప్రశ్నలు ఉంటే, మీ సంస్థ యొక్క నిర్వాహకులను సంప్రదించండి."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"ముద్రణ <xliff:g id="OWNER_APP">%s</xliff:g> ద్వారా నిలిపివేయబడింది."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"అడ్మిన్ ద్వారా వ్యక్తిగత యాప్లు సస్పెండ్ చేయబడ్డాయి"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"పాలసీ పాటించబడుతోందో లేదో తనిఖీ చేయడానికి ఇక్కడ ట్యాప్ చేయండి."</string>
<string name="me" msgid="6207584824693813140">"నేను"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"టాబ్లెట్ ఎంపికలు"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV ఎంపికలు"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఇమెయిల్ ఖాతాను ఉపయోగించి మీ ఫోన్ను అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని అడుగుతారు.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"తీసివేయి"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> నుండి, బ్యాక్గ్రౌండ్లో ప్రారంభమైన ఫోర్ గ్రౌండ్ సేవకు భవిష్యత్తు R బిల్డ్స్లో \'ఉపయోగంలో వున్నప్పుడు\' అనుమతి ఉండదు. దయచేసి go/r-bg-fgs-restrictionను చూసి బగ్ నివేదికను ఫైల్ చేయండి."</string>
<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="8306239551412868396">"షార్ట్కట్ ఆన్లో ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కితే యాక్సెస్ సామర్థ్య ఫీచర్ ప్రారంభం అవుతుంది.\n\n ప్రస్తుత యాక్సెస్ సామర్థ్య ఫీచర్:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n సెట్టింగ్లు > యాక్సెస్ సామర్థ్యంలో మీరు ఫీచర్ను మార్చవచ్చు."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"యాప్ అందుబాటులో లేదు"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ప్రస్తుతం అందుబాటులో లేదు. ఇది <xliff:g id="APP_NAME_1">%2$s</xliff:g> ద్వారా నిర్వహించబడుతుంది."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"మరింత తెలుసుకోండి"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"యాప్పై వున్న పాజ్ను తొలగించండి"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"కార్యాలయ ప్రొఫైల్ని ఆన్ చేయాలా?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"మీ కార్యాలయ యాప్లు, నోటిఫికేషన్లు, డేటా మరియు ఇతర కార్యాలయ ప్రొఫైల్ ఫీచర్లు ఆన్ చేయబడతాయి"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"ఆన్ చేయి"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"స్క్రీన్ విభజనను టోగుల్ చేయి"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"యాక్సెసిబిలిటీ మెను"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> క్యాప్షన్ బార్."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> పరిమితం చేయబడిన బకెట్లో ఉంచబడింది"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"వ్యక్తిగతం"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"కార్యాలయం"</string>
</resources>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index efff25b..98f2d88 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"ระบบจะลบข้อมูลในอุปกรณ์ของคุณ"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"ใช้แอปผู้ดูแลระบบนี้ไม่ได้ ขณะนี้ระบบจะลบข้อมูลในอุปกรณ์ของคุณ\n\nโปรดติดต่อผู้ดูแลระบบขององค์กรหากมีคำถาม"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> ปิดใช้การพิมพ์แล้ว"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ผู้ดูแลระบบได้ระงับแอปส่วนตัวไว้"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"แตะที่นี่เพื่อตรวจสอบการปฏิบัติตามข้อกำหนดของนโยบาย"</string>
<string name="me" msgid="6207584824693813140">"ฉัน"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ตัวเลือกของแท็บเล็ต"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"ตัวเลือกของ Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"คุณวาดรูปแบบการปลดล็อกไม่ถูกต้อง <xliff:g id="NUMBER_0">%1$d</xliff:g> ครั้งแล้ว หากทำไม่สำเร็จอีก <xliff:g id="NUMBER_1">%2$d</xliff:g> ครั้ง ระบบจะขอให้คุณปลดล็อกโทรศัพท์โดยใช้ับัญชีอีเมล\n\n โปรดลองอีกครั้งในอีก <xliff:g id="NUMBER_2">%3$d</xliff:g> วินาที"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ลบ"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"บริการที่ทำงานอยู่เบื้องหน้าซึ่งเริ่มขึ้นในเบื้องหลังจาก <xliff:g id="PACKAGENAME">%1$s</xliff:g> จะไม่มีสิทธิ์ขณะใช้งานใน R บิลด์ต่อๆ ไป โปรดดู go/r-bg-fgs-restriction และส่งรายงานข้อบกพร่อง"</string>
<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="8306239551412868396">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มเป็นเวลา 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ\n\n ฟีเจอร์การช่วยเหลือพิเศษปัจจุบัน:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n คุณสามารถเปลี่ยนฟีเจอร์ในการตั้งค่า > การช่วยเหลือพิเศษ"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"แอปไม่พร้อมใช้งาน"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"เปิด <xliff:g id="APP_NAME_0">%1$s</xliff:g> ไม่ได้ในขณะนี้ แอปนี้จัดการโดย <xliff:g id="APP_NAME_1">%2$s</xliff:g>"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"ดูข้อมูลเพิ่มเติม"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ยกเลิกการหยุดแอปชั่วคราว"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"เปิดโปรไฟล์งานไหม"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"ระบบจะเปิดแอปงาน การแจ้งเตือน ข้อมูล และฟีเจอร์อื่นๆ ในโปรไฟล์งาน"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"เปิด"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"เปิด/ปิดการแบ่งหน้าจอ"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"หน้าจอล็อก"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"ภาพหน้าจอ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"เมนูการช่วยเหลือพิเศษ"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"แถบคำบรรยาย <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"ใส่ <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ในที่เก็บข้อมูลที่ถูกจำกัดแล้ว"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string>
</resources>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 7cfa7b0..c38a6d5 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Buburahin ang iyong device"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Hindi magamit ang admin app. Mabubura na ang iyong device.\n\nKung mayroon kang mga tanong, makipag-ugnayan sa admin ng iyong organisasyon."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Na-disable ng <xliff:g id="OWNER_APP">%s</xliff:g> ang pag-print."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Sinuspinde ng isang admin ang mga personal na app"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Mag-tap dito para matingnan ang pagsunod sa patakaran."</string>
<string name="me" msgid="6207584824693813140">"Ako"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Mga pagpipilian sa tablet"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Mga opsyon sa Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Naguhit mo nang hindi tama ang iyong pattern sa pag-unlock nang <xliff:g id="NUMBER_0">%1$d</xliff:g> (na) beses. Pagkatapos ng <xliff:g id="NUMBER_1">%2$d</xliff:g> pang hindi matagumpay na pagtatangka, hihilingin sa iyong i-unlock ang telepono mo gamit ang isang email account.\n\n Subukang muli sa loob ng <xliff:g id="NUMBER_2">%3$d</xliff:g> (na) segundo."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Alisin"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ang sinimulan sa background na serbisyo sa foreground mula sa <xliff:g id="PACKAGENAME">%1$s</xliff:g> ay hindi magkakaroon ng pahintulot habang ginagamit sa mga R build sa hinaharap. Pakipuntahan ang go/r-bg-fgs-restriction at maghain ng bugreport."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Lakasan ang volume nang lagpas sa inirerekomendang antas?\n\nMaaaring mapinsala ng pakikinig sa malakas na volume sa loob ng mahahabang panahon ang iyong pandinig."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Gagamitin ang Shortcut sa Pagiging Accessible?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume sa loob ng 3 segundo.\n\n Kasalukuyang feature ng pagiging naa-access:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Maaari mong baguhin ang feature sa Mga Setting > Pagiging Accessible."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Hindi available ang app"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Hindi available ang <xliff:g id="APP_NAME_0">%1$s</xliff:g> sa ngayon. Pinamamahalaan ito ng <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Matuto pa"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"I-unpause ang app"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"I-on ang profile sa trabaho?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Mao-on ang iyong mga app sa trabaho, notification, data, at iba pang feature sa profile sa trabaho"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"I-on"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"I-toggle ang Split Screen"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Lock Screen"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Screenshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Menu ng Accessibility"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Caption bar ng <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Inilagay ang <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> sa PINAGHIHIGPITANG bucket"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Personal"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Trabaho"</string>
</resources>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index b47eb4b..5e09309 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Cihazınız silinecek"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Yönetim uygulaması kullanılamıyor. Cihazınız şimdi silinecek.\n\nSorularınız varsa kuruluşunuzun yöneticisine başvurun."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Yazdırma işlemi <xliff:g id="OWNER_APP">%s</xliff:g> tarafından devre dışı bırakıldı."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Kişisel uygulamalar bir yönetici tarafından askıya alındı"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Politika uyumluluğunu kontrol etmek için buraya dokunun."</string>
<string name="me" msgid="6207584824693813140">"Ben"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tablet seçenekleri"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV seçenekleri"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Kilit açma deseninizi <xliff:g id="NUMBER_0">%1$d</xliff:g> kez yanlış çizdiniz. <xliff:g id="NUMBER_1">%2$d</xliff:g> başarısız denemeden sonra telefonunuzu bir e-posta hesabı kullanarak açmanız istenir.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> saniye içinde tekrar deneyin."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Kaldır"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"<xliff:g id="PACKAGENAME">%1$s</xliff:g> paketinden ön plan hizmetini başlatan arka plan, sonraki R derlemelerinde kullanım sırasında iznine sahip olmayacak. Lütfen go/r-bg-fgs-restriction sayfasına bakıp hata raporu girin."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Ses seviyesi önerilen düzeyin üzerine yükseltilsin mi?\n\nUzun süre yüksek ses seviyesinde dinlemek işitme duyunuza zarar verebilir."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Erişilebilirlik Kısayolu Kullanılsın mı?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Kısayol açık olduğunda, ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır.\n\n Geçerli erişilebilirlik özelliği:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Özelliği, Ayarlar > Erişilebilirlik seçeneğinden değiştirebilirsiniz."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Uygulama kullanılamıyor"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> uygulaması şu anda kullanılamıyor. Uygulamanın kullanım durumu <xliff:g id="APP_NAME_1">%2$s</xliff:g> tarafından yönetiliyor."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Daha fazla bilgi"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Uygulamanın duraklatmasını kaldır"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"İş profili açılsın mı?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"İş uygulamalarınız, bildirimleriniz, verileriniz ve diğer iş profili özellikleriniz açılacak"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Aç"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bölünmüş Ekranı aç/kapat"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Kilit Ekranı"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Ekran görüntüsü"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Erişilebilirlik Menüsü"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasının başlık çubuğu."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> KISITLANMIŞ gruba yerleştirildi"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Kişisel"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"İş"</string>
</resources>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 22aa199..1096f97 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -198,10 +198,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"З вашого пристрою буде стерто всі дані"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Не можна запускати додаток для адміністраторів. Буде відновлено заводські налаштування пристрою.\n\nЯкщо у вас є запитання, зв’яжіться з адміністратором своєї організації."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Додаток <xliff:g id="OWNER_APP">%s</xliff:g> вимкнув друк."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Особисті додатки заблоковано адміністратором"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Натисніть тут, щоб перевірити відповідність правилам."</string>
<string name="me" msgid="6207584824693813140">"Я"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Парам. пристрою"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Опції Android TV"</string>
@@ -1657,8 +1655,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ключ розблокування неправильно намальовано стільки разів: <xliff:g id="NUMBER_0">%1$d</xliff:g>. У вас є ще стільки спроб: <xliff:g id="NUMBER_1">%2$d</xliff:g>. У разі невдачі з’явиться запит розблокувати телефон за допомогою облікового запису електронної пошти.\n\n Повторіть спробу через <xliff:g id="NUMBER_2">%3$d</xliff:g> сек."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" – "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Вилучити"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Активний сервіс пакета <xliff:g id="PACKAGENAME">%1$s</xliff:g>, запущений у фоновому режимі, не матиме дозволу \"Коли додаток використовується\" в майбутніх складаннях R. Перегляньте go/r-bg-fgs-restriction і надішліть звіт про помилки."</string>
<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="8306239551412868396">"Коли ярлик увімкнено, після натискання обох клавіш гучності й утримування їх протягом 3 секунд увімкнеться функція спеціальних можливостей.\n\n Поточна функція спеціальних можливостей:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Цю функцію можна змінити в меню \"Налаштування\" > \"Спеціальні можливості\"."</string>
@@ -1916,8 +1913,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Додаток недоступний"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"Додаток <xliff:g id="APP_NAME_0">%1$s</xliff:g> зараз недоступний. Керує додаток <xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Докладніше"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Відновити доступ до додатка"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Увімкнути робочий профіль?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Додатки, сповіщення, дані й інші функції робочого профілю буде ввімкнено"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Увімкнути"</string>
@@ -2075,12 +2071,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Розділити екран"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Заблокувати екран"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Знімок екрана"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Меню спеціальних можливостей"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Смуга із субтитрами для додатка <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Пакет \"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>\" додано в сегмент з обмеженнями"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Особисте"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Робоче"</string>
</resources>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index a88d6c5..4c33191 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"آپ کا آلہ صاف کر دیا جائے گا"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"منتظم کی ایپ استعمال نہیں کی جا سکتی۔ آپ کا آلہ اب مٹا دیا جائے گا۔\n\nاگر آپ کے سوالات ہیں تو اپنی تنظیم کے منتظم سے رابطہ کریں۔"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> نے پرنٹنگ کو غیر فعال کر دیا ہے۔"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"ایک منتظم کے ذریعہ ذاتی ایپس معطل کر دی گئی ہیں"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"پالیسی کی تعمیل کو چیک کرنے کے ليے یہاں تھپتھپائیں۔"</string>
<string name="me" msgid="6207584824693813140">"میں"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"ٹیبلیٹ کے اختیارات"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV اختیارات"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"آپ نے اپنا غیر مقفل کرنے کا پیٹرن <xliff:g id="NUMBER_0">%1$d</xliff:g> بار غلط طریقے سے ڈرا کیا ہے۔ <xliff:g id="NUMBER_1">%2$d</xliff:g> مزید ناکام کوششوں کے بعد، آپ سے ایک ای میل اکاؤنٹ استعمال کرکے اپنا فون غیر مقفل کرنے کو کہا جائے گا۔\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> سیکنڈ میں دوبارہ کوشش کریں۔"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"ہٹائیں"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"پس منظر <xliff:g id="PACKAGENAME">%1$s</xliff:g> سے شروع کی گئی پیش منظر کی سروس کو مستقبل کے R بلڈز میں استعمال کے دوران اجازت نہیں ہوگی۔ براہ کرم go/r-bg-fgs-restriction دیکھیں اور بگ رپورٹ دائر کریں۔"</string>
<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="8306239551412868396">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔\n\n موجودہ ایکسیسبیلٹی خصوصیت:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n آپ خصوصیت کو ترتیبات > ایکسیسبیلٹی میں جا کر تبدیل کر سکتے ہیں۔"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"ایپ دستیاب نہیں ہے"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ابھی دستیاب نہیں ہے۔ یہ <xliff:g id="APP_NAME_1">%2$s</xliff:g> کے زیر انتظام ہے۔"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"مزید جانیں"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"ایپ کو غیر موقوف کریں"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"دفتری پروفائل آن کریں؟"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"آپ کی دفتری ایپس، اطلاعات، ڈیٹا اور دفتری پروفائل کی دیگر خصوصیات آن کر دی جائیں گی"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"آن کریں"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"اسپلٹ اسکرین ٹوگل کریں"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"مقفل اسکرین"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"اسکرین شاٹ"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"ایکسیسبیلٹی مینو"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> کی کیپشن بار۔"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> کو پابند کردہ بکٹ میں رکھ دیا گیا ہے"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"ذاتی"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"دفتر"</string>
</resources>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a08b178..23873b5 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Qurilmangizdagi ma’lumotlar o‘chirib tashlanadi"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Administrator ilovasini ishlatib bo‘lmaydi. Qurilmada barcha ma’lumotlar o‘chirib tashlanadi.\n\nSavollaringiz bo‘lsa, administrator bilan bog‘laning."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Chop etish funksiyasi <xliff:g id="OWNER_APP">%s</xliff:g> tomonidan faolsizlantirilgan."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Shaxsiy ilovalar administrator tomonidan faolsizlantirildi"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Siyosatga muvofiqligini tekshirish uchun shu yerga bosing."</string>
<string name="me" msgid="6207584824693813140">"Men"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Planshet sozlamalari"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV parametrlari"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Siz grafik kalitni <xliff:g id="NUMBER_0">%1$d</xliff:g> marta noto‘g‘ri chizdingiz. <xliff:g id="NUMBER_1">%2$d</xliff:g> marta muvaffaqiyatsiz urinishdan so‘ng, sizdan e-pochtangizdan foydalanib, telefon qulfini ochishingiz so‘raladi.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> soniyadan so‘ng yana urinib ko‘ring."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Olib tashlash"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Fonda faol <xliff:g id="PACKAGENAME">%1$s</xliff:g> xizmatini ishga tushirish uchun kelgusi R nashrlarida ishlatilayotganda ruxsat berish imkoniyati boʻlmaydi. go/r-bg-fgs-restriction sahifasiga kiring va xatolik hisobotini yuboring."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Tovush balandligi tavsiya etilgan darajadan ham yuqori qilinsinmi?\n\nUzoq vaqt davomida baland ovozda tinglash eshitish qobiliyatingizga salbiy ta’sir ko‘rsatishi mumkin."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Tezkor ishga tushirishdan foydalanilsinmi?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala ovoz balandligini boshqarish tugmasini 3 soniya bosib turing.\n\n Joriy maxsus imkoniyatlar funksiyasi:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bu funksiyani Sozlamalar > Maxsus imkoniyatlar orqali o‘zgartirish mumkin."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Ilova ishlamayapti"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> ishlamayapti. Uning ishlashini <xliff:g id="APP_NAME_1">%2$s</xliff:g> cheklamoqda."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Batafsil"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Ilovani ishga tushirish"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Ishchi profil yoqilsinmi?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Ishchi ilovalar, bildirishnomalar, ma’lumotlar va boshqa ishchi profil imkoniyatlari yoqiladi"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Yoqish"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Ekranni ikkiga ajratish tugmasi"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Ekran qulfi"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Skrinshot"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Maxsus imkoniyatlar menyusi"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g> taglavhalar paneli."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> cheklangan turkumga joylandi"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Shaxsiy"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Ish"</string>
</resources>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index db55613..1ed30d7 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Thiết bị của bạn sẽ bị xóa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Không thể sử dụng ứng dụng quản trị. Thiết bị của bạn sẽ bị xóa ngay bây giờ.\n\nHãy liên hệ với quản trị viên của tổ chức nếu bạn có thắc mắc."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"<xliff:g id="OWNER_APP">%s</xliff:g> đã tắt tính năng in."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Các ứng dụng cá nhân đã bị một quản trị viên tạm ngưng"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Nhấn vào đây để kiểm tra tính tuân thủ đối với chính sách."</string>
<string name="me" msgid="6207584824693813140">"Tôi"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Tùy chọn máy tính bảng"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Tùy chọn dành cho Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Bạn đã <xliff:g id="NUMBER_0">%1$d</xliff:g> lần vẽ không chính xác hình mở khóa của mình. Sau <xliff:g id="NUMBER_1">%2$d</xliff:g> lần thử không thành công nữa, bạn sẽ được yêu cầu mở khóa điện thoại bằng tài khoản email.\n\n Vui lòng thử lại sau <xliff:g id="NUMBER_2">%3$d</xliff:g> giây."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Xóa"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Dịch vụ trên nền trước đã bắt đầu ở nền từ <xliff:g id="PACKAGENAME">%1$s</xliff:g> sẽ không có quyền khi đang sử dụng trong các bản dựng R trong tương lai. Vui lòng xem go/r-bg-fgs-restriction và gửi báo cáo lỗi."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Bạn tăng âm lượng lên quá mức khuyên dùng?\n\nViệc nghe ở mức âm lượng cao trong thời gian dài có thể gây tổn thương thính giác của bạn."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sử dụng phím tắt Hỗ trợ tiếp cận?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Khi phím tắt được bật, nhấn cả hai nút âm lượng trong 3 giây sẽ bắt đầu một tính năng trợ năng.\n\n Tính năng trợ năng hiện tại:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Bạn có thể thay đổi tính năng trong Cài đặt > Trợ năng."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Ứng dụng không sử dụng được"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g> hiện không sử dụng được. Chính sách này do <xliff:g id="APP_NAME_1">%2$s</xliff:g> quản lý."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Tìm hiểu thêm"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Mở lại ứng dụng"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Bạn muốn bật hồ sơ công việc?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Ứng dụng công việc, thông báo, dữ liệu và các tính năng khác của hồ sơ công việc sẽ được bật"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Bật"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Bật/tắt chế độ chia đôi màn hình"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khóa màn hình"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Chụp ảnh màn hình"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Trình đơn Hỗ trợ tiếp cận"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Thanh phụ đề của <xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"Đã đưa <xliff:g id="PACKAGE_NAME">%1$s</xliff:g> vào bộ chứa BỊ HẠN CHẾ"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Cá nhân"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Cơ quan"</string>
</resources>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 08d2326..7671063 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"系统将清空您的设备"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"无法使用管理应用,系统现在将清空您的设备。\n\n如有疑问,请与您所在单位的管理员联系。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"“<xliff:g id="OWNER_APP">%s</xliff:g>”已停用打印功能。"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理员已暂停个人应用"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"点按此处即可检查政策合规性。"</string>
<string name="me" msgid="6207584824693813140">"我"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板电脑选项"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 选项"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已连续 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次画错解锁图案。如果再尝试 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次后仍不成功,系统就会要求您使用自己的电子邮件帐号解锁手机。\n\n请在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒后重试。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"删除"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"在未来的 R 版本中,在后台启动的 <xliff:g id="PACKAGENAME">%1$s</xliff:g> 中的前台服务将不具有仅在使用时授予的权限。请访问 go/r-bg-fgs-restriction 并提交错误报告。"</string>
<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="8306239551412868396">"开启快捷方式后,同时按下两个音量按钮 3 秒钟即可启动所设定的无障碍功能。\n\n当前设定的无障碍功能:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如需更改设定的功能,请依次转到“设置”>“无障碍”。"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"应用无法使用"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"<xliff:g id="APP_NAME_0">%1$s</xliff:g>目前无法使用。该应用是由<xliff:g id="APP_NAME_1">%2$s</xliff:g>所管理。"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"了解详情"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暂停应用"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"要开启工作资料吗?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"您的工作应用、通知、数据及其他工作资料功能将会开启"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"开启"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"开启/关闭分屏"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"锁定屏幕"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"屏幕截图"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"无障碍功能菜单"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"<xliff:g id="APP_NAME">%1$s</xliff:g>的标题栏。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已被放入受限存储分区"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"个人"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string>
</resources>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index ea106c6c..89bea07 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"您的裝置將被清除"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理員應用程式。系統會現在清除您的裝置。\n\n如有任何疑問,請聯絡您的機構管理員。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」暫停了列印。"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理員已停用個人應用程式"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"輕按這裡查看應用程式是否符合政策要求。"</string>
<string name="me" msgid="6207584824693813140">"我本人"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"您已畫錯解鎖圖案 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統會要求您透過電郵帳戶解開上鎖的手機。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"移除"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"從「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」啟動前景服務的背景將不會在未來的 R 版本中提供「僅在使用此應用程式時允許」權限。請參閱 go/r-bg-fgs-restriction,提交錯誤報告。"</string>
<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="8306239551412868396">"快速鍵開啟後,同時按住音量按鈕 3 秒,無障礙功能便會啟用。\n\n目前的無障礙功能:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n如要變更功能,請前往「設定」>「無障礙功能」。"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"目前無法使用此應用程式"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用 <xliff:g id="APP_NAME_0">%1$s</xliff:g>。此應用程式是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暫停應用程式"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作設定檔嗎?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟您的工作應用程式、通知、資料和其他工作設定檔功能"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割螢幕"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"將畫面上鎖"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"螢幕截圖"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"無障礙功能選單"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> 已納入受限制的儲存區"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"公司"</string>
</resources>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 7065181..c95ae37 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"你的裝置資料將遭到清除"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"無法使用管理應用程式,系統現在將清除你裝置中的資料。\n\n如有任何問題,請與貴機構的管理員聯絡。"</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"「<xliff:g id="OWNER_APP">%s</xliff:g>」已停用列印功能。"</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"管理員已將個人應用程式設為暫停使用"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"輕觸這裡即可查看政策違規問題。"</string>
<string name="me" msgid="6207584824693813140">"我"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"平板電腦選項"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Android TV 選項"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"你的解鎖圖案已畫錯 <xliff:g id="NUMBER_0">%1$d</xliff:g> 次,如果再嘗試 <xliff:g id="NUMBER_1">%2$d</xliff:g> 次仍未成功,系統就會要求你透過電子郵件帳戶解除手機的鎖定狀態。\n\n請在 <xliff:g id="NUMBER_2">%3$d</xliff:g> 秒後再試一次。"</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"移除"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"來自「<xliff:g id="PACKAGENAME">%1$s</xliff:g>」的背景啟動前景服務不會具備未來 R 版本的使用狀態權限。請前往 go/r-bg-fgs-restriction 並提交錯誤報告。"</string>
<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="8306239551412868396">"啟用捷徑功能後,只要同時按下兩個音量鍵 3 秒,就能啟動無障礙功能。\n\n 目前設定的無障礙功能為:\n<xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n 如要變更設定的功能,請依序輕觸 [設定] > [無障礙設定]。"</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"應用程式目前無法使用"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"目前無法使用「<xliff:g id="APP_NAME_0">%1$s</xliff:g>」。這項設定是由「<xliff:g id="APP_NAME_1">%2$s</xliff:g>」管理。"</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"瞭解詳情"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"取消暫停應用程式"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"要開啟工作資料夾嗎?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"系統將開啟你的辦公應用程式、通知、資料和其他工作資料夾功能"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"開啟"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"切換分割畫面模式"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"螢幕鎖定"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"擷取螢幕畫面"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"無障礙選單"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」的說明文字列。"</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"已將「<xliff:g id="PACKAGE_NAME">%1$s</xliff:g>」移入受限制的值區"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"個人"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"工作"</string>
</resources>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 1cb67e1..0cd669b 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -194,10 +194,8 @@
<string name="factory_reset_warning" msgid="6858705527798047809">"Idivayisi yakho izosulwa"</string>
<string name="factory_reset_message" msgid="2657049595153992213">"Uhlelo lokusebenza lomlawuli alikwazi ukusetshenziswa. Idivayisi yakho manje izosuswa.\n\nUma unemibuzo, xhumana nomlawuli wezinhlangano zakho."</string>
<string name="printing_disabled_by" msgid="3517499806528864633">"Ukuphrinta kukhutshazwe nge-<xliff:g id="OWNER_APP">%s</xliff:g>."</string>
- <!-- no translation found for personal_apps_suspended_notification_title (6551578720258229430) -->
- <skip />
- <!-- no translation found for personal_apps_suspended_notification_text (8321053338614244297) -->
- <skip />
+ <string name="personal_apps_suspended_notification_title" msgid="6551578720258229430">"Izinhlelo zokusebenza zimiswe okwesikhashana ngumlawuli"</string>
+ <string name="personal_apps_suspended_notification_text" msgid="8321053338614244297">"Thepha lapha ukuze uhlole ukuthobelana kwenqubomgomo."</string>
<string name="me" msgid="6207584824693813140">"Mina"</string>
<string name="power_dialog" product="tablet" msgid="8333207765671417261">"Okukhethwa kukho kwethebhulethi"</string>
<string name="power_dialog" product="tv" msgid="7792839006640933763">"Izinketho ze-Android TV"</string>
@@ -1613,8 +1611,7 @@
<string name="kg_failed_attempts_almost_at_login" product="default" msgid="5270861875006378092">"Ukulayisha ungenisa iphathini yakho yokuvula ngendlela engalungile izikhathi ezi-<xliff:g id="NUMBER_0">%1$d</xliff:g> Emva kweminye imizamo engu-<xliff:g id="NUMBER_1">%2$d</xliff:g>, uzocelwa ukuvula ifoni yakho usebenzisa ukungena ngemvume ku-Google\n\n Zame futhi emumva kwengu- <xliff:g id="NUMBER_2">%3$d</xliff:g> amasekhondi."</string>
<string name="kg_text_message_separator" product="default" msgid="4503708889934976866">" — "</string>
<string name="kg_reordering_delete_drop_target_text" msgid="2034358143731750914">"Susa"</string>
- <!-- no translation found for allow_while_in_use_permission_in_fgs (4101339676785053656) -->
- <skip />
+ <string name="allow_while_in_use_permission_in_fgs" msgid="4101339676785053656">"Ingemuva eqalise isevisi yasemuva kusuka ku-<xliff:g id="PACKAGENAME">%1$s</xliff:g> ngeke ithole imvume yokusebenzisa yesikhathi ekwakheni kwe-R ezayo. Sicela ubone i-go/r-bg-fgs-restriction bese ufayele umbiko wesiphazamiso."</string>
<string name="safe_media_volume_warning" product="default" msgid="3751676824423049994">"Khuphukisa ivolumu ngaphezu kweleveli enconyiwe?\n\nUkulalela ngevolumu ephezulu izikhathi ezide kungahle kulimaze ukuzwa kwakho."</string>
<string name="accessibility_shortcut_warning_dialog_title" msgid="4017995837692622933">"Sebenzisa isinqamuleli sokufinyelela?"</string>
<string name="accessibility_shortcut_toogle_warning" msgid="8306239551412868396">"Uma kuvulwe isinqamuleli, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqala isici sokufinyelela.\n\n Isici samanje sokufinyelela:\n <xliff:g id="SERVICE_NAME">%1$s</xliff:g>\n\n Ungashintsha isici kuzilungiselelo > Ukufinyelela."</string>
@@ -1852,8 +1849,7 @@
<string name="app_suspended_title" msgid="888873445010322650">"Uhlelo lokusebenza alutholakali"</string>
<string name="app_suspended_default_message" msgid="6451215678552004172">"I-<xliff:g id="APP_NAME_0">%1$s</xliff:g> ayitholakali okwamanje. Lokhu kuphethwe i-<xliff:g id="APP_NAME_1">%2$s</xliff:g>."</string>
<string name="app_suspended_more_details" msgid="211260942831587014">"Funda kabanzi"</string>
- <!-- no translation found for app_suspended_unsuspend_message (1665438589450555459) -->
- <skip />
+ <string name="app_suspended_unsuspend_message" msgid="1665438589450555459">"Susa ukuphumuza uhlelo lokusebenza"</string>
<string name="work_mode_off_title" msgid="5503291976647976560">"Vula iphrofayela yomsebenzi?"</string>
<string name="work_mode_off_message" msgid="8417484421098563803">"Izinhlelo zakho zokusebenza zomsebenzi, izaziso, idatha, nezinye izici zephrofayela yomsebenzi kuzovulwa"</string>
<string name="work_mode_turn_on" msgid="3662561662475962285">"Vula"</string>
@@ -2007,12 +2003,9 @@
<string name="accessibility_system_action_toggle_split_screen_label" msgid="6626177163849387748">"Guqula ukuhlukanisa isikrini"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"Khiya isikrini"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"Isithombe-skrini"</string>
- <!-- no translation found for accessibility_system_action_accessibility_menu_label (8436484650391125184) -->
- <skip />
+ <string name="accessibility_system_action_accessibility_menu_label" msgid="8436484650391125184">"Imenyu yokufinyeleleka"</string>
<string name="accessibility_freeform_caption" msgid="8377519323496290122">"Ibha yamazwibela we-<xliff:g id="APP_NAME">%1$s</xliff:g>."</string>
<string name="as_app_forced_to_restricted_bucket" msgid="8233871289353898964">"I-<xliff:g id="PACKAGE_NAME">%1$s</xliff:g> ifakwe kubhakede LOKUKHAWULELWE"</string>
- <!-- no translation found for resolver_personal_tab (2051260504014442073) -->
- <skip />
- <!-- no translation found for resolver_work_tab (2690019516263167035) -->
- <skip />
+ <string name="resolver_personal_tab" msgid="2051260504014442073">"Okomuntu siqu"</string>
+ <string name="resolver_work_tab" msgid="2690019516263167035">"Umsebenzi"</string>
</resources>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cfed805..059bc44 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1781,8 +1781,11 @@
<attr name="crossProfile" format="boolean" />
</declare-styleable>
- <!-- The <code>feature</code> tag declares a feature. A feature is a part of an app. E.g.
- photo sharing app might include a direct messaging component.
+ <!-- The <code>feature</code> tag declares a feature. A feature is a logical part of an app.
+ E.g. photo sharing app might include a direct messaging component. To tag certain code as
+ belonging to a feature, use a context created via
+ {@link android.content.Context#createFeatureContext(String)} for any interaction with the
+ system.
<p>This appears as a child tag of the root {@link #AndroidManifest manifest} tag.
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 21128e3..21d1d3c 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1266,6 +1266,7 @@
<java-symbol type="array" name="vendor_disallowed_apps_managed_profile" />
<java-symbol type="array" name="vendor_disallowed_apps_managed_device" />
<java-symbol type="array" name="cross_profile_apps" />
+ <java-symbol type="array" name="vendor_cross_profile_apps" />
<java-symbol type="drawable" name="default_wallpaper" />
<java-symbol type="drawable" name="default_lock_wallpaper" />
diff --git a/core/res/res/values/vendor_cross_profile_apps.xml b/core/res/res/values/vendor_cross_profile_apps.xml
new file mode 100644
index 0000000..32839cd
--- /dev/null
+++ b/core/res/res/values/vendor_cross_profile_apps.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License.
+ -->
+<resources>
+ <!--
+ A collection of apps that have been pre-approved for cross-profile communication.
+ These will not require admin consent, but will still require user consent during provisioning.
+ -->
+ <string-array translatable="false" name="vendor_cross_profile_apps">
+ </string-array>
+</resources>
diff --git a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
index 09bbe37..a052543 100644
--- a/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
+++ b/core/tests/PlatformCompatFramework/src/com/android/internal/compat/ChangeReporterTest.java
@@ -24,10 +24,10 @@
public class ChangeReporterTest {
@Test
public void testStatsLogOnce() {
- ChangeReporter reporter = new ChangeReporter(0);
+ ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
int myUid = 1022, otherUid = 1023;
long myChangeId = 500L, otherChangeId = 600L;
- int myState = 1, otherState = 2;
+ int myState = ChangeReporter.STATE_ENABLED, otherState = ChangeReporter.STATE_DISABLED;
assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
reporter.reportChange(myUid, myChangeId, myState);
@@ -42,10 +42,10 @@
@Test
public void testStatsLogAfterReset() {
- ChangeReporter reporter = new ChangeReporter(0);
+ ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
int myUid = 1022;
long myChangeId = 500L;
- int myState = 1;
+ int myState = ChangeReporter.STATE_ENABLED;
assertTrue(reporter.shouldWriteToStatsLog(myUid, myChangeId, myState));
reporter.reportChange(myUid, myChangeId, myState);
@@ -60,10 +60,10 @@
@Test
public void testDebugLogOnce() {
- ChangeReporter reporter = new ChangeReporter(0);
+ ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
int myUid = 1022, otherUid = 1023;
long myChangeId = 500L, otherChangeId = 600L;
- int myState = 1, otherState = 2;
+ int myState = ChangeReporter.STATE_ENABLED, otherState = ChangeReporter.STATE_DISABLED;
assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
reporter.reportChange(myUid, myChangeId, myState);
@@ -78,10 +78,10 @@
@Test
public void testDebugLogAfterReset() {
- ChangeReporter reporter = new ChangeReporter(0);
+ ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
int myUid = 1022;
long myChangeId = 500L;
- int myState = 1;
+ int myState = ChangeReporter.STATE_ENABLED;
assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
reporter.reportChange(myUid, myChangeId, myState);
@@ -96,10 +96,10 @@
@Test
public void testDebugLogWithLogAll() {
- ChangeReporter reporter = new ChangeReporter(0);
+ ChangeReporter reporter = new ChangeReporter(ChangeReporter.SOURCE_UNKNOWN_SOURCE);
int myUid = 1022;
long myChangeId = 500L;
- int myState = 1;
+ int myState = ChangeReporter.STATE_ENABLED;
assertTrue(reporter.shouldWriteToDebug(myUid, myChangeId, myState));
reporter.reportChange(myUid, myChangeId, myState);
diff --git a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
index 8a22aca..a027f9e 100644
--- a/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
+++ b/core/tests/coretests/BstatsTestApp/src/com/android/coretests/apps/bstatstestapp/TestService.java
@@ -22,12 +22,12 @@
import android.app.Service;
import android.content.Intent;
import android.graphics.Color;
-import android.graphics.Point;
import android.os.Handler;
import android.os.IBinder;
import android.os.Process;
import android.os.RemoteException;
import android.util.Log;
+import android.util.Size;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
@@ -108,16 +108,15 @@
@Override
public void showApplicationOverlay() throws RemoteException {
final WindowManager wm = TestService.this.getSystemService(WindowManager.class);
- final Point size = new Point();
- wm.getDefaultDisplay().getSize(size);
+ final Size size = wm.getCurrentWindowMetrics().getSize();
final WindowManager.LayoutParams wmlp = new WindowManager.LayoutParams(
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);
- wmlp.width = size.x / 2;
- wmlp.height = size.y / 2;
+ wmlp.width = size.getWidth() / 2;
+ wmlp.height = size.getHeight() / 2;
wmlp.gravity = Gravity.CENTER | Gravity.LEFT;
wmlp.setTitle(TAG);
diff --git a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
index ba29a97..d17b635 100644
--- a/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timedetector/PhoneTimeSuggestionTest.java
@@ -27,17 +27,17 @@
import org.junit.Test;
public class PhoneTimeSuggestionTest {
- private static final int PHONE_ID = 99999;
+ private static final int SLOT_INDEX = 99999;
@Test
public void testEquals() {
- PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(PHONE_ID);
+ PhoneTimeSuggestion.Builder builder1 = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
{
PhoneTimeSuggestion one = builder1.build();
assertEquals(one, one);
}
- PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(PHONE_ID);
+ PhoneTimeSuggestion.Builder builder2 = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
{
PhoneTimeSuggestion one = builder1.build();
PhoneTimeSuggestion two = builder2.build();
@@ -59,7 +59,7 @@
assertEquals(two, one);
}
- PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(PHONE_ID + 1);
+ PhoneTimeSuggestion.Builder builder3 = new PhoneTimeSuggestion.Builder(SLOT_INDEX + 1);
builder3.setUtcTime(new TimestampedValue<>(1111L, 2222L));
{
PhoneTimeSuggestion one = builder1.build();
@@ -80,7 +80,7 @@
@Test
public void testParcelable() {
- PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(PHONE_ID);
+ PhoneTimeSuggestion.Builder builder = new PhoneTimeSuggestion.Builder(SLOT_INDEX);
assertRoundTripParcelable(builder.build());
builder.setUtcTime(new TimestampedValue<>(1111L, 2222L));
diff --git a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
index 0108a0b..384dbf9 100644
--- a/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
+++ b/core/tests/coretests/src/android/app/timezonedetector/PhoneTimeZoneSuggestionTest.java
@@ -26,17 +26,17 @@
import org.junit.Test;
public class PhoneTimeZoneSuggestionTest {
- private static final int PHONE_ID = 99999;
+ private static final int SLOT_INDEX = 99999;
@Test
public void testEquals() {
- PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ PhoneTimeZoneSuggestion.Builder builder1 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
{
PhoneTimeZoneSuggestion one = builder1.build();
assertEquals(one, one);
}
- PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ PhoneTimeZoneSuggestion.Builder builder2 = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
{
PhoneTimeZoneSuggestion one = builder1.build();
PhoneTimeZoneSuggestion two = builder2.build();
@@ -45,7 +45,7 @@
}
PhoneTimeZoneSuggestion.Builder builder3 =
- new PhoneTimeZoneSuggestion.Builder(PHONE_ID + 1);
+ new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX + 1);
{
PhoneTimeZoneSuggestion one = builder1.build();
PhoneTimeZoneSuggestion three = builder3.build();
@@ -120,7 +120,7 @@
@Test(expected = RuntimeException.class)
public void testBuilderValidates_emptyZone_badMatchType() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
// No zone ID, so match type should be left unset.
builder.setMatchType(PhoneTimeZoneSuggestion.MATCH_TYPE_NETWORK_COUNTRY_AND_OFFSET);
builder.build();
@@ -128,7 +128,7 @@
@Test(expected = RuntimeException.class)
public void testBuilderValidates_zoneSet_badMatchType() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
builder.setZoneId("Europe/London");
builder.setQuality(PhoneTimeZoneSuggestion.QUALITY_SINGLE_ZONE);
builder.build();
@@ -136,7 +136,7 @@
@Test
public void testParcelable() {
- PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(PHONE_ID);
+ PhoneTimeZoneSuggestion.Builder builder = new PhoneTimeZoneSuggestion.Builder(SLOT_INDEX);
assertRoundTripParcelable(builder.build());
builder.setZoneId("Europe/London");
diff --git a/core/tests/coretests/src/android/content/ContextTest.java b/core/tests/coretests/src/android/content/ContextTest.java
index b1a54dc..f074233 100644
--- a/core/tests/coretests/src/android/content/ContextTest.java
+++ b/core/tests/coretests/src/android/content/ContextTest.java
@@ -48,6 +48,7 @@
assertEquals(testContext.getDisplay().getDisplayId(), testContext.getDisplayId());
}
+ // TODO(b/128338354): Re-visit this test after introducing WindowContext
@Test
public void testDisplayIdForDefaultDisplayContext() {
final Context testContext =
diff --git a/core/tests/coretests/src/android/os/PowerManagerTest.java b/core/tests/coretests/src/android/os/PowerManagerTest.java
index 5cb7852..ea0a0fd 100644
--- a/core/tests/coretests/src/android/os/PowerManagerTest.java
+++ b/core/tests/coretests/src/android/os/PowerManagerTest.java
@@ -214,6 +214,9 @@
}
// Add listener2 on main thread.
mPm.addThermalStatusListener(mListener2);
+ verify(mListener2, timeout(CALLBACK_TIMEOUT_MILLI_SEC)
+ .times(1)).onThermalStatusChanged(status);
+ reset(mListener2);
status = PowerManager.THERMAL_STATUS_MODERATE;
mUiDevice.executeShellCommand("cmd thermalservice override-status "
+ Integer.toString(status));
diff --git a/core/tests/coretests/src/android/util/GridScenario.java b/core/tests/coretests/src/android/util/GridScenario.java
index 0f1730e..4809a21 100644
--- a/core/tests/coretests/src/android/util/GridScenario.java
+++ b/core/tests/coretests/src/android/util/GridScenario.java
@@ -233,7 +233,7 @@
// turn off title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
- mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
final Params params = new Params();
init(params);
diff --git a/core/tests/coretests/src/android/util/ListScenario.java b/core/tests/coretests/src/android/util/ListScenario.java
index 129484a..d4e5a43 100644
--- a/core/tests/coretests/src/android/util/ListScenario.java
+++ b/core/tests/coretests/src/android/util/ListScenario.java
@@ -306,7 +306,7 @@
requestWindowFeature(Window.FEATURE_NO_TITLE);
- mScreenHeight = getWindowManager().getDefaultDisplay().getHeight();
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
final Params params = createParams();
init(params);
diff --git a/core/tests/coretests/src/android/util/ScrollViewScenario.java b/core/tests/coretests/src/android/util/ScrollViewScenario.java
index e9eb978..2c0aa73 100644
--- a/core/tests/coretests/src/android/util/ScrollViewScenario.java
+++ b/core/tests/coretests/src/android/util/ScrollViewScenario.java
@@ -239,7 +239,7 @@
// for test stability, turn off title bar
requestWindowFeature(Window.FEATURE_NO_TITLE);
- int screenHeight = getWindowManager().getDefaultDisplay().getHeight()
+ int screenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight()
- 25;
mLinearLayout = new LinearLayout(this);
mLinearLayout.setOrientation(LinearLayout.VERTICAL);
diff --git a/core/tests/coretests/src/android/view/BigCache.java b/core/tests/coretests/src/android/view/BigCache.java
index 6a1bcaa..e465a85 100644
--- a/core/tests/coretests/src/android/view/BigCache.java
+++ b/core/tests/coretests/src/android/view/BigCache.java
@@ -18,6 +18,7 @@
import android.app.Activity;
import android.os.Bundle;
+import android.util.Size;
import android.widget.LinearLayout;
import android.widget.ScrollView;
@@ -38,9 +39,9 @@
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
final int cacheSize = ViewConfiguration.getMaximumDrawingCacheSize();
- final Display display = getWindowManager().getDefaultDisplay();
- final int screenWidth = display.getWidth();
- final int screenHeight = display.getHeight();
+ final Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
+ final int screenWidth = windowSize.getWidth();
+ final int screenHeight = windowSize.getHeight();
final View tiny = new View(this);
tiny.setId(R.id.a);
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 169716f..bdb8021 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -109,13 +109,14 @@
InsetsSourceConsumer topConsumer = new InsetsSourceConsumer(ITYPE_STATUS_BAR, mInsetsState,
() -> mMockTransaction, mMockController);
topConsumer.setControl(
- new InsetsSourceControl(ITYPE_STATUS_BAR, mTopLeash, new Point(0, 0)));
+ new InsetsSourceControl(ITYPE_STATUS_BAR, mTopLeash, new Point(0, 0)),
+ new int[1], new int[1]);
InsetsSourceConsumer navConsumer = new InsetsSourceConsumer(ITYPE_NAVIGATION_BAR,
mInsetsState, () -> mMockTransaction, mMockController);
- navConsumer.hide();
navConsumer.setControl(new InsetsSourceControl(ITYPE_NAVIGATION_BAR, mNavLeash,
- new Point(400, 0)));
+ new Point(400, 0)), new int[1], new int[1]);
+ navConsumer.hide();
SparseArray<InsetsSourceControl> controls = new SparseArray<>();
controls.put(ITYPE_STATUS_BAR, topConsumer.getControl());
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index e68c4b8..2c9dba1 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -121,9 +121,20 @@
if (type == ITYPE_IME) {
return new InsetsSourceConsumer(type, controller.getState(),
Transaction::new, controller) {
+
+ private boolean mImeRequestedShow;
+
+ @Override
+ public void show(boolean fromIme) {
+ super.show(fromIme);
+ if (fromIme) {
+ mImeRequestedShow = true;
+ }
+ }
+
@Override
public int requestShow(boolean fromController) {
- if (fromController) {
+ if (fromController || mImeRequestedShow) {
return SHOW_IMMEDIATELY;
} else {
return IME_SHOW_DELAYED;
@@ -399,6 +410,84 @@
}
@Test
+ public void testRestoreStartsAnimation() {
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
+ mController.onControlsChanged(new InsetsSourceControl[]{control});
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mController.hide(Type.statusBars());
+ mController.cancelExistingAnimation();
+ assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
+ assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
+
+ // Loosing control
+ InsetsState state = new InsetsState(mController.getState());
+ state.setSourceVisible(ITYPE_STATUS_BAR, true);
+ mController.onStateChanged(state);
+ mController.onControlsChanged(new InsetsSourceControl[0]);
+ assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
+ assertTrue(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
+
+ // Gaining control
+ mController.onControlsChanged(new InsetsSourceControl[]{control});
+ assertEquals(ANIMATION_TYPE_HIDE, mController.getAnimationType(ITYPE_STATUS_BAR));
+ mController.cancelExistingAnimation();
+ assertFalse(mController.getSourceConsumer(ITYPE_STATUS_BAR).isRequestedVisible());
+ assertFalse(mController.getState().getSource(ITYPE_STATUS_BAR).isVisible());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testStartImeAnimationAfterGettingControl() {
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+
+ mController.show(ime());
+ assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
+
+ // Pretend IME is calling
+ mController.show(ime(), true /* fromIme */);
+
+ // Gaining control shortly after
+ mController.onControlsChanged(new InsetsSourceControl[]{control});
+
+ assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
+ mController.cancelExistingAnimation();
+ assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
+ assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testStartImeAnimationAfterGettingControl_imeLater() {
+ InsetsSourceControl control =
+ new InsetsSourceControl(ITYPE_IME, mLeash, new Point());
+
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+
+ mController.show(ime());
+ assertFalse(mController.getState().getSource(ITYPE_IME).isVisible());
+
+ // Gaining control shortly after
+ mController.onControlsChanged(new InsetsSourceControl[]{control});
+
+ // Pretend IME is calling
+ mController.show(ime(), true /* fromIme */);
+
+ assertEquals(ANIMATION_TYPE_SHOW, mController.getAnimationType(ITYPE_IME));
+ mController.cancelExistingAnimation();
+ assertTrue(mController.getSourceConsumer(ITYPE_IME).isRequestedVisible());
+ assertTrue(mController.getState().getSource(ITYPE_IME).isVisible());
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
public void testAnimationEndState_controller() throws Exception {
InsetsSourceControl control =
new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point());
@@ -432,7 +521,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -456,7 +545,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
@@ -476,7 +565,7 @@
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
WindowInsetsAnimationControlListener listener =
mock(WindowInsetsAnimationControlListener.class);
- mController.controlInputMethodAnimation(0, new LinearInterpolator(), listener);
+ mController.controlWindowInsetsAnimation(ime(), 0, new LinearInterpolator(), listener);
// Ready gets deferred until next predraw
mViewRoot.getView().getViewTreeObserver().dispatchOnPreDraw();
diff --git a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
index 492c036..5e9e2f0 100644
--- a/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsSourceConsumerTest.java
@@ -18,6 +18,8 @@
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.WindowInsets.Type.statusBars;
+import static junit.framework.Assert.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
@@ -90,34 +92,44 @@
});
instrumentation.waitForIdleSync();
- mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()));
+ mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+ new int[1], new int[1]);
}
@Test
public void testHide() {
- mConsumer.hide();
- assertFalse("Consumer should not be visible", mConsumer.isRequestedVisible());
- verify(mSpyInsetsSource).setVisible(eq(false));
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mConsumer.hide();
+ assertFalse("Consumer should not be visible", mConsumer.isRequestedVisible());
+ verify(mSpyInsetsSource).setVisible(eq(false));
+ });
+
}
@Test
public void testShow() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ // Insets source starts out visible
+ mConsumer.hide();
+ mConsumer.show(false /* fromIme */);
+ assertTrue("Consumer should be visible", mConsumer.isRequestedVisible());
+ verify(mSpyInsetsSource).setVisible(eq(false));
+ verify(mSpyInsetsSource).setVisible(eq(true));
+ });
- // Insets source starts out visible
- mConsumer.hide();
- mConsumer.show();
- assertTrue("Consumer should be visible", mConsumer.isRequestedVisible());
- verify(mSpyInsetsSource).setVisible(eq(false));
- verify(mSpyInsetsSource).setVisible(eq(true));
}
@Test
public void testRestore() {
- mConsumer.setControl(null);
- reset(mMockTransaction);
- mConsumer.hide();
- verifyZeroInteractions(mMockTransaction);
- mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()));
- verify(mMockTransaction).hide(eq(mLeash));
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ mConsumer.setControl(null, new int[1], new int[1]);
+ reset(mMockTransaction);
+ mConsumer.hide();
+ verifyZeroInteractions(mMockTransaction);
+ int[] hideTypes = new int[1];
+ mConsumer.setControl(new InsetsSourceControl(ITYPE_STATUS_BAR, mLeash, new Point()),
+ new int[1], hideTypes);
+ assertEquals(statusBars(), hideTypes[0]);
+ });
}
}
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 20be8c2..79ac2b7 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -213,6 +213,7 @@
@Test
public void testParcelUnparcel() {
mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
mState.getSource(ITYPE_IME).setVisible(true);
mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
Parcel p = Parcel.obtain();
@@ -224,6 +225,16 @@
}
@Test
+ public void testCopy() {
+ mState.getSource(ITYPE_IME).setFrame(new Rect(0, 0, 100, 100));
+ mState.getSource(ITYPE_IME).setVisibleFrame(new Rect(0, 0, 50, 10));
+ mState.getSource(ITYPE_IME).setVisible(true);
+ mState.getSource(ITYPE_STATUS_BAR).setFrame(new Rect(0, 0, 100, 100));
+ mState2.set(mState, true);
+ assertEquals(mState, mState2);
+ }
+
+ @Test
public void testGetDefaultVisibility() {
assertTrue(InsetsState.getDefaultVisibility(ITYPE_STATUS_BAR));
assertTrue(InsetsState.getDefaultVisibility(ITYPE_NAVIGATION_BAR));
diff --git a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
index f63a454..039387c 100644
--- a/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
+++ b/core/tests/coretests/src/android/view/ScaleGestureDetectorTest.java
@@ -22,8 +22,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
-import android.content.Context;
-import android.util.DisplayMetrics;
+import android.util.Size;
import android.widget.TextView;
import androidx.test.filters.LargeTest;
@@ -54,25 +53,23 @@
final float initialScaleFactor = 1.0f;
assertEquals(initialScaleFactor, mScaleGestureActivity.getScaleFactor(), 0f);
- // Specify start and end coordinates, irrespective of device display size.
- final DisplayMetrics dm = new DisplayMetrics();
- final WindowManager wm = (WindowManager) (mScaleGestureActivity.getApplicationContext())
- .getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getMetrics(dm);
- final int displayWidth = dm.widthPixels;
- final int displayHeight = dm.heightPixels;
+ // Specify start and end coordinates with respect to the window size.
+ final WindowManager wm = mScaleGestureActivity.getSystemService(WindowManager.class);
+ final Size windowSize = wm.getCurrentWindowMetrics().getSize();
+ final int windowWidth = windowSize.getWidth();
+ final int windowHeight = windowSize.getHeight();
// Obtain coordinates to perform pinch and zoom from the center, to 75% of the display.
- final int centerX = displayWidth / 2;
- final int centerY = displayHeight / 2;
+ final int centerX = windowWidth / 2;
+ final int centerY = windowHeight / 2;
// Offset center coordinates by one, so that the two starting points are different.
final float[] firstFingerStartCoords = new float[] {centerX + 1.0f, centerY - 1.0f};
final float[] firstFingerEndCoords =
- new float[] {0.75f * displayWidth, 0.25f * displayHeight};
+ new float[] {0.75f * windowWidth, 0.25f * windowHeight};
final float[] secondFingerStartCoords = new float[] {centerX - 1.0f, centerY + 1.0f};
final float[] secondFingerEndCoords =
- new float[] {0.25f * displayWidth, 0.75f * displayHeight};
+ new float[] {0.25f * windowWidth, 0.75f * windowHeight};
onView(withId(R.id.article)).perform(new PinchZoomAction(firstFingerStartCoords,
firstFingerEndCoords, secondFingerStartCoords, secondFingerEndCoords,
diff --git a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
index 9f259a8..d705724 100644
--- a/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
+++ b/core/tests/coretests/src/android/view/inputmethod/InputMethodManagerTest.java
@@ -16,11 +16,13 @@
package android.view.inputmethod;
+import static android.view.Display.DEFAULT_DISPLAY;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import android.content.Context;
-import android.view.WindowManager;
+import android.hardware.display.DisplayManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -43,9 +45,9 @@
final Context testContext = InstrumentationRegistry.getInstrumentation()
.getTargetContext();
- final WindowManager wm = testContext.getSystemService(WindowManager.class);
+ final DisplayManager dm = testContext.getSystemService(DisplayManager.class);
final Context defaultDisplayContext =
- testContext.createDisplayContext(wm.getDefaultDisplay());
+ testContext.createDisplayContext(dm.getDisplay(DEFAULT_DISPLAY));
final InputMethodManager imm =
defaultDisplayContext.getSystemService(InputMethodManager.class);
assertEquals("InputMethodManager.getInstance() always returns the instance for the default"
diff --git a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
index ba85d76..d5825e2 100644
--- a/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
+++ b/core/tests/coretests/src/android/view/menu/ContextMenuTest.java
@@ -16,11 +16,9 @@
package android.view.menu;
-import android.content.Context;
-import android.graphics.Point;
import android.test.ActivityInstrumentationTestCase;
import android.util.PollingCheck;
-import android.view.Display;
+import android.util.Size;
import android.view.View;
import android.view.WindowManager;
import android.widget.espresso.ContextMenuUtils;
@@ -82,12 +80,9 @@
* Returns the minimum of the default display's width and height.
*/
private int getMinScreenDimension() {
- final WindowManager windowManager = (WindowManager) getActivity().getSystemService(
- Context.WINDOW_SERVICE);
- final Display display = windowManager.getDefaultDisplay();
- final Point displaySize = new Point();
- display.getRealSize(displaySize);
- return Math.min(displaySize.x, displaySize.y);
+ final WindowManager windowManager = getActivity().getSystemService(WindowManager.class);
+ final Size maxWindowSize = windowManager.getMaximumWindowMetrics().getSize();
+ return Math.min(maxWindowSize.getWidth(), maxWindowSize.getHeight());
}
/**
diff --git a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
index 73e4ea8..8e90a82 100644
--- a/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
+++ b/core/tests/coretests/src/android/widget/focus/ListOfInternalSelectionViews.java
@@ -17,7 +17,6 @@
package android.widget.focus;
import android.app.Activity;
-import android.graphics.Point;
import android.os.Bundle;
import android.util.InternalSelectionView;
import android.view.View;
@@ -112,9 +111,7 @@
protected void onCreate(Bundle icicle) {
super.onCreate(icicle);
- Point size = new Point();
- getWindowManager().getDefaultDisplay().getSize(size);
- mScreenHeight = size.y;
+ mScreenHeight = getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
Bundle extras = getIntent().getExtras();
if (extras != null) {
diff --git a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
index 0d3092c..fd1dbfc 100644
--- a/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
+++ b/core/tests/coretests/src/android/widget/gridview/touch/GridTouchVerticalSpacingStackFromBottomTest.java
@@ -106,9 +106,10 @@
int firstTop = firstChild.getTop();
+ int windowHeight = mActivity.getWindowManager().getCurrentWindowMetrics().getSize()
+ .getHeight();
int distance = TouchUtils.dragViewBy(this, firstChild,
- Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0,
- (int) (mActivity.getWindowManager().getDefaultDisplay().getHeight() * 0.75f));
+ Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, (int) (windowHeight * 0.75f));
assertEquals("View scrolled to wrong position", firstTop
+ (distance - mViewConfig.getScaledTouchSlop() - 1), firstChild.getTop());
diff --git a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
index 9e49719..e6195b1 100644
--- a/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
+++ b/core/tests/coretests/src/android/widget/listview/AdjacentListsWithAdjacentISVsInside.java
@@ -65,7 +65,8 @@
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
- final int desiredHeight = (int) (0.8 * getWindowManager().getDefaultDisplay().getHeight());
+ final int desiredHeight =
+ (int) (0.8 * getWindowManager().getCurrentWindowMetrics().getSize().getHeight());
mLeftListView = new ListView(this);
mLeftListView.setAdapter(new AdjacentISVAdapter(desiredHeight));
diff --git a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
index cd70608..cdcf23f 100644
--- a/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
+++ b/core/tests/coretests/src/com/android/internal/policy/DecorContextTest.java
@@ -26,7 +26,6 @@
import android.view.Display;
import android.view.DisplayAdjustments;
import android.view.DisplayInfo;
-import android.view.WindowManager;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -71,8 +70,7 @@
private static void assertDecorContextDisplay(int expectedDisplayId,
DecorContext decorContext) {
- WindowManager wm = (WindowManager) decorContext.getSystemService(Context.WINDOW_SERVICE);
- Display associatedDisplay = wm.getDefaultDisplay();
+ Display associatedDisplay = decorContext.getDisplay();
assertEquals(expectedDisplayId, associatedDisplay.getDisplayId());
}
}
diff --git a/data/etc/car/com.android.car.secondaryhome.xml b/data/etc/car/com.android.car.secondaryhome.xml
new file mode 100644
index 0000000..c74b86e
--- /dev/null
+++ b/data/etc/car/com.android.car.secondaryhome.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ Copyright (C) 2020 The Android Open Source Project
+ ~
+ ~ Licensed under the Apache License, Version 2.0 (the "License");
+ ~ you may not use this file except in compliance with the License.
+ ~ You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing, software
+ ~ distributed under the License is distributed on an "AS IS" BASIS,
+ ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ ~ See the License for the specific language governing permissions and
+ ~ limitations under the License
+ -->
+<permissions>
+ <privapp-permissions package="com.android.car.secondaryhome">
+ <!-- Required to launch app in ActivityView -->
+ <permission name="android.permission.ACTIVITY_EMBEDDING"/>
+ <!-- Required to send notification to current user-->
+ <permission name="android.permission.MANAGE_USERS"/>
+ </privapp-permissions>
+</permissions>
diff --git a/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index 91c5fbe..9da185b 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -1183,12 +1183,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/AppTransitionController.java"
},
- "292555239": {
- "message": "ScreenRotation sill animating: mDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
- },
"292904800": {
"message": "Deferring rotation, animation in progress.",
"level": "VERBOSE",
@@ -1573,12 +1567,6 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "1004585481": {
- "message": "%s forcing orientation to %d for display id=%d",
- "level": "VERBOSE",
- "group": "WM_DEBUG_ORIENTATION",
- "at": "com\/android\/server\/wm\/DisplayContent.java"
- },
"1051545910": {
"message": "Exit animation finished in %s: remove=%b",
"level": "VERBOSE",
@@ -1699,6 +1687,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1346895820": {
+ "message": "ScreenRotation still animating: type: %d\nmDisplayAnimator: %s\nmEnterBlackFrameAnimator: %s\nmRotateScreenAnimator: %s\nmScreenshotRotationAnimator: %s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/ScreenRotationAnimation.java"
+ },
"1358462645": {
"message": "Looking for focus: %s, flags=%d, canReceive=%b",
"level": "VERBOSE",
@@ -1717,6 +1711,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
},
+ "1389009035": {
+ "message": "NonAppWindowContainer cannot set orientation: %s",
+ "level": "WARN",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"1401700824": {
"message": "Window drawn win=%s",
"level": "DEBUG",
@@ -1891,6 +1891,12 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1674747211": {
+ "message": "%s forcing orientation to %d for display id=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_ORIENTATION",
+ "at": "com\/android\/server\/wm\/DisplayArea.java"
+ },
"1677260366": {
"message": "Finish starting %s: first real window is shown, no animation",
"level": "VERBOSE",
diff --git a/graphics/java/android/graphics/Outline.java b/graphics/java/android/graphics/Outline.java
index 91a60c3..c12159c 100644
--- a/graphics/java/android/graphics/Outline.java
+++ b/graphics/java/android/graphics/Outline.java
@@ -43,7 +43,7 @@
/** @hide */
public static final int MODE_ROUND_RECT = 1;
/** @hide */
- public static final int MODE_CONVEX_PATH = 2;
+ public static final int MODE_PATH = 2;
/** @hide */
@Retention(RetentionPolicy.SOURCE)
@@ -51,7 +51,7 @@
value = {
MODE_EMPTY,
MODE_ROUND_RECT,
- MODE_CONVEX_PATH,
+ MODE_PATH,
})
public @interface Mode {}
@@ -60,7 +60,7 @@
public int mMode = MODE_EMPTY;
/**
- * Only guaranteed to be non-null when mode == MODE_CONVEX_PATH
+ * Only guaranteed to be non-null when mode == MODE_PATH
*
* @hide
*/
@@ -124,7 +124,7 @@
* @see android.view.View#setClipToOutline(boolean)
*/
public boolean canClip() {
- return mMode != MODE_CONVEX_PATH;
+ return mMode != MODE_PATH;
}
/**
@@ -157,7 +157,7 @@
*/
public void set(@NonNull Outline src) {
mMode = src.mMode;
- if (src.mMode == MODE_CONVEX_PATH) {
+ if (src.mMode == MODE_PATH) {
if (mPath == null) {
mPath = new Path();
}
@@ -194,7 +194,7 @@
return;
}
- if (mMode == MODE_CONVEX_PATH) {
+ if (mMode == MODE_PATH) {
// rewind here to avoid thrashing the allocations, but could alternately clear ref
mPath.rewind();
}
@@ -213,7 +213,7 @@
/**
* Populates {@code outBounds} with the outline bounds, if set, and returns
* {@code true}. If no outline bounds are set, or if a path has been set
- * via {@link #setConvexPath(Path)}, returns {@code false}.
+ * via {@link #setPath(Path)}, returns {@code false}.
*
* @param outRect the rect to populate with the outline bounds, if set
* @return {@code true} if {@code outBounds} was populated with outline
@@ -229,7 +229,7 @@
/**
* Returns the rounded rect radius, if set, or a value less than 0 if a path has
- * been set via {@link #setConvexPath(Path)}. A return value of {@code 0}
+ * been set via {@link #setPath(Path)}. A return value of {@code 0}
* indicates a non-rounded rect.
*
* @return the rounded rect radius, or value < 0
@@ -259,7 +259,7 @@
mPath.rewind();
}
- mMode = MODE_CONVEX_PATH;
+ mMode = MODE_PATH;
mPath.addOval(left, top, right, bottom, Path.Direction.CW);
mRect.setEmpty();
mRadius = RADIUS_UNDEFINED;
@@ -279,9 +279,21 @@
* @param convexPath used to construct the Outline. As of
* {@link android.os.Build.VERSION_CODES#Q}, it is no longer required to be
* convex.
+ *
+ * @deprecated The path is no longer required to be convex. Use {@link #setPath} instead.
*/
+ @Deprecated
public void setConvexPath(@NonNull Path convexPath) {
- if (convexPath.isEmpty()) {
+ setPath(convexPath);
+ }
+
+ /**
+ * Sets the Outline to a {@link android.graphics.Path path}.
+ *
+ * @param path used to construct the Outline.
+ */
+ public void setPath(@NonNull Path path) {
+ if (path.isEmpty()) {
setEmpty();
return;
}
@@ -290,8 +302,8 @@
mPath = new Path();
}
- mMode = MODE_CONVEX_PATH;
- mPath.set(convexPath);
+ mMode = MODE_PATH;
+ mPath.set(path);
mRect.setEmpty();
mRadius = RADIUS_UNDEFINED;
}
@@ -302,7 +314,7 @@
public void offset(int dx, int dy) {
if (mMode == MODE_ROUND_RECT) {
mRect.offset(dx, dy);
- } else if (mMode == MODE_CONVEX_PATH) {
+ } else if (mMode == MODE_PATH) {
mPath.offset(dx, dy);
}
}
diff --git a/graphics/java/android/graphics/RenderNode.java b/graphics/java/android/graphics/RenderNode.java
index 17e3b44..3835b2d 100644
--- a/graphics/java/android/graphics/RenderNode.java
+++ b/graphics/java/android/graphics/RenderNode.java
@@ -687,8 +687,8 @@
outline.mRect.left, outline.mRect.top,
outline.mRect.right, outline.mRect.bottom,
outline.mRadius, outline.mAlpha);
- case Outline.MODE_CONVEX_PATH:
- return nSetOutlineConvexPath(mNativeRenderNode, outline.mPath.mNativePath,
+ case Outline.MODE_PATH:
+ return nSetOutlinePath(mNativeRenderNode, outline.mPath.mNativePath,
outline.mAlpha);
}
@@ -1620,7 +1620,7 @@
int right, int bottom, float radius, float alpha);
@CriticalNative
- private static native boolean nSetOutlineConvexPath(long renderNode, long nativePath,
+ private static native boolean nSetOutlinePath(long renderNode, long nativePath,
float alpha);
@CriticalNative
diff --git a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
index 928e607..746378e 100644
--- a/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
+++ b/graphics/java/android/graphics/drawable/AdaptiveIconDrawable.java
@@ -387,7 +387,7 @@
@Override
public void getOutline(@NonNull Outline outline) {
- outline.setConvexPath(mMask);
+ outline.setPath(mMask);
}
/** @hide */
diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java
index 3881955..f053f39 100644
--- a/graphics/java/android/graphics/drawable/GradientDrawable.java
+++ b/graphics/java/android/graphics/drawable/GradientDrawable.java
@@ -1915,7 +1915,7 @@
case RECTANGLE:
if (st.mRadiusArray != null) {
buildPathIfDirty();
- outline.setConvexPath(mPath);
+ outline.setPath(mPath);
return;
}
diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
index 475e0bb..28ba605 100644
--- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
+++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java
@@ -94,7 +94,7 @@
for (int i = 1; i < 8; i++) {
if (mOuterRadii[i] != radius) {
// can't call simple constructors, use path
- outline.setConvexPath(mPath);
+ outline.setPath(mPath);
return;
}
}
diff --git a/libs/hwui/Outline.h b/libs/hwui/Outline.h
index f1c3803..2eb2c7c 100644
--- a/libs/hwui/Outline.h
+++ b/libs/hwui/Outline.h
@@ -26,7 +26,7 @@
class Outline {
public:
- enum class Type { None = 0, Empty = 1, ConvexPath = 2, RoundRect = 3 };
+ enum class Type { None = 0, Empty = 1, Path = 2, RoundRect = 3 };
Outline() : mShouldClip(false), mType(Type::None), mRadius(0), mAlpha(0.0f) {}
@@ -57,12 +57,12 @@
}
}
- void setConvexPath(const SkPath* outline, float alpha) {
+ void setPath(const SkPath* outline, float alpha) {
if (!outline) {
setEmpty();
return;
}
- mType = Type::ConvexPath;
+ mType = Type::Path;
mPath = *outline;
mBounds.set(outline->getBounds());
mAlpha = alpha;
diff --git a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
index 551bdc6..234f42d 100644
--- a/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
+++ b/libs/hwui/pipeline/skia/ATraceMemoryDump.cpp
@@ -39,14 +39,13 @@
* ATraceMemoryDump calculates memory category first by looking at the "type" string passed to
* dumpStringValue and then by looking at "backingType" passed to setMemoryBacking.
* Only GPU Texture memory is tracked separately and everything else is grouped as one
- * "GPU Memory" category.
+ * "Misc Memory" category.
*/
static std::unordered_map<const char*, const char*> sResourceMap = {
{"malloc", "HWUI CPU Memory"}, // taken from setMemoryBacking(backingType)
{"gl_texture", "HWUI Texture Memory"}, // taken from setMemoryBacking(backingType)
- {"Texture",
- "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
- // Uncomment categories below to split "GPU Memory" into more brackets for debugging.
+ {"Texture", "HWUI Texture Memory"}, // taken from dumpStringValue(value, valueName="type")
+ // Uncomment categories below to split "Misc Memory" into more brackets for debugging.
/*{"vk_buffer", "vk_buffer"},
{"gl_renderbuffer", "gl_renderbuffer"},
{"gl_buffer", "gl_buffer"},
@@ -169,8 +168,8 @@
mLastDumpValue = 0;
mLastPurgeableDumpValue = INVALID_MEMORY_SIZE;
mLastDumpName = dumpName;
- // Categories not listed in sResourceMap are reported as "GPU memory"
- mCategory = "HWUI GPU Memory";
+ // Categories not listed in sResourceMap are reported as "Misc Memory"
+ mCategory = "HWUI Misc Memory";
}
} /* namespace skiapipeline */
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 5993e17..699b96a 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -143,10 +143,11 @@
ATRACE_CALL();
if (surface) {
- mNativeSurface = new ReliableSurface{std::move(surface)};
+ mNativeSurface = std::make_unique<ReliableSurface>(std::move(surface));
+ mNativeSurface->init();
if (enableTimeout) {
// TODO: Fix error handling & re-shorten timeout
- ANativeWindow_setDequeueTimeout(mNativeSurface.get(), 4000_ms);
+ ANativeWindow_setDequeueTimeout(mNativeSurface->getNativeWindow(), 4000_ms);
}
} else {
mNativeSurface = nullptr;
@@ -161,8 +162,9 @@
}
ColorMode colorMode = mWideColorGamut ? ColorMode::WideColorGamut : ColorMode::SRGB;
- bool hasSurface = mRenderPipeline->setSurface(mNativeSurface.get(), mSwapBehavior, colorMode,
- mRenderAheadCapacity);
+ bool hasSurface = mRenderPipeline->setSurface(
+ mNativeSurface ? mNativeSurface->getNativeWindow() : nullptr, mSwapBehavior, colorMode,
+ mRenderAheadCapacity);
mFrameNumber = -1;
@@ -203,7 +205,8 @@
void CanvasContext::allocateBuffers() {
if (mNativeSurface) {
- mNativeSurface->allocateBuffers();
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ ANativeWindow_allocateBuffers(anw);
}
}
@@ -428,7 +431,7 @@
presentTime = mCurrentFrameInfo->get(FrameInfoIndex::Vsync) +
(frameIntervalNanos * (renderAhead + 1));
}
- native_window_set_buffers_timestamp(mNativeSurface.get(), presentTime);
+ native_window_set_buffers_timestamp(mNativeSurface->getNativeWindow(), presentTime);
}
void CanvasContext::draw() {
@@ -489,16 +492,18 @@
swap.swapCompletedTime = systemTime(SYSTEM_TIME_MONOTONIC);
swap.vsyncTime = mRenderThread.timeLord().latestVsync();
if (didDraw) {
- nsecs_t dequeueStart = ANativeWindow_getLastDequeueStartTime(mNativeSurface.get());
+ nsecs_t dequeueStart =
+ ANativeWindow_getLastDequeueStartTime(mNativeSurface->getNativeWindow());
if (dequeueStart < mCurrentFrameInfo->get(FrameInfoIndex::SyncStart)) {
// Ignoring dequeue duration as it happened prior to frame render start
// and thus is not part of the frame.
swap.dequeueDuration = 0;
} else {
swap.dequeueDuration =
- ANativeWindow_getLastDequeueDuration(mNativeSurface.get());
+ ANativeWindow_getLastDequeueDuration(mNativeSurface->getNativeWindow());
}
- swap.queueDuration = ANativeWindow_getLastQueueDuration(mNativeSurface.get());
+ swap.queueDuration =
+ ANativeWindow_getLastQueueDuration(mNativeSurface->getNativeWindow());
} else {
swap.dequeueDuration = 0;
swap.queueDuration = 0;
@@ -567,14 +572,16 @@
}
SkISize CanvasContext::getNextFrameSize() const {
- ReliableSurface* surface = mNativeSurface.get();
- if (surface) {
- SkISize size;
- size.fWidth = ANativeWindow_getWidth(surface);
- size.fHeight = ANativeWindow_getHeight(surface);
- return size;
+ static constexpr SkISize defaultFrameSize = {INT32_MAX, INT32_MAX};
+ if (mNativeSurface == nullptr) {
+ return defaultFrameSize;
}
- return {INT32_MAX, INT32_MAX};
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+
+ SkISize size;
+ size.fWidth = ANativeWindow_getWidth(anw);
+ size.fHeight = ANativeWindow_getHeight(anw);
+ return size;
}
void CanvasContext::prepareAndDraw(RenderNode* node) {
@@ -702,11 +709,9 @@
if (!mNativeSurface) return false;
if (mHaveNewSurface) return true;
- int width = -1;
- int height = -1;
- ReliableSurface* surface = mNativeSurface.get();
- surface->query(NATIVE_WINDOW_WIDTH, &width);
- surface->query(NATIVE_WINDOW_HEIGHT, &height);
+ ANativeWindow* anw = mNativeSurface->getNativeWindow();
+ const int width = ANativeWindow_getWidth(anw);
+ const int height = ANativeWindow_getHeight(anw);
return width != mLastFrameWidth || height != mLastFrameHeight;
}
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 4490f80..0967b20 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -220,7 +220,7 @@
int32_t mLastFrameHeight = 0;
RenderThread& mRenderThread;
- sp<ReliableSurface> mNativeSurface;
+ std::unique_ptr<ReliableSurface> mNativeSurface;
// stopped indicates the CanvasContext will reject actual redraw operations,
// and defer repaint until it is un-stopped
bool mStopped = false;
diff --git a/libs/hwui/renderthread/ReliableSurface.cpp b/libs/hwui/renderthread/ReliableSurface.cpp
index 864780f..e92500f 100644
--- a/libs/hwui/renderthread/ReliableSurface.cpp
+++ b/libs/hwui/renderthread/ReliableSurface.cpp
@@ -26,64 +26,38 @@
// to propagate this error back to the caller
constexpr bool DISABLE_BUFFER_PREFETCH = true;
-// TODO: Make surface less protected
-// This exists because perform is a varargs, and ANativeWindow has no va_list perform.
-// So wrapping/chaining that is hard. Telling the compiler to ignore protected is easy, so we do
-// that instead
-struct SurfaceExposer : Surface {
- // Make warnings happy
- SurfaceExposer() = delete;
-
- using Surface::cancelBuffer;
- using Surface::dequeueBuffer;
- using Surface::lockBuffer_DEPRECATED;
- using Surface::perform;
- using Surface::queueBuffer;
- using Surface::setBufferCount;
- using Surface::setSwapInterval;
-};
-
-#define callProtected(surface, func, ...) ((*surface).*&SurfaceExposer::func)(__VA_ARGS__)
-
ReliableSurface::ReliableSurface(sp<Surface>&& surface) : mSurface(std::move(surface)) {
LOG_ALWAYS_FATAL_IF(!mSurface, "Error, unable to wrap a nullptr");
-
- ANativeWindow::setSwapInterval = hook_setSwapInterval;
- ANativeWindow::dequeueBuffer = hook_dequeueBuffer;
- ANativeWindow::cancelBuffer = hook_cancelBuffer;
- ANativeWindow::queueBuffer = hook_queueBuffer;
- ANativeWindow::query = hook_query;
- ANativeWindow::perform = hook_perform;
-
- ANativeWindow::dequeueBuffer_DEPRECATED = hook_dequeueBuffer_DEPRECATED;
- ANativeWindow::cancelBuffer_DEPRECATED = hook_cancelBuffer_DEPRECATED;
- ANativeWindow::lockBuffer_DEPRECATED = hook_lockBuffer_DEPRECATED;
- ANativeWindow::queueBuffer_DEPRECATED = hook_queueBuffer_DEPRECATED;
}
ReliableSurface::~ReliableSurface() {
clearReservedBuffer();
+ // Clear out the interceptors for proper hygiene.
+ // As a concrete example, if the underlying ANativeWindow is associated with
+ // an EGLSurface that is still in use, then if we don't clear out the
+ // interceptors then we walk into undefined behavior.
+ ANativeWindow_setCancelBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setQueueBufferInterceptor(mSurface.get(), nullptr, nullptr);
+ ANativeWindow_setPerformInterceptor(mSurface.get(), nullptr, nullptr);
}
-void ReliableSurface::perform(int operation, va_list args) {
- std::lock_guard _lock{mMutex};
+void ReliableSurface::init() {
+ int result = ANativeWindow_setCancelBufferInterceptor(mSurface.get(), hook_cancelBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set cancelBuffer interceptor: error = %d",
+ result);
- switch (operation) {
- case NATIVE_WINDOW_SET_USAGE:
- mUsage = va_arg(args, uint32_t);
- break;
- case NATIVE_WINDOW_SET_USAGE64:
- mUsage = va_arg(args, uint64_t);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_GEOMETRY:
- /* width */ va_arg(args, uint32_t);
- /* height */ va_arg(args, uint32_t);
- mFormat = va_arg(args, PixelFormat);
- break;
- case NATIVE_WINDOW_SET_BUFFERS_FORMAT:
- mFormat = va_arg(args, PixelFormat);
- break;
- }
+ result = ANativeWindow_setDequeueBufferInterceptor(mSurface.get(), hook_dequeueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set dequeueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setQueueBufferInterceptor(mSurface.get(), hook_queueBuffer, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set queueBuffer interceptor: error = %d",
+ result);
+
+ result = ANativeWindow_setPerformInterceptor(mSurface.get(), hook_perform, this);
+ LOG_ALWAYS_FATAL_IF(result != NO_ERROR, "Failed to set perform interceptor: error = %d",
+ result);
}
int ReliableSurface::reserveNext() {
@@ -111,7 +85,9 @@
int fenceFd = -1;
ANativeWindowBuffer* buffer = nullptr;
- int result = callProtected(mSurface, dequeueBuffer, &buffer, &fenceFd);
+
+ // Note that this calls back into our own hooked method.
+ int result = ANativeWindow_dequeueBuffer(mSurface.get(), &buffer, &fenceFd);
{
std::lock_guard _lock{mMutex};
@@ -138,61 +114,13 @@
mHasDequeuedBuffer = false;
}
if (buffer) {
- callProtected(mSurface, cancelBuffer, buffer, releaseFd);
+ // Note that clearReservedBuffer may be reentrant here, so
+ // mReservedBuffer must be cleared once we reach here to avoid recursing
+ // forever.
+ ANativeWindow_cancelBuffer(mSurface.get(), buffer, releaseFd);
}
}
-int ReliableSurface::cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
- int result = callProtected(mSurface, cancelBuffer, buffer, fenceFd);
- return result;
-}
-
-int ReliableSurface::dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd) {
- {
- std::lock_guard _lock{mMutex};
- if (mReservedBuffer) {
- *buffer = mReservedBuffer;
- *fenceFd = mReservedFenceFd.release();
- mReservedBuffer = nullptr;
- return OK;
- }
- }
-
-
- int result = callProtected(mSurface, dequeueBuffer, buffer, fenceFd);
- if (result != OK) {
- ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
- *buffer = acquireFallbackBuffer(result);
- *fenceFd = -1;
- return *buffer ? OK : INVALID_OPERATION;
- } else {
- std::lock_guard _lock{mMutex};
- mHasDequeuedBuffer = true;
- }
- return OK;
-}
-
-int ReliableSurface::queueBuffer(ANativeWindowBuffer* buffer, int fenceFd) {
- clearReservedBuffer();
-
- if (isFallbackBuffer(buffer)) {
- if (fenceFd > 0) {
- close(fenceFd);
- }
- return OK;
- }
-
- int result = callProtected(mSurface, queueBuffer, buffer, fenceFd);
- return result;
-}
-
bool ReliableSurface::isFallbackBuffer(const ANativeWindowBuffer* windowBuffer) const {
if (!mScratchBuffer || !windowBuffer) {
return false;
@@ -229,82 +157,95 @@
return AHardwareBuffer_to_ANativeWindowBuffer(newBuffer);
}
-Surface* ReliableSurface::getWrapped(const ANativeWindow* window) {
- return getSelf(window)->mSurface.get();
-}
+int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ {
+ std::lock_guard _lock{rs->mMutex};
+ if (rs->mReservedBuffer) {
+ *buffer = rs->mReservedBuffer;
+ *fenceFd = rs->mReservedFenceFd.release();
+ rs->mReservedBuffer = nullptr;
+ return OK;
+ }
+ }
-int ReliableSurface::hook_setSwapInterval(ANativeWindow* window, int interval) {
- return callProtected(getWrapped(window), setSwapInterval, interval);
-}
-
-int ReliableSurface::hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd) {
- return getSelf(window)->dequeueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->cancelBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer,
- int fenceFd) {
- return getSelf(window)->queueBuffer(buffer, fenceFd);
-}
-
-int ReliableSurface::hook_dequeueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer** buffer) {
- ANativeWindowBuffer* buf;
- int fenceFd = -1;
- int result = window->dequeueBuffer(window, &buf, &fenceFd);
+ int result = dequeueBuffer(window, buffer, fenceFd);
if (result != OK) {
- return result;
+ ALOGW("dequeueBuffer failed, error = %d; switching to fallback", result);
+ *buffer = rs->acquireFallbackBuffer(result);
+ *fenceFd = -1;
+ return *buffer ? OK : INVALID_OPERATION;
+ } else {
+ std::lock_guard _lock{rs->mMutex};
+ rs->mHasDequeuedBuffer = true;
}
- sp<Fence> fence(new Fence(fenceFd));
- int waitResult = fence->waitForever("dequeueBuffer_DEPRECATED");
- if (waitResult != OK) {
- ALOGE("dequeueBuffer_DEPRECATED: Fence::wait returned an error: %d", waitResult);
- window->cancelBuffer(window, buf, -1);
- return waitResult;
- }
- *buffer = buf;
- return result;
-}
-
-int ReliableSurface::hook_cancelBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->cancelBuffer(window, buffer, -1);
-}
-
-int ReliableSurface::hook_lockBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- // This method is a no-op in Surface as well
return OK;
}
-int ReliableSurface::hook_queueBuffer_DEPRECATED(ANativeWindow* window,
- ANativeWindowBuffer* buffer) {
- return window->queueBuffer(window, buffer, -1);
+int ReliableSurface::hook_cancelBuffer(ANativeWindow* window,
+ ANativeWindow_cancelBufferFn cancelBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+ return cancelBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_query(const ANativeWindow* window, int what, int* value) {
- return getWrapped(window)->query(what, value);
+int ReliableSurface::hook_queueBuffer(ANativeWindow* window,
+ ANativeWindow_queueBufferFn queueBuffer, void* data,
+ ANativeWindowBuffer* buffer, int fenceFd) {
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
+
+ if (rs->isFallbackBuffer(buffer)) {
+ if (fenceFd > 0) {
+ close(fenceFd);
+ }
+ return OK;
+ }
+
+ return queueBuffer(window, buffer, fenceFd);
}
-int ReliableSurface::hook_perform(ANativeWindow* window, int operation, ...) {
+int ReliableSurface::hook_perform(ANativeWindow* window, ANativeWindow_performFn perform,
+ void* data, int operation, va_list args) {
// Drop the reserved buffer if there is one since this (probably) mutated buffer dimensions
// TODO: Filter to things that only affect the reserved buffer
// TODO: Can we mutate the reserved buffer in some cases?
- getSelf(window)->clearReservedBuffer();
- va_list args;
- va_start(args, operation);
- int result = callProtected(getWrapped(window), perform, operation, args);
- va_end(args);
+ ReliableSurface* rs = reinterpret_cast<ReliableSurface*>(data);
+ rs->clearReservedBuffer();
- va_start(args, operation);
- getSelf(window)->perform(operation, args);
- va_end(args);
+ va_list argsCopy;
+ va_copy(argsCopy, args);
+ int result = perform(window, operation, argsCopy);
+ {
+ std::lock_guard _lock{rs->mMutex};
+
+ switch (operation) {
+ case ANATIVEWINDOW_PERFORM_SET_USAGE:
+ rs->mUsage = va_arg(args, uint32_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_USAGE64:
+ rs->mUsage = va_arg(args, uint64_t);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_GEOMETRY:
+ /* width */ va_arg(args, uint32_t);
+ /* height */ va_arg(args, uint32_t);
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ case ANATIVEWINDOW_PERFORM_SET_BUFFERS_FORMAT:
+ rs->mFormat = va_arg(args, PixelFormat);
+ break;
+ }
+ }
return result;
}
diff --git a/libs/hwui/renderthread/ReliableSurface.h b/libs/hwui/renderthread/ReliableSurface.h
index f768df3..3247253 100644
--- a/libs/hwui/renderthread/ReliableSurface.h
+++ b/libs/hwui/renderthread/ReliableSurface.h
@@ -16,6 +16,7 @@
#pragma once
+#include <apex/window.h>
#include <gui/Surface.h>
#include <utils/Macros.h>
#include <utils/StrongPointer.h>
@@ -24,16 +25,21 @@
namespace android::uirenderer::renderthread {
-class ReliableSurface : public ANativeObjectBase<ANativeWindow, ReliableSurface, RefBase> {
+class ReliableSurface {
PREVENT_COPY_AND_ASSIGN(ReliableSurface);
public:
ReliableSurface(sp<Surface>&& surface);
~ReliableSurface();
- int reserveNext();
+ // Performs initialization that is not safe to do in the constructor.
+ // For instance, registering ANativeWindow interceptors with ReliableSurface
+ // passed as the data pointer is not safe.
+ void init();
- void allocateBuffers() { mSurface->allocateBuffers(); }
+ ANativeWindow* getNativeWindow() { return mSurface.get(); }
+
+ int reserveNext();
int query(int what, int* value) const { return mSurface->query(what, value); }
@@ -61,7 +67,7 @@
}
private:
- const sp<Surface> mSurface;
+ sp<Surface> mSurface;
mutable std::mutex mMutex;
@@ -78,27 +84,20 @@
ANativeWindowBuffer* acquireFallbackBuffer(int error);
void clearReservedBuffer();
- void perform(int operation, va_list args);
- int cancelBuffer(ANativeWindowBuffer* buffer, int fenceFd);
- int dequeueBuffer(ANativeWindowBuffer** buffer, int* fenceFd);
- int queueBuffer(ANativeWindowBuffer* buffer, int fenceFd);
+ // ANativeWindow hooks. When an ANativeWindow_* method is called on the
+ // underlying ANativeWindow, these methods will intercept the original call.
+ // For example, an EGL driver would call into these hooks instead of the
+ // original methods.
+ static int hook_cancelBuffer(ANativeWindow* window, ANativeWindow_cancelBufferFn cancelBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
+ static int hook_dequeueBuffer(ANativeWindow* window,
+ ANativeWindow_dequeueBufferFn dequeueBuffer, void* data,
+ ANativeWindowBuffer** buffer, int* fenceFd);
+ static int hook_queueBuffer(ANativeWindow* window, ANativeWindow_queueBufferFn queueBuffer,
+ void* data, ANativeWindowBuffer* buffer, int fenceFd);
- static Surface* getWrapped(const ANativeWindow*);
-
- // ANativeWindow hooks
- static int hook_cancelBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
- static int hook_dequeueBuffer(ANativeWindow* window, ANativeWindowBuffer** buffer,
- int* fenceFd);
- static int hook_queueBuffer(ANativeWindow* window, ANativeWindowBuffer* buffer, int fenceFd);
-
- static int hook_perform(ANativeWindow* window, int operation, ...);
- static int hook_query(const ANativeWindow* window, int what, int* value);
- static int hook_setSwapInterval(ANativeWindow* window, int interval);
-
- static int hook_cancelBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_dequeueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer** buffer);
- static int hook_lockBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
- static int hook_queueBuffer_DEPRECATED(ANativeWindow* window, ANativeWindowBuffer* buffer);
+ static int hook_perform(ANativeWindow* window, ANativeWindow_performFn perform, void* data,
+ int operation, va_list args);
};
}; // namespace android::uirenderer::renderthread
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 7a12cee..eb76c29 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -16,7 +16,6 @@
package android.location;
-import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.compat.annotation.UnsupportedAppUsage;
@@ -1214,23 +1213,6 @@
}
/**
- * Attaches an extra {@link Location} to this Location. This is useful for location providers
- * to set the {@link #EXTRA_NO_GPS_LOCATION} extra to provide coarse locations for clients.
- *
- * @param key the key associated with the Location extra
- * @param value the Location to attach
- * @hide
- */
- @TestApi
- @SystemApi
- public void setExtraLocation(@Nullable String key, @Nullable Location value) {
- if (mExtras == null) {
- mExtras = new Bundle();
- }
- mExtras.putParcelable(key, value);
- }
-
- /**
* Returns true if the Location came from a mock provider.
*
* @return true if this Location came from a mock provider, false otherwise
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index 114c0f1..fe0c2d2 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -1427,7 +1427,10 @@
}
}
- static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
+ /**
+ * @hide
+ */
+ public static int capturePolicyToFlags(@CapturePolicy int capturePolicy, int flags) {
switch (capturePolicy) {
case ALLOW_CAPTURE_BY_NONE:
flags |= FLAG_NO_MEDIA_PROJECTION | FLAG_NO_SYSTEM_CAPTURE;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 861b76d..7b17f9f 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1547,23 +1547,22 @@
* {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
* {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
* {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
- * @throws IllegalArgumentException if the argument is not a valid value.
+ * @throws RuntimeException if the argument is not a valid value.
*/
public void setAllowedCapturePolicy(@AudioAttributes.CapturePolicy int capturePolicy) {
- int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
- // TODO: got trough AudioService and save a cache to restore in case of AP crash
// TODO: also pass the package in case multiple packages have the same UID
- int result = AudioSystem.setAllowedCapturePolicy(Process.myUid(), flags);
- if (result != AudioSystem.AUDIO_STATUS_OK) {
- Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
- return;
+ final IAudioService service = getService();
+ try {
+ int result = service.setAllowedCapturePolicy(capturePolicy);
+ if (result != AudioSystem.AUDIO_STATUS_OK) {
+ Log.e(TAG, "Could not setAllowedCapturePolicy: " + result);
+ return;
+ }
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
}
- mCapturePolicy = capturePolicy;
}
- @AudioAttributes.CapturePolicy
- private int mCapturePolicy = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
-
/**
* Return the capture policy.
* @return the capture policy set by {@link #setAllowedCapturePolicy(int)} or
@@ -1571,7 +1570,13 @@
*/
@AudioAttributes.CapturePolicy
public int getAllowedCapturePolicy() {
- return mCapturePolicy;
+ int result = AudioAttributes.ALLOW_CAPTURE_BY_ALL;
+ try {
+ result = getService().getAllowedCapturePolicy();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Failed to query allowed capture policy: " + e);
+ }
+ return result;
}
//====================================================================
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 1f97be5..64c5c05 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -282,6 +282,10 @@
List<AudioDeviceAddress> getDevicesForAttributes(in AudioAttributes attributes);
+ int setAllowedCapturePolicy(in int capturePolicy);
+
+ int getAllowedCapturePolicy();
+
// WARNING: read warning at top of file, new methods that need to be used by native
// code via IAudioManager.h need to be added to the top section.
}
diff --git a/media/java/android/media/MediaRoute2Info.java b/media/java/android/media/MediaRoute2Info.java
index dd01243..0e88c75 100644
--- a/media/java/android/media/MediaRoute2Info.java
+++ b/media/java/android/media/MediaRoute2Info.java
@@ -21,6 +21,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
+import android.annotation.TestApi;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
@@ -197,6 +198,7 @@
final List<String> mFeatures;
@DeviceType
final int mDeviceType;
+ final boolean mIsSystem;
final Uri mIconUri;
final CharSequence mDescription;
@ConnectionState
@@ -213,6 +215,7 @@
mName = builder.mName;
mFeatures = builder.mFeatures;
mDeviceType = builder.mDeviceType;
+ mIsSystem = builder.mIsSystem;
mIconUri = builder.mIconUri;
mDescription = builder.mDescription;
mConnectionState = builder.mConnectionState;
@@ -229,6 +232,7 @@
mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mFeatures = in.createStringArrayList();
mDeviceType = in.readInt();
+ mIsSystem = in.readBoolean();
mIconUri = in.readParcelable(null);
mDescription = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
mConnectionState = in.readInt();
@@ -287,6 +291,17 @@
}
/**
+ * Returns whether the route is a system route or not.
+ * <p>
+ * System routes are media routes directly controlled by the system
+ * such as phone speaker, wired headset, and Bluetooth devices.
+ * </p>
+ */
+ public boolean isSystemRoute() {
+ return mIsSystem;
+ }
+
+ /**
* Gets the URI of the icon representing this route.
* <p>
* This icon will be used in picker UIs if available.
@@ -360,6 +375,7 @@
* @hide
*/
@NonNull
+ @TestApi
public String getOriginalId() {
return mId;
}
@@ -423,6 +439,7 @@
&& Objects.equals(mName, other.mName)
&& Objects.equals(mFeatures, other.mFeatures)
&& (mDeviceType == other.mDeviceType)
+ && (mIsSystem == other.mIsSystem)
&& Objects.equals(mIconUri, other.mIconUri)
&& Objects.equals(mDescription, other.mDescription)
&& (mConnectionState == other.mConnectionState)
@@ -436,7 +453,7 @@
@Override
public int hashCode() {
// Note: mExtras is not included.
- return Objects.hash(mId, mName, mFeatures, mDeviceType, mIconUri, mDescription,
+ return Objects.hash(mId, mName, mFeatures, mDeviceType, mIsSystem, mIconUri, mDescription,
mConnectionState, mClientPackageName, mVolumeHandling, mVolumeMax, mVolume,
mProviderId);
}
@@ -473,6 +490,7 @@
TextUtils.writeToParcel(mName, dest, flags);
dest.writeStringList(mFeatures);
dest.writeInt(mDeviceType);
+ dest.writeBoolean(mIsSystem);
dest.writeParcelable(mIconUri, flags);
TextUtils.writeToParcel(mDescription, dest, flags);
dest.writeInt(mConnectionState);
@@ -494,6 +512,7 @@
@DeviceType
int mDeviceType = DEVICE_TYPE_UNKNOWN;
+ boolean mIsSystem;
Uri mIconUri;
CharSequence mDescription;
@ConnectionState
@@ -540,6 +559,7 @@
mName = routeInfo.mName;
mFeatures = new ArrayList<>(routeInfo.mFeatures);
mDeviceType = routeInfo.mDeviceType;
+ mIsSystem = routeInfo.mIsSystem;
mIconUri = routeInfo.mIconUri;
mDescription = routeInfo.mDescription;
mConnectionState = routeInfo.mConnectionState;
@@ -608,6 +628,16 @@
}
/**
+ * Sets whether the route is a system route or not.
+ * @hide
+ */
+ @NonNull
+ public Builder setSystemRoute(boolean isSystem) {
+ mIsSystem = isSystem;
+ return this;
+ }
+
+ /**
* Sets the URI of the icon representing this route.
* <p>
* This icon will be used in picker UIs if available.
diff --git a/media/java/android/media/MediaRoute2ProviderInfo.java b/media/java/android/media/MediaRoute2ProviderInfo.java
index c9a2ec7..afe002e 100644
--- a/media/java/android/media/MediaRoute2ProviderInfo.java
+++ b/media/java/android/media/MediaRoute2ProviderInfo.java
@@ -180,6 +180,23 @@
}
/**
+ * Sets whether the provider provides system routes or not
+ */
+ @NonNull
+ public Builder setSystemRouteProvider(boolean isSystem) {
+ int count = mRoutes.size();
+ for (int i = 0; i < count; i++) {
+ MediaRoute2Info route = mRoutes.valueAt(i);
+ if (route.isSystemRoute() != isSystem) {
+ mRoutes.setValueAt(i, new MediaRoute2Info.Builder(route)
+ .setSystemRoute(isSystem)
+ .build());
+ }
+ }
+ return this;
+ }
+
+ /**
* Adds a route to the provider
*/
@NonNull
diff --git a/media/java/android/media/MediaRouter2.java b/media/java/android/media/MediaRouter2.java
index 7b9a44f..f751a22 100644
--- a/media/java/android/media/MediaRouter2.java
+++ b/media/java/android/media/MediaRouter2.java
@@ -230,7 +230,11 @@
/**
* Gets the unmodifiable list of {@link MediaRoute2Info routes} currently
* known to the media router.
+ * <p>
+ * {@link MediaRoute2Info#isSystemRoute() System routes} such as phone speaker,
+ * Bluetooth devices are always included in the list.
* Please note that the list can be changed before callbacks are invoked.
+ * </p>
*
* @return the list of routes that contains at least one of the route features in discovery
* preferences registered by the application
@@ -243,7 +247,8 @@
List<MediaRoute2Info> filteredRoutes = new ArrayList<>();
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
+ if (route.isSystemRoute()
+ || route.hasAnyFeatures(mDiscoveryPreference.getPreferredFeatures())) {
filteredRoutes.add(route);
}
}
@@ -307,12 +312,18 @@
* with the given route.
*
* @param route the route you want to create a controller with.
+ * @throws IllegalArgumentException if the given route is
+ * {@link MediaRoute2Info#isSystemRoute() system route}
*
* @see RoutingControllerCallback#onControllerCreated
* @see RoutingControllerCallback#onControllerCreationFailed
*/
public void requestCreateController(@NonNull MediaRoute2Info route) {
Objects.requireNonNull(route, "route must not be null");
+ if (route.isSystemRoute()) {
+ throw new IllegalArgumentException("Can't create a route controller with "
+ + "a system route. Use getSystemController().");
+ }
// TODO: Check the given route exists
final int requestId;
diff --git a/media/java/android/media/MediaRouter2Manager.java b/media/java/android/media/MediaRouter2Manager.java
index 61e2f77..662eeb1 100644
--- a/media/java/android/media/MediaRouter2Manager.java
+++ b/media/java/android/media/MediaRouter2Manager.java
@@ -161,14 +161,15 @@
public List<MediaRoute2Info> getAvailableRoutes(@NonNull String packageName) {
Objects.requireNonNull(packageName, "packageName must not be null");
+ List<MediaRoute2Info> routes = new ArrayList<>();
+
List<String> preferredFeatures = mPreferredFeaturesMap.get(packageName);
if (preferredFeatures == null) {
- return Collections.emptyList();
+ preferredFeatures = Collections.emptyList();
}
- List<MediaRoute2Info> routes = new ArrayList<>();
synchronized (mRoutesLock) {
for (MediaRoute2Info route : mRoutes.values()) {
- if (route.hasAnyFeatures(preferredFeatures)) {
+ if (route.isSystemRoute() || route.hasAnyFeatures(preferredFeatures)) {
routes.add(route);
}
}
diff --git a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
index 074188e..adf4d3d 100644
--- a/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
+++ b/media/java/android/media/audiopolicy/AudioVolumeGroupChangeHandler.java
@@ -157,9 +157,7 @@
Handler handler = eventHandler.handler();
if (handler != null) {
Message m = handler.obtainMessage(what, arg1, arg2, obj);
- if (what != AUDIOVOLUMEGROUP_EVENT_NEW_LISTENER) {
- handler.removeMessages(what);
- }
+ // Do not remove previous messages, as we would lose notification of group changes
handler.sendMessage(m);
}
}
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index f3c071a0..a828e2d 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -722,6 +722,7 @@
return MtpConstants.RESPONSE_OK;
case MtpConstants.DEVICE_PROPERTY_IMAGE_SIZE:
// use screen size as max image size
+ // TODO(b/147721765): Add support for foldables/multi-display devices.
Display display = ((WindowManager) mContext.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay();
int width = display.getMaximumSizeDimension();
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
index 0ae640d..2522095 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/helpers/CameraTestUtils.java
@@ -58,7 +58,6 @@
import android.util.Log;
import android.util.Pair;
import android.util.Size;
-import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
@@ -2211,14 +2210,14 @@
}
public static Size getPreviewSizeBound(WindowManager windowManager, Size bound) {
- Display display = windowManager.getDefaultDisplay();
+ Size windowSize = windowManager.getCurrentWindowMetrics().getSize();
- int width = display.getWidth();
- int height = display.getHeight();
+ int width = windowSize.getWidth();
+ int height = windowSize.getHeight();
if (height > width) {
height = width;
- width = display.getHeight();
+ width = windowSize.getHeight();
}
if (bound.getWidth() <= width &&
diff --git a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
index 4a2044a..16259ab 100644
--- a/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
+++ b/media/tests/MediaRouter/src/com/android/mediaroutertest/MediaRouterManagerTest.java
@@ -196,7 +196,14 @@
public void testRouteFeatures() throws Exception {
Map<String, MediaRoute2Info> routes = waitAndGetRoutesWithManager(FEATURES_SPECIAL);
- assertEquals(1, routes.size());
+ int routeCount = 0;
+ for (MediaRoute2Info route : routes.values()) {
+ if (!route.isSystemRoute()) {
+ routeCount++;
+ }
+ }
+
+ assertEquals(1, routeCount);
assertNotNull(routes.get(ROUTE_ID_SPECIAL_FEATURE));
}
diff --git a/native/android/libandroid.map.txt b/native/android/libandroid.map.txt
index 97b861b..a8f1d2c 100644
--- a/native/android/libandroid.map.txt
+++ b/native/android/libandroid.map.txt
@@ -23,6 +23,8 @@
AChoreographer_postFrameCallbackDelayed; # introduced=24
AChoreographer_postFrameCallback64; # introduced=29
AChoreographer_postFrameCallbackDelayed64; # introduced=29
+ AChoreographer_registerRefreshRateCallback; # introduced=30
+ AChoreographer_unregisterRefreshRateCallback; # introduced=30
AConfiguration_copy;
AConfiguration_delete;
AConfiguration_diff;
diff --git a/packages/CarSystemUI/res/values/config.xml b/packages/CarSystemUI/res/values/config.xml
index e2297e4..d2f514c 100644
--- a/packages/CarSystemUI/res/values/config.xml
+++ b/packages/CarSystemUI/res/values/config.xml
@@ -29,6 +29,9 @@
<bool name="config_enableRightNavigationBar">false</bool>
<bool name="config_enableBottomNavigationBar">true</bool>
+ <!-- Disable normal notification rendering; we handle that ourselves -->
+ <bool name="config_renderNotifications">false</bool>
+
<!-- Whether heads-up notifications should be shown when shade is open. -->
<bool name="config_enableHeadsUpNotificationWhenNotificationShadeOpen">true</bool>
diff --git a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
index cf4ee7d..585acfe 100644
--- a/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/CarSystemUIModule.java
@@ -22,7 +22,6 @@
import android.content.Context;
import com.android.systemui.car.CarDeviceProvisionedControllerImpl;
-import com.android.systemui.car.CarNotificationEntryManager;
import com.android.systemui.car.CarNotificationInterruptionStateProvider;
import com.android.systemui.dagger.SystemUIRootComponent;
import com.android.systemui.dock.DockManager;
@@ -73,13 +72,6 @@
return false;
}
- /**
- * Use {@link CarNotificationEntryManager}, which does nothing when adding a notification.
- */
- @Binds
- abstract NotificationEntryManager bindNotificationEntryManager(
- CarNotificationEntryManager notificationEntryManager);
-
@Singleton
@Provides
static HeadsUpManagerPhone provideHeadsUpManagerPhone(Context context,
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java b/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
deleted file mode 100644
index cfe1c70..0000000
--- a/packages/CarSystemUI/src/com/android/systemui/car/CarNotificationEntryManager.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2019 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package com.android.systemui.car;
-
-import android.service.notification.NotificationListenerService;
-import android.service.notification.StatusBarNotification;
-
-import com.android.systemui.statusbar.FeatureFlags;
-import com.android.systemui.statusbar.NotificationRemoteInputManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
-import com.android.systemui.statusbar.notification.collection.NotificationRankingManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
-import com.android.systemui.statusbar.notification.logging.NotifLog;
-import com.android.systemui.statusbar.phone.NotificationGroupManager;
-import com.android.systemui.util.leak.LeakDetector;
-
-import javax.inject.Inject;
-import javax.inject.Singleton;
-
-import dagger.Lazy;
-
-/**
- * Car specific notification entry manager that does nothing when adding a notification.
- *
- * <p> This is because system UI notifications are disabled and we have a different implementation.
- * Please see {@link com.android.car.notification}.
- */
-@Singleton
-public class CarNotificationEntryManager extends NotificationEntryManager {
-
- @Inject
- public CarNotificationEntryManager(
- NotifLog notifLog,
- NotificationGroupManager groupManager,
- NotificationRankingManager rankingManager,
- KeyguardEnvironment keyguardEnvironment,
- FeatureFlags featureFlags,
- Lazy<NotificationRowBinder> notificationRowBinderLazy,
- Lazy<NotificationRemoteInputManager> notificationRemoteInputManagerLazy,
- LeakDetector leakDetector) {
- super(notifLog, groupManager, rankingManager, keyguardEnvironment, featureFlags,
- notificationRowBinderLazy, notificationRemoteInputManagerLazy, leakDetector);
- }
-
- @Override
- public void addNotification(
- StatusBarNotification notification, NotificationListenerService.RankingMap ranking) {
- }
-}
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 76e9ec6..210dd32 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -87,10 +87,8 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -103,12 +101,10 @@
import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -124,7 +120,6 @@
import com.android.systemui.statusbar.phone.LightsOutNotifController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -141,7 +136,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
@@ -257,7 +251,7 @@
public CarStatusBar(
Context context,
- FeatureFlags featureFlags,
+ NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -269,13 +263,11 @@
HeadsUpManagerPhone headsUpManagerPhone,
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
- Lazy<NotifPipelineInitializer> notifPipelineInitializer,
FalsingManager falsingManager,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationEntryManager notificationEntryManager,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -296,12 +288,10 @@
VibratorHelper vibratorHelper,
BubbleController bubbleController,
NotificationGroupManager groupManager,
- NotificationGroupAlertTransferHelper groupAlertTransferHelper,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
- NotificationListener notificationListener,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
LockscreenLockIconController lockscreenLockIconController,
@@ -318,7 +308,6 @@
Optional<Recents> recents,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
SuperStatusBarViewFactory superStatusBarViewFactory,
LightsOutNotifController lightsOutNotifController,
@@ -334,7 +323,6 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- NotificationRowBinderImpl notificationRowBinder,
DismissCallbackRegistry dismissCallbackRegistry,
/* Car Settings injected components. */
CarServiceProvider carServiceProvider,
@@ -345,7 +333,7 @@
FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
super(
context,
- featureFlags,
+ notificationsController,
lightBarController,
autoHideController,
keyguardUpdateMonitor,
@@ -357,13 +345,11 @@
headsUpManagerPhone,
dynamicPrivacyController,
bypassHeadsUpNotifier,
- notifPipelineInitializer,
falsingManager,
broadcastDispatcher,
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationEntryManager,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
@@ -384,12 +370,10 @@
vibratorHelper,
bubbleController,
groupManager,
- groupAlertTransferHelper,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
assistManagerLazy,
- notificationListener,
configurationController,
notificationShadeWindowController,
lockscreenLockIconController,
@@ -407,7 +391,6 @@
recents,
statusBarComponentBuilder,
pluginManager,
- remoteInputUriController,
dividerOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
@@ -422,7 +405,6 @@
keyguardDismissUtil,
extensionController,
userInfoControllerImpl,
- notificationRowBinder,
dismissCallbackRegistry);
mUserSwitcherController = userSwitcherController;
mScrimController = scrimController;
diff --git a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
index 45da822..498bd87 100644
--- a/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
+++ b/packages/CarSystemUI/src/com/android/systemui/statusbar/car/CarStatusBarModule.java
@@ -47,10 +47,8 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.FlingAnimationUtils;
import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -63,12 +61,10 @@
import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.AutoHideController;
@@ -83,7 +79,6 @@
import com.android.systemui.statusbar.phone.LightsOutNotifController;
import com.android.systemui.statusbar.phone.LockscreenLockIconController;
import com.android.systemui.statusbar.phone.LockscreenWallpaper;
-import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper;
import com.android.systemui.statusbar.phone.NotificationGroupManager;
import com.android.systemui.statusbar.phone.NotificationShadeWindowController;
import com.android.systemui.statusbar.phone.ScrimController;
@@ -99,7 +94,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
@@ -127,7 +121,7 @@
@Singleton
static CarStatusBar provideStatusBar(
Context context,
- FeatureFlags featureFlags,
+ NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -139,13 +133,11 @@
HeadsUpManagerPhone headsUpManagerPhone,
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
- Lazy<NotifPipelineInitializer> notifPipelineInitializer,
FalsingManager falsingManager,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationEntryManager notificationEntryManager,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -166,12 +158,10 @@
VibratorHelper vibratorHelper,
BubbleController bubbleController,
NotificationGroupManager groupManager,
- NotificationGroupAlertTransferHelper groupAlertTransferHelper,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
- NotificationListener notificationListener,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
LockscreenLockIconController lockscreenLockIconController,
@@ -188,7 +178,6 @@
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
SuperStatusBarViewFactory superStatusBarViewFactory,
LightsOutNotifController lightsOutNotifController,
@@ -204,7 +193,6 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- NotificationRowBinderImpl notificationRowBinder,
DismissCallbackRegistry dismissCallbackRegistry,
CarServiceProvider carServiceProvider,
Lazy<PowerManagerHelper> powerManagerHelperLazy,
@@ -214,7 +202,7 @@
FlingAnimationUtils.Builder flingAnimationUtilsBuilder) {
return new CarStatusBar(
context,
- featureFlags,
+ notificationsController,
lightBarController,
autoHideController,
keyguardUpdateMonitor,
@@ -226,13 +214,11 @@
headsUpManagerPhone,
dynamicPrivacyController,
bypassHeadsUpNotifier,
- notifPipelineInitializer,
falsingManager,
broadcastDispatcher,
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationEntryManager,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
@@ -253,12 +239,10 @@
vibratorHelper,
bubbleController,
groupManager,
- groupAlertTransferHelper,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
assistManagerLazy,
- notificationListener,
configurationController,
notificationShadeWindowController,
lockscreenLockIconController,
@@ -275,7 +259,6 @@
recentsOptional,
statusBarComponentBuilder,
pluginManager,
- remoteInputUriController,
dividerOptional,
superStatusBarViewFactory,
lightsOutNotifController,
@@ -290,7 +273,6 @@
keyguardDismissUtil,
extensionController,
userInfoControllerImpl,
- notificationRowBinder,
dismissCallbackRegistry,
carServiceProvider,
powerManagerHelperLazy,
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index ec445d4..38cf5ab 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -318,6 +318,16 @@
return false;
}
+ // Allow all directories on USB, including the root.
+ try {
+ RootInfo rootInfo = getRootFromDocId(docId);
+ if ((rootInfo.flags & Root.FLAG_REMOVABLE_USB) == Root.FLAG_REMOVABLE_USB) {
+ return false;
+ }
+ } catch (FileNotFoundException e) {
+ Log.e(TAG, "Failed to determine rootInfo for docId");
+ }
+
final String path = getPathFromDocId(docId);
// Block the root of the storage
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
index c9e0d0a..d4eb2a9 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeApp.java
@@ -16,6 +16,9 @@
package com.android.fakeoemfeatures;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
import android.app.ActivityManager;
import android.app.ActivityThread;
import android.app.AlertDialog;
@@ -25,9 +28,11 @@
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
+import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.util.Size;
import android.util.Slog;
import android.view.Display;
import android.view.ViewGroup;
@@ -94,8 +99,13 @@
return;
}
- final WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
- final Display display = wm.getDefaultDisplay();
+ // Construct an instance of WindowManager to add the window of TYPE_APPLICATION_OVERLAY to
+ // the default display.
+ final DisplayManager dm = getSystemService(DisplayManager.class);
+ final Display defaultDisplay = dm.getDisplay(DEFAULT_DISPLAY);
+ final Context windowContext = createDisplayContext(defaultDisplay)
+ .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */);
+ final WindowManager wm = windowContext.getSystemService(WindowManager.class);
// Check to make sure we are not running on a user build. If this
// is a user build, WARN! Do not want!
@@ -108,14 +118,14 @@
builder.setCancelable(false);
builder.setPositiveButton("I understand", null);
Dialog dialog = builder.create();
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+ dialog.getWindow().setType(TYPE_APPLICATION_OVERLAY);
dialog.show();
}
// Make a fake window that is always around eating graphics resources.
FakeView view = new FakeView(this);
WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
+ TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS);
@@ -124,7 +134,8 @@
}
lp.width = ViewGroup.LayoutParams.MATCH_PARENT;
lp.height = ViewGroup.LayoutParams.MATCH_PARENT;
- int maxSize = display.getMaximumSizeDimension();
+ Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
+ int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
maxSize *= 2;
lp.x = maxSize;
lp.y = maxSize;
diff --git a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
index ff09000..df00eee 100644
--- a/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
+++ b/packages/FakeOemFeatures/src/com/android/fakeoemfeatures/FakeBackgroundService.java
@@ -16,6 +16,9 @@
package com.android.fakeoemfeatures;
+import static android.view.Display.DEFAULT_DISPLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+
import java.util.ArrayList;
import java.util.Random;
@@ -23,9 +26,11 @@
import android.app.Service;
import android.content.Context;
import android.content.Intent;
+import android.hardware.display.DisplayManager;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
+import android.util.Size;
import android.view.Display;
import android.view.ViewGroup;
import android.view.WindowManager;
@@ -68,13 +73,15 @@
super.onCreate();
mHandler.sendEmptyMessageDelayed(MSG_TICK, TICK_DELAY);
- final WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
- final Display display = wm.getDefaultDisplay();
+ final DisplayManager dm = getSystemService(DisplayManager.class);
+ final Display display = dm.getDisplay(DEFAULT_DISPLAY);
+ final Context windowContext = createDisplayContext(display)
+ .createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */);
// Make a fake window that is always around eating graphics resources.
- FakeView view = new FakeView(this);
- Dialog dialog = new Dialog(this, android.R.style.Theme_Holo_Dialog);
- dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
+ FakeView view = new FakeView(windowContext);
+ Dialog dialog = new Dialog(windowContext, android.R.style.Theme_Holo_Dialog);
+ dialog.getWindow().setType(TYPE_APPLICATION_OVERLAY);
dialog.getWindow().setFlags(
WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
| WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
@@ -89,7 +96,11 @@
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.MATCH_PARENT);
WindowManager.LayoutParams lp = dialog.getWindow().getAttributes();
- int maxSize = display.getMaximumSizeDimension();
+ // Create an instance of WindowManager that is adjusted to the area of the display dedicated
+ // for windows with type TYPE_APPLICATION_OVERLAY.
+ final WindowManager wm = windowContext.getSystemService(WindowManager.class);
+ Size maxWindowSize = wm.getMaximumWindowMetrics().getSize();
+ int maxSize = Math.max(maxWindowSize.getWidth(), maxWindowSize.getHeight());
maxSize *= 2;
lp.x = maxSize;
lp.y = maxSize;
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 2b143e4..b31841d 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Gekoppel via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Beskikbaar via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tik om aan te meld"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Gekoppel, geen internet nie"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Daar kan nie by private DNS-bediener ingegaan word nie"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Beperkte verbinding"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Geen internet nie"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 2a93e017..4955ad8 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"በ <xliff:g id="NAME">%1$s</xliff:g> በኩል ተገናኝተዋል"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"በ%1$s በኩል የሚገኝ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ለመመዝገብ መታ ያድርጉ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ተገናኝቷል፣ ምንም በይነመረብ የለም"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"የግል ዲኤንኤስ አገልጋይ ሊደረስበት አይችልም"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"የተገደበ ግንኙነት"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ምንም በይነመረብ የለም"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 5103345..7b26be4 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"تم الاتصال عبر <xliff:g id="NAME">%1$s</xliff:g>."</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"متوفرة عبر %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"انقر للاشتراك."</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"متصلة ولكن بلا إنترنت"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"لا يمكن الوصول إلى خادم أسماء نظام نطاقات خاص"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"اتصال محدود"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"لا يتوفر اتصال إنترنت."</string>
diff --git a/packages/SettingsLib/res/values-as/strings.xml b/packages/SettingsLib/res/values-as/strings.xml
index fa26b9b..dcebe5b 100644
--- a/packages/SettingsLib/res/values-as/strings.xml
+++ b/packages/SettingsLib/res/values-as/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g>ৰ জৰিয়তে সংযুক্ত"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$sৰ মাধ্যমেৰে উপলব্ধ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ছাইন আপ কৰিবলৈ টিপক"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"সংযোজিত, ইণ্টাৰনেট নাই"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ব্যক্তিগত DNS ছাৰ্ভাৰ এক্সেছ কৰিব নোৱাৰি"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ইণ্টাৰনেট সংযোগ সীমিত"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ইণ্টাৰনেট সংযোগ নাই"</string>
diff --git a/packages/SettingsLib/res/values-az/strings.xml b/packages/SettingsLib/res/values-az/strings.xml
index 2e80fdc..7f3db37 100644
--- a/packages/SettingsLib/res/values-az/strings.xml
+++ b/packages/SettingsLib/res/values-az/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ilə qoşulub"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s vasitəsilə əlçatandır"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Qeydiyyatdan keçmək üçün klikləyin"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Qoşuludur, internet yoxdur"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Özəl DNS serverinə giriş mümkün deyil"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Məhdud bağlantı"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"İnternet yoxdur"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index ae5c936..b789cb0 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezano preko: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupna je preko pristupne tačke %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite da biste se registrovali"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Veza je uspostavljena, nema interneta"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Pristup privatnom DNS serveru nije uspeo"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema interneta"</string>
diff --git a/packages/SettingsLib/res/values-be/strings.xml b/packages/SettingsLib/res/values-be/strings.xml
index ad201d0..ce191eb 100644
--- a/packages/SettingsLib/res/values-be/strings.xml
+++ b/packages/SettingsLib/res/values-be/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Падключана праз праграму \"<xliff:g id="NAME">%1$s</xliff:g>\""</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Даступна праз %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Націсніце, каб зарэгістравацца"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Падключана, без доступу да інтэрнэту"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Не ўдалося атрымаць доступ да прыватнага DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Абмежаваныя магчымасці падключэння"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Не падключана да інтэрнэту"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 94f78ad..3e6f77d 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Установена е връзка през <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Мрежата е достъпна през „%1$s“"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Докоснете, за да се регистрирате"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Установена е връзка – няма достъп до интернет"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Не може да се осъществи достъп до частния DNS сървър"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена връзка"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Няма връзка с интернет"</string>
diff --git a/packages/SettingsLib/res/values-bn/strings.xml b/packages/SettingsLib/res/values-bn/strings.xml
index 51719160..7f6938a 100644
--- a/packages/SettingsLib/res/values-bn/strings.xml
+++ b/packages/SettingsLib/res/values-bn/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g>-এর মাধ্যমে কানেক্ট করা আছে"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s এর মাধ্যমে উপলব্ধ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"সাইন-আপ করতে ট্যাপ করুন"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"কানেক্ট, ইন্টারনেট নেই"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ব্যক্তিগত ডিএনএস সার্ভার অ্যাক্সেস করা যাবে না"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"সীমিত কানেকশন"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ইন্টারনেট কানেকশন নেই"</string>
diff --git a/packages/SettingsLib/res/values-bs/strings.xml b/packages/SettingsLib/res/values-bs/strings.xml
index f74bcee..0563abd 100644
--- a/packages/SettingsLib/res/values-bs/strings.xml
+++ b/packages/SettingsLib/res/values-bs/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezano preko <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupan preko %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite za prijavu"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Povezano, nema interneta"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Nije moguće pristupiti privatnom DNS serveru"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema internetske veze"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 1b23ecf..71b2c5d 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connectat mitjançant <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible mitjançant %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca per registrar-te"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connectada, sense Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"No es pot accedir al servidor DNS privat"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexió limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sense connexió a Internet"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 22603cc..a381772 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Připojeno přes <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupné prostřednictvím %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Klepnutím se zaregistrujete"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Připojeno, není k dispozici internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Nelze získat přístup k soukromému serveru DNS"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Omezené připojení"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nejste připojeni k internetu"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index bef1855..f6e8576 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Forbundet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tilgængelig via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tryk for at registrere dig"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Tilsluttet – intet internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Der er ikke adgang til den private DNS-server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begrænset forbindelse"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Intet internet"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index c8c97bd..99a0910 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Verbunden über <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Verfügbar über %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Zum Anmelden tippen"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Verbunden, kein Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Auf den privaten DNS-Server kann nicht zugegriffen werden"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Eingeschränkte Verbindung"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Kein Internet"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index 371075c..d37ea44 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Συνδέθηκε μέσω <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Διαθέσιμο μέσω %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Πατήστε για εγγραφή"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Συνδέθηκε, χωρίς σύνδεση στο διαδίκτυο"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Δεν είναι δυνατή η πρόσβαση στον ιδιωτικό διακομιστή DNS."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Περιορισμένη σύνδεση"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Δεν υπάρχει σύνδεση στο διαδίκτυο"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b314d17..429cd3e 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connected, no Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
diff --git a/packages/SettingsLib/res/values-en-rCA/strings.xml b/packages/SettingsLib/res/values-en-rCA/strings.xml
index b314d17..429cd3e 100644
--- a/packages/SettingsLib/res/values-en-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-en-rCA/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connected, no Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b314d17..429cd3e 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connected, no Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b314d17..429cd3e 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connected, no Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No Internet"</string>
diff --git a/packages/SettingsLib/res/values-en-rXC/strings.xml b/packages/SettingsLib/res/values-en-rXC/strings.xml
index 95944dc..1aa6cdb 100644
--- a/packages/SettingsLib/res/values-en-rXC/strings.xml
+++ b/packages/SettingsLib/res/values-en-rXC/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connected via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tap to sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connected, no internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Private DNS server cannot be accessed"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limited connection"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"No internet"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index c6dfdd3..7d28a32 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conexión a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Presiona para registrarte"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conectado pero sin conexión a Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"No se puede acceder al servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexión limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sin Internet"</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index ba4a9ff..b35696f5 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca para registrarte"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conexión sin Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"No se ha podido acceder al servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexión limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sin Internet"</string>
diff --git a/packages/SettingsLib/res/values-et/strings.xml b/packages/SettingsLib/res/values-et/strings.xml
index df3b792..b6c112b 100644
--- a/packages/SettingsLib/res/values-et/strings.xml
+++ b/packages/SettingsLib/res/values-et/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ühendatud võrgu <xliff:g id="NAME">%1$s</xliff:g> kaudu"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Saadaval üksuse %1$s kaudu"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Puudutage registreerumiseks"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Ühendatud, Interneti-ühendus puudub"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Privaatsele DNS-serverile ei pääse juurde"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Piiratud ühendus"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Interneti-ühendus puudub"</string>
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index fcb320f..4fd9add 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> bidez konektatuta"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s bidez erabilgarri"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Sakatu erregistratzeko"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Konektatuta; ezin da atzitu Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Ezin da atzitu DNS zerbitzari pribatua"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Konexio mugatua"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ez dago Interneteko konexiorik"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 261a438..32a98be 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"متصل شده ازطریق <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"در دسترس از طریق %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"برای ثبتنام ضربه بزنید"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"متصل، بدون اینترنت"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"سرور DNS خصوصی قابل دسترسی نیست"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"اتصال محدود"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"عدم دسترسی به اینترنت"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index 4ccf430..84c5372 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Yhdistetty (<xliff:g id="NAME">%1$s</xliff:g>)"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Käytettävissä seuraavan kautta: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Rekisteröidy napauttamalla"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Yhdistetty, ei internetyhteyttä"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Ei pääsyä yksityiselle DNS-palvelimelle"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Rajallinen yhteys"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ei internetyhteyttä"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 84a9797..995eab6 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connecté sur le réseau <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Accessible par %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toucher pour vous connecter"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connecté, aucun accès à Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Impossible d\'accéder au serveur DNS privé"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexion limitée"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Aucune connexion Internet"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 030a7f9..2afacab 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connecté via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponible via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Appuyez ici pour vous connecter"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connecté, aucun accès à Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Impossible d\'accéder au serveur DNS privé"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connexion limitée"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Aucun accès à Internet"</string>
@@ -57,7 +58,7 @@
<string name="osu_sign_up_complete" msgid="7640183358878916847">"Inscription terminée. Connexion…"</string>
<string name="speed_label_very_slow" msgid="8526005255731597666">"Très lente"</string>
<string name="speed_label_slow" msgid="6069917670665664161">"Lente"</string>
- <string name="speed_label_okay" msgid="1253594383880810424">"Correct"</string>
+ <string name="speed_label_okay" msgid="1253594383880810424">"Correcte"</string>
<string name="speed_label_medium" msgid="9078405312828606976">"Moyenne"</string>
<string name="speed_label_fast" msgid="2677719134596044051">"Élevée"</string>
<string name="speed_label_very_fast" msgid="8215718029533182439">"Très rapide"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index af033cf..a106e60 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Wifi conectada a través de <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dispoñible a través de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toca para rexistrarte"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conexión sen Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Non se puido acceder ao servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Pouca conexión"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Non hai conexión a Internet"</string>
@@ -316,7 +317,7 @@
<string name="usb_audio_disable_routing" msgid="3367656923544254975">"Desactivar encamiñamento audio USB"</string>
<string name="usb_audio_disable_routing_summary" msgid="8768242894849534699">"Desactiva o encamiñamento automático a periféricos de audio USB"</string>
<string name="debug_layout" msgid="1659216803043339741">"Mostrar límites de deseño"</string>
- <string name="debug_layout_summary" msgid="8825829038287321978">"Mostra os límites dos clips, as marxes, etc."</string>
+ <string name="debug_layout_summary" msgid="8825829038287321978">"Mostra os límites dos clips, as marxes etc."</string>
<string name="force_rtl_layout_all_locales" msgid="8690762598501599796">"Forzar dirección do deseño RTL"</string>
<string name="force_rtl_layout_all_locales_summary" msgid="6663016859517239880">"Forza a dirección de pantalla a RTL (dereita a esquerda) para todas as configuración rexionais"</string>
<string name="force_msaa" msgid="4081288296137775550">"Forzar MSAA 4x"</string>
diff --git a/packages/SettingsLib/res/values-gu/strings.xml b/packages/SettingsLib/res/values-gu/strings.xml
index 87fd876..5f2d5cd 100644
--- a/packages/SettingsLib/res/values-gu/strings.xml
+++ b/packages/SettingsLib/res/values-gu/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> દ્વારા કનેક્ટ થયેલ"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s દ્વારા ઉપલબ્ધ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"સાઇન અપ કરવા માટે ટૅપ કરો"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"કનેક્ટ કર્યું, કોઈ ઇન્ટરનેટ નથી"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ખાનગી DNS સર્વર ઍક્સેસ કરી શકાતા નથી"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"મર્યાદિત કનેક્શન"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ઇન્ટરનેટ ઍક્સેસ નથી"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 02b5c96..d60eead 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> के ज़रिए कनेक्ट किया गया"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s के द्वारा उपलब्ध"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"साइन अप करने के लिए टैप करें"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"कनेक्ट हो गया है, लेकिन इंटरनेट नहीं है"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"निजी डीएनएस सर्वर को ऐक्सेस नहीं किया जा सकता"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"सीमित कनेक्शन"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इंटरनेट कनेक्शन नहीं है"</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index 598cfe2..28e3460 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezan putem mreže <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostupno putem %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dodirnite da biste se registrirali"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Povezano, bez interneta"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Nije moguće pristupiti privatnom DNS poslužitelju"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograničena veza"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nema interneta"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index d970c73..22e03a7 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Kapcsolódva a következőn keresztül: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Elérhető a következőn keresztül: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Koppintson a regisztrációhoz"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Csatlakozva, nincs internet-hozzáférés"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"A privát DNS-kiszolgálóhoz nem lehet hozzáférni"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Korlátozott kapcsolat"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nincs internetkapcsolat"</string>
diff --git a/packages/SettingsLib/res/values-hy/strings.xml b/packages/SettingsLib/res/values-hy/strings.xml
index 9086934..ecb615a 100644
--- a/packages/SettingsLib/res/values-hy/strings.xml
+++ b/packages/SettingsLib/res/values-hy/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Միացված է <xliff:g id="NAME">%1$s</xliff:g>-ի միջոցով"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Հասանելի է %1$s-ի միջոցով"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Հպեք՝ գրանցվելու համար"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Միացված է, սակայն ինտերնետ կապ չկա"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Մասնավոր DNS սերվերն անհասանելի է"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Սահմանափակ կապ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ինտերնետ կապ չկա"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 3c1504c..cfbda04 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tersambung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ketuk untuk mendaftar"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Tersambung, tidak ada internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Server DNS pribadi tidak dapat diakses"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Koneksi terbatas"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Tidak ada internet"</string>
diff --git a/packages/SettingsLib/res/values-is/strings.xml b/packages/SettingsLib/res/values-is/strings.xml
index 438e900..ba4c009 100644
--- a/packages/SettingsLib/res/values-is/strings.xml
+++ b/packages/SettingsLib/res/values-is/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tenging í gegnum <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Í boði í gegnum %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ýttu til að skrá þig"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Tengt, enginn netaðgangur"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Ekki næst í DNS-einkaþjón"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Takmörkuð tenging"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Engin nettenging"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 114b33b..50e5777 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Connesso tramite <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponibile tramite %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tocca per registrarti"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Connesso, senza Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Non è possibile accedere al server DNS privato"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Connessione limitata"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nessuna connessione a Internet"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 62085a8..9f1e457 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"מחוברת באמצעות <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"זמינה דרך %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"יש להקיש כדי להירשם"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"מחובר. אין אינטרנט"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"לא ניתן לגשת לשרת DNS הפרטי"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"חיבור מוגבל"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"אין אינטרנט"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 28b98ee..47020ed 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> で接続しました"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s経由で使用可能"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"タップして登録してください"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"接続済み、インターネット接続なし"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"プライベート DNS サーバーにアクセスできません"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"接続が制限されています"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"インターネット未接続"</string>
diff --git a/packages/SettingsLib/res/values-ka/strings.xml b/packages/SettingsLib/res/values-ka/strings.xml
index 6f5d0b3..116488d 100644
--- a/packages/SettingsLib/res/values-ka/strings.xml
+++ b/packages/SettingsLib/res/values-ka/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"დაკავშირებულია <xliff:g id="NAME">%1$s</xliff:g>-ით"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"ხელმისაწვდომია %1$s-ით"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"შეეხეთ რეგისტრაციისთვის"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"დაკავშირებულია, ინტერნეტის გარეშე"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"პირად DNS სერვერზე წვდომა შეუძლებელია"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"შეზღუდული კავშირი"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ინტერნეტ-კავშირი არ არის"</string>
diff --git a/packages/SettingsLib/res/values-kk/strings.xml b/packages/SettingsLib/res/values-kk/strings.xml
index 3fe426e..3c4fdb7 100644
--- a/packages/SettingsLib/res/values-kk/strings.xml
+++ b/packages/SettingsLib/res/values-kk/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> арқылы жалғанған"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s арқылы қолжетімді"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Тіркелу үшін түртіңіз."</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Қосылған, интернет жоқ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Жеке DNS серверіне кіру мүмкін емес."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Шектеулі байланыс"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернетпен байланыс жоқ"</string>
diff --git a/packages/SettingsLib/res/values-km/strings.xml b/packages/SettingsLib/res/values-km/strings.xml
index 24bfa35..87a4f19 100644
--- a/packages/SettingsLib/res/values-km/strings.xml
+++ b/packages/SettingsLib/res/values-km/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"ភ្ជាប់តាម <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"មានតាមរយៈ %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ចុចដើម្បីចុះឈ្មោះ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"បានភ្ជាប់ ប៉ុន្តែគ្មានអ៊ីនធឺណិតទេ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"មិនអាចចូលប្រើម៉ាស៊ីនមេ DNS ឯកជនបានទេ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ការតភ្ជាប់មានកម្រិត"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"គ្មានអ៊ីនធឺណិតទេ"</string>
diff --git a/packages/SettingsLib/res/values-kn/strings.xml b/packages/SettingsLib/res/values-kn/strings.xml
index 0699bbc..144dddb 100644
--- a/packages/SettingsLib/res/values-kn/strings.xml
+++ b/packages/SettingsLib/res/values-kn/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ಆ್ಯಪ್ ಮೂಲಕ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ಮೂಲಕ ಲಭ್ಯವಿದೆ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ಸೈನ್ ಅಪ್ ಮಾಡಲು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ, ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ಖಾಸಗಿ DNS ಸರ್ವರ್ ಅನ್ನು ಪ್ರವೇಶಿಸಲು ಸಾಧ್ಯವಿಲ್ಲ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ಸೀಮಿತ ಸಂಪರ್ಕ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ಇಂಟರ್ನೆಟ್ ಇಲ್ಲ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 25e9cfe..df9f21d 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g>을(를) 통해 연결됨"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s을(를) 통해 사용 가능"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"탭하여 가입"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"연결됨, 인터넷 사용 불가"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"비공개 DNS 서버에 액세스할 수 없습니다."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"제한된 연결"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"인터넷 연결 없음"</string>
diff --git a/packages/SettingsLib/res/values-ky/strings.xml b/packages/SettingsLib/res/values-ky/strings.xml
index 3dfce1e..13c4144 100644
--- a/packages/SettingsLib/res/values-ky/strings.xml
+++ b/packages/SettingsLib/res/values-ky/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> аркылуу туташты"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s аркылуу жеткиликтүү"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Катталуу үчүн таптап коюңуз"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Туташып турат, Интернет жок"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Жеке DNS сервери жеткиликсиз"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Байланыш чектелген"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернет жок"</string>
diff --git a/packages/SettingsLib/res/values-lo/strings.xml b/packages/SettingsLib/res/values-lo/strings.xml
index 48e5093..48224f4 100644
--- a/packages/SettingsLib/res/values-lo/strings.xml
+++ b/packages/SettingsLib/res/values-lo/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"ເຊື່ອມຕໍ່ຜ່ານ <xliff:g id="NAME">%1$s</xliff:g> ແລ້ວ"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"ມີໃຫ້ຜ່ານ %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ແຕະເພື່ອສະໝັກ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ເຊື່ອມຕໍ່ແລ້ວ, ບໍ່ມີອິນເຕີເນັດ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ບໍ່ສາມາດເຂົ້າເຖິງເຊີບເວີ DNS ສ່ວນຕົວໄດ້"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ການເຊື່ອມຕໍ່ຈຳກັດ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ບໍ່ມີອິນເຕີເນັດ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 8b3fbad..d080334 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Prisijungta naudojant programą „<xliff:g id="NAME">%1$s</xliff:g>“"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Pasiekiama naudojant „%1$s“"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Palieskite, kad prisiregistruotumėte"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Prisijungta, nėra interneto"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Privataus DNS serverio negalima pasiekti"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ribotas ryšys"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nėra interneto ryšio"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 4fc5b22..e13a50d 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Savienojums ar <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Pieejams, izmantojot %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Pieskarieties, lai reģistrētos"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Savienojums izveidots, nav piekļuves internetam"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Nevar piekļūt privātam DNS serverim."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ierobežots savienojums"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nav piekļuves internetam"</string>
diff --git a/packages/SettingsLib/res/values-mk/strings.xml b/packages/SettingsLib/res/values-mk/strings.xml
index 288e526..d027ffe 100644
--- a/packages/SettingsLib/res/values-mk/strings.xml
+++ b/packages/SettingsLib/res/values-mk/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Поврзано преку <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Достапно преку %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Допрете за да се регистрирате"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Поврзана, нема интернет"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Не може да се пристапи до приватниот DNS-сервер"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена врска"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нема интернет"</string>
diff --git a/packages/SettingsLib/res/values-ml/strings.xml b/packages/SettingsLib/res/values-ml/strings.xml
index e775297..e2a3d9f 100644
--- a/packages/SettingsLib/res/values-ml/strings.xml
+++ b/packages/SettingsLib/res/values-ml/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> മുഖേന കണക്റ്റ് ചെയ്തു"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s വഴി ലഭ്യം"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"സൈൻ അപ്പ് ചെയ്യാൻ ടാപ്പ് ചെയ്യുക"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"കണക്റ്റ് ചെയ്തു, ഇന്റർനെറ്റ് ഇല്ല"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"സ്വകാര്യ DNS സെർവർ ആക്സസ് ചെയ്യാനാവില്ല"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"പരിമിത കണക്ഷൻ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ഇന്റർനെറ്റ് ഇല്ല"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index ba69f9b..dd08c9e 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g>-р холбогдсон"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s-р боломжтой"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Бүртгүүлэхийн тулд товшино уу"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Холбогдсон хэдий ч интернет алга"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Хувийн DNS серверт хандах боломжгүй байна"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Хязгаарлагдмал холболт"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Интернэт алга"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 1930cdf..fb7cd1f 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> द्वारे कनेक्ट केले"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s द्वारे उपलब्ध"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"साइन अप करण्यासाठी टॅप करा"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"कनेक्ट केले, इंटरनेट नाही"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"खाजगी DNS सर्व्हर ॲक्सेस करू शकत नाही"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"मर्यादित कनेक्शन"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इंटरनेट नाही"</string>
diff --git a/packages/SettingsLib/res/values-ms/strings.xml b/packages/SettingsLib/res/values-ms/strings.xml
index e493188..72b15ff 100644
--- a/packages/SettingsLib/res/values-ms/strings.xml
+++ b/packages/SettingsLib/res/values-ms/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Disambungkan melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ketik untuk daftar"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Disambungkan, tiada Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Pelayan DNS peribadi tidak boleh diakses"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Sambungan terhad"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Tiada Internet"</string>
diff --git a/packages/SettingsLib/res/values-my/strings.xml b/packages/SettingsLib/res/values-my/strings.xml
index 2c4b32c..24017ec 100644
--- a/packages/SettingsLib/res/values-my/strings.xml
+++ b/packages/SettingsLib/res/values-my/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> မှတစ်ဆင့် ချိတ်ဆက်ထားသည်"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s မှတစ်ဆင့်ရနိုင်သည်"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"အကောင့်ဖွင့်ရန် တို့ပါ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ချိတ်ဆက်ထားသည်၊ အင်တာနက်မရှိ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"သီးသန့် ဒီအန်အက်စ် (DNS) ဆာဗာကို သုံး၍မရပါ။"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ချိတ်ဆက်မှု ကန့်သတ်ထားသည်"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"အင်တာနက် မရှိပါ"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index 093c06f..aca13a7 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Tilkoblet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tilgjengelig via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Trykk for å registrere deg"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Tilkoblet – ingen Internett-tilgang"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Den private DNS-tjeneren kan ikke nås"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begrenset tilkobling"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ingen internettilkobling"</string>
diff --git a/packages/SettingsLib/res/values-ne/strings.xml b/packages/SettingsLib/res/values-ne/strings.xml
index fb8b737..b2c7518 100644
--- a/packages/SettingsLib/res/values-ne/strings.xml
+++ b/packages/SettingsLib/res/values-ne/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> मार्फत जडान गरिएको"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s मार्फत उपलब्ध"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"साइन अप गर्न ट्याप गर्नुहोस्"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"जडान गरियो तर इन्टरनेट छैन"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"निजी DNS सर्भरमाथि पहुँच प्राप्त गर्न सकिँदैन"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"सीमित जडान"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"इन्टरनेटमाथिको पहुँच छैन"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 267dab4..c74683b 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Verbonden via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Beschikbaar via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tik om aan te melden"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Verbonden, geen internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Geen toegang tot privé-DNS-server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Beperkte verbinding"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Geen internet"</string>
diff --git a/packages/SettingsLib/res/values-or/strings.xml b/packages/SettingsLib/res/values-or/strings.xml
index d8ae3bf..704fc42 100644
--- a/packages/SettingsLib/res/values-or/strings.xml
+++ b/packages/SettingsLib/res/values-or/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ଦ୍ବାରା ସଂଯୋଗ କରାଯାଇଛି"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ମାଧ୍ୟମରେ ଉପଲବ୍ଧ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ସାଇନ୍ ଅପ୍ ପାଇଁ ଟାପ୍ କରନ୍ତୁ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ସଂଯୁକ୍ତ, ଇଣ୍ଟର୍ନେଟ୍ ନାହିଁ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ବ୍ୟକ୍ତିଗତ DNS ସର୍ଭର୍ ଆକ୍ସେସ୍ କରିହେବ ନାହିଁ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ସୀମିତ ସଂଯୋଗ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"କୌଣସି ଇଣ୍ଟରନେଟ୍ ନାହିଁ"</string>
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 6a78486..bf5a32c 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ਰਾਹੀਂ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ਰਾਹੀਂ ਉਪਲਬਧ"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ਸਾਈਨ-ਅੱਪ ਕਰਨ ਲਈ ਟੈਪ ਕਰੋ"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"ਕਨੈਕਟ ਕੀਤਾ, ਕੋਈ ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ਨਿੱਜੀ ਡੋਮੇਨ ਨਾਮ ਪ੍ਰਣਾਲੀ (DNS) ਸਰਵਰ \'ਤੇ ਪਹੁੰਚ ਨਹੀਂ ਕੀਤੀ ਜਾ ਸਕੀ"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"ਸੀਮਤ ਕਨੈਕਸ਼ਨ"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ਇੰਟਰਨੈੱਟ ਨਹੀਂ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index 8c5547c..d907760 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Połączenie przez: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Dostępne przez %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Kliknij, by się zarejestrować"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Połączono, brak internetu"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Brak dostępu do prywatnego serwera DNS"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ograniczone połączenie"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Brak internetu"</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 8c03616..e61c84e 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conectada, sem Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível acessar o servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexão limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index 6aeff1c..8ceeb63 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ligado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível através de %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Ligado, sem Internet."</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível aceder ao servidor DNS."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ligação limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 8c03616..e61c84e 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectado via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponível via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Toque para se inscrever"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conectada, sem Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Não é possível acessar o servidor DNS privado"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexão limitada"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Sem Internet"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index 387441f..5ad8dfd 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Conectat prin <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Disponibilă prin %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Atingeți pentru a vă înscrie"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Conectată, fără internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Serverul DNS privat nu poate fi accesat"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Conexiune limitată"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Fără conexiune la internet"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index 361e29f..104efdc 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Подключено через приложение \"<xliff:g id="NAME">%1$s</xliff:g>\"."</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Доступно через %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Нажмите, чтобы зарегистрироваться"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Подключено, без доступа к Интернету"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Доступа к частному DNS-серверу нет."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Подключение к сети ограничено."</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нет подключения к Интернету"</string>
diff --git a/packages/SettingsLib/res/values-si/strings.xml b/packages/SettingsLib/res/values-si/strings.xml
index faa848f..f5dad87 100644
--- a/packages/SettingsLib/res/values-si/strings.xml
+++ b/packages/SettingsLib/res/values-si/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> හරහා සම්බන්ධයි"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s හරහා ලබා ගැනීමට හැකිය"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"ලියාපදිංචි වීමට තට්ටු කරන්න"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"සම්බන්ධයි, අන්තර්ජාලය නැත"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"පුද්ගලික DNS සේවාදායකයට ප්රවේශ වීමට නොහැකිය"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"සීමිත සම්බන්ධතාව"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"අන්තර්ජාලය නැත"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index 2035d88c..527dafb 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Pripojené prostredníctvom siete <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"K dispozícii prostredníctvom %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Prihláste sa klepnutím"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Pripojené, žiadny internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"K súkromnému serveru DNS sa nepodarilo získať prístup"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Obmedzené pripojenie"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Žiadny internet"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index 2889619..4816950 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Povezava vzpostavljena prek omrežja <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Na voljo prek: %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Dotaknite se, če se želite registrirati"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Vzpostavljena povezava, brez interneta"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Do zasebnega strežnika DNS ni mogoče dostopati"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Omejena povezava"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Brez internetne povezave"</string>
diff --git a/packages/SettingsLib/res/values-sq/strings.xml b/packages/SettingsLib/res/values-sq/strings.xml
index ccd4e306..12511dd3 100644
--- a/packages/SettingsLib/res/values-sq/strings.xml
+++ b/packages/SettingsLib/res/values-sq/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Lidhur përmes <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"E mundshme përmes %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Trokit për t\'u regjistruar"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"U lidh, por nuk ka internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Serveri privat DNS nuk mund të qaset"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Lidhje e kufizuar"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Nuk ka internet"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 08e2bc8..4724be5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Повезано преко: <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Доступна је преко приступне тачке %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Додирните да бисте се регистровали"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Веза је успостављена, нема интернета"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Приступ приватном DNS серверу није успео"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Ограничена веза"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Нема интернета"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index c0cdbc9..9d1bc42 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Anslutet via <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tillgängligt via %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Tryck för att logga in"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Ansluten, inget internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Det går inte att komma åt den privata DNS-servern."</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Begränsad anslutning"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Inget internet"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index f00dea3..1e2489f 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Imeunganishwa kupitia <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Inapatikana kupitia %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Gusa ili ujisajili"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Imeunganishwa, hakuna intaneti"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Seva ya faragha ya DNS haiwezi kufikiwa"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Muunganisho hafifu"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Hakuna intaneti"</string>
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 52e0363..fcb801b 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> மூலம் இணைக்கப்பட்டது"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s வழியாகக் கிடைக்கிறது"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"பதிவு செய்யத் தட்டவும்"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"இணைக்கப்பட்டுள்ளது, ஆனால் இண்டர்நெட் இல்லை"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"தனிப்பட்ட DNS சேவையகத்தை அணுக இயலாது"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"வரம்பிற்கு உட்பட்ட இணைப்பு"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"இணைய இணைப்பு இல்லை"</string>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index a39c4e1..7a80451 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ద్వారా కనెక్ట్ చేయబడింది"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s ద్వారా అందుబాటులో ఉంది"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"సైన్ అప్ చేయడానికి నొక్కండి"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"కనెక్ట్ చేయబడింది, ఇంటర్నెట్ లేదు"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"ప్రైవేట్ DNS సర్వర్ను యాక్సెస్ చేయడం సాధ్యపడదు"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"పరిమిత కనెక్షన్"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ఇంటర్నెట్ లేదు"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index 635d77a..130e1c4 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"เชื่อมต่อแล้วผ่าน <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"พร้อมใช้งานผ่านทาง %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"แตะเพื่อลงชื่อสมัครใช้"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"เชื่อมต่อแล้ว ไม่พบอินเทอร์เน็ต"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"เข้าถึงเซิร์ฟเวอร์ DNS ไม่ได้"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"การเชื่อมต่อที่จำกัด"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"ไม่มีอินเทอร์เน็ต"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 3f7f0ff..bc1a405 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Nakakonekta sa pamamagitan ng <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Available sa pamamagitan ng %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"I-tap para mag-sign up"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Nakakonekta, walang internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Hindi ma-access ang pribadong DNS server"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Limitadong koneksyon"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Walang internet"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index 7ad6fcd..4e263ef 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> ile bağlandı"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s üzerinden kullanılabilir"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Kaydolmak için dokunun"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Bağlı, internet yok"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Gizli DNS sunucusuna erişilemiyor"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Sınırlı bağlantı"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"İnternet yok"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index b5dd618..ad9f600 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Підключено через додаток <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Доступ через %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Торкніться, щоб увійти"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Під’єднано, але немає доступу до Інтернету"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Немає доступу до приватного DNS-сервера"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Обмежене з’єднання"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Немає Інтернету"</string>
diff --git a/packages/SettingsLib/res/values-ur/strings.xml b/packages/SettingsLib/res/values-ur/strings.xml
index ef9b2a1..b995da1 100644
--- a/packages/SettingsLib/res/values-ur/strings.xml
+++ b/packages/SettingsLib/res/values-ur/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> کے ذریعے منسلک"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"دستیاب بذریعہ %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"سائن اپ کے لیے تھپتھپائیں"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"منسلک، انٹرنیٹ نہیں ہے"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"نجی DNS سرور تک رسائی حاصل نہیں کی جا سکی"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"محدود کنکشن"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"انٹرنیٹ نہیں ہے"</string>
diff --git a/packages/SettingsLib/res/values-uz/strings.xml b/packages/SettingsLib/res/values-uz/strings.xml
index b202d64..f02b639 100644
--- a/packages/SettingsLib/res/values-uz/strings.xml
+++ b/packages/SettingsLib/res/values-uz/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"<xliff:g id="NAME">%1$s</xliff:g> orqali ulandi"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"%1$s orqali ishlaydi"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Yozilish uchun bosing"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Ulangan, lekin internet aloqasi yo‘q"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Xususiy DNS server ishlamayapti"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Cheklangan aloqa"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Internet yo‘q"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 5bcff5a..8fcf1f2 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Đã kết nối qua <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Có sẵn qua %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Nhấn để đăng ký"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Đã kết nối, không có Internet"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Không thể truy cập máy chủ DNS riêng tư"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Kết nối giới hạn"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Không có Internet"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 418370b..755cbee 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"已通过<xliff:g id="NAME">%1$s</xliff:g>连接到网络"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"可通过%1$s连接"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"点按即可注册"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"已连接,但无法访问互联网"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"无法访问私人 DNS 服务器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"网络连接受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"无法访问互联网"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index 79b5579..e50acf5 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"已透過「<xliff:g id="NAME">%1$s</xliff:g>」連線"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"可透過 %1$s 連線"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"輕按即可登入"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"已連線,但沒有互聯網"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"無法存取私人 DNS 伺服器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"連線受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"沒有互聯網連線"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index 47ab764..7df6fed 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"透過「<xliff:g id="NAME">%1$s</xliff:g>」連線"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"可透過 %1$s 使用"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"輕觸即可註冊"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"已連線,沒有網際網路"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"無法存取私人 DNS 伺服器"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"連線能力受限"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"沒有網際網路連線"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index 87f45de..46dffbe 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -42,7 +42,8 @@
<string name="connected_via_app" msgid="3532267661404276584">"Ixhumeke nge-<xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Iyatholakala nge-%1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Thepha ukuze ubhalisele"</string>
- <string name="wifi_connected_no_internet" msgid="2381729074310543563">"Kuxhunyiwe, ayikho i-inthanethi"</string>
+ <!-- no translation found for wifi_connected_no_internet (5087420713443350646) -->
+ <skip />
<string name="private_dns_broken" msgid="1984159464346556931">"Iseva eyimfihlo ye-DNS ayikwazi ukufinyelelwa"</string>
<string name="wifi_limited_connection" msgid="1184778285475204682">"Iqoqo elikhawulelwe"</string>
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Ayikho i-inthanethi"</string>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index a7df6db..dd21e5c 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -129,7 +129,7 @@
<string name="certinstaller_package" translatable="false">com.android.certinstaller</string>
<!-- Summary for Connected wifi network without internet -->
- <string name="wifi_connected_no_internet">Connected, no internet</string>
+ <string name="wifi_connected_no_internet">No internet</string>
<!-- Summary for connected network without internet due to private dns validation failed [CHAR LIMIT=NONE] -->
<string name="private_dns_broken">Private DNS server cannot be accessed</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
index aac7fc3..d48aa24 100644
--- a/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
+++ b/packages/SettingsLib/src/com/android/settingslib/datetime/ZoneGetter.java
@@ -402,7 +402,7 @@
private static List<String> extractTimeZoneIds(List<TimeZoneMapping> timeZoneMappings) {
final List<String> zoneIds = new ArrayList<>(timeZoneMappings.size());
for (TimeZoneMapping timeZoneMapping : timeZoneMappings) {
- zoneIds.add(timeZoneMapping.timeZoneId);
+ zoneIds.add(timeZoneMapping.getTimeZoneId());
}
return Collections.unmodifiableList(zoneIds);
}
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index e008cd03..a4be46c 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -40,15 +40,16 @@
final Executor mExecutor = Executors.newSingleThreadExecutor();
@VisibleForTesting
MediaRouter2Manager mRouterManager;
+ @VisibleForTesting
+ String mPackageName;
- private String mPackageName;
private MediaDevice mCurrentConnectedDevice;
public InfoMediaManager(Context context, String packageName, Notification notification) {
super(context, notification);
mRouterManager = MediaRouter2Manager.getInstance(context);
- if (packageName != null) {
+ if (!TextUtils.isEmpty(packageName)) {
mPackageName = packageName;
}
}
@@ -57,6 +58,7 @@
public void startScan() {
mMediaDevices.clear();
mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
+ refreshDevices();
}
@VisibleForTesting
@@ -79,21 +81,37 @@
return mCurrentConnectedDevice;
}
- class RouterManagerCallback extends MediaRouter2Manager.Callback {
-
- private void refreshDevices() {
- mMediaDevices.clear();
- mCurrentConnectedDevice = null;
- for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
- final MediaDevice device = new InfoMediaDevice(mContext, mRouterManager, route,
- mPackageName);
- if (TextUtils.equals(route.getClientPackageName(), mPackageName)) {
- mCurrentConnectedDevice = device;
- }
- mMediaDevices.add(device);
- }
- dispatchDeviceListAdded();
+ private void refreshDevices() {
+ mMediaDevices.clear();
+ mCurrentConnectedDevice = null;
+ if (TextUtils.isEmpty(mPackageName)) {
+ buildAllRoutes();
+ } else {
+ buildAvailableRoutes();
}
+ dispatchDeviceListAdded();
+ }
+
+ private void buildAllRoutes() {
+ for (MediaRoute2Info route : mRouterManager.getAllRoutes()) {
+ final MediaDevice device = new InfoMediaDevice(mContext, mRouterManager, route,
+ mPackageName);
+ mMediaDevices.add(device);
+ }
+ }
+
+ private void buildAvailableRoutes() {
+ for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
+ final MediaDevice device = new InfoMediaDevice(mContext, mRouterManager, route,
+ mPackageName);
+ if (TextUtils.equals(route.getClientPackageName(), mPackageName)) {
+ mCurrentConnectedDevice = device;
+ }
+ mMediaDevices.add(device);
+ }
+ }
+
+ class RouterManagerCallback extends MediaRouter2Manager.Callback {
@Override
public void onRoutesAdded(List<MediaRoute2Info> routes) {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index e85a102..50196d2 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -18,7 +18,6 @@
import android.app.Notification;
import android.bluetooth.BluetoothProfile;
import android.content.Context;
-import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.IntDef;
@@ -162,10 +161,8 @@
mMediaDevices.clear();
mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
mBluetoothMediaManager.startScan();
- if (!TextUtils.isEmpty(mPackageName)) {
- mInfoMediaManager.registerCallback(mMediaDeviceCallback);
- mInfoMediaManager.startScan();
- }
+ mInfoMediaManager.registerCallback(mMediaDeviceCallback);
+ mInfoMediaManager.startScan();
}
private void addPhoneDeviceIfNecessary() {
@@ -208,10 +205,8 @@
public void stopScan() {
mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
mBluetoothMediaManager.stopScan();
- if (!TextUtils.isEmpty(mPackageName)) {
- mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
- mInfoMediaManager.stopScan();
- }
+ mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
+ mInfoMediaManager.stopScan();
}
/**
diff --git a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
index 84dde05..44e70f4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
+++ b/packages/SettingsLib/src/com/android/settingslib/wifi/AccessPoint.java
@@ -654,7 +654,7 @@
}
}
}
- return oldMetering == mIsScoredNetworkMetered;
+ return oldMetering != mIsScoredNetworkMetered;
}
/**
@@ -1170,8 +1170,8 @@
} else { // In range, not disabled.
if (mConfig != null) { // Is saved network
// Last attempt to connect to this failed. Show reason why
- switch (mConfig.recentFailure.getAssociationStatus()) {
- case WifiConfiguration.RecentFailure.STATUS_AP_UNABLE_TO_HANDLE_NEW_STA:
+ switch (mConfig.getRecentFailureReason()) {
+ case WifiConfiguration.RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA:
summary.append(mContext.getString(
R.string.wifi_ap_unable_to_handle_new_sta));
break;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index 67f6dd90..3726fb2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -74,7 +74,7 @@
}
@Test
- public void onRouteAdded_shouldAddMediaDevice() {
+ public void onRouteAdded_getAvailableRoutes_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
@@ -95,6 +95,27 @@
}
@Test
+ public void onRouteAdded_buildAllRoutes_shouldAddMediaDevice() {
+ final MediaRoute2Info info = mock(MediaRoute2Info.class);
+ when(info.getId()).thenReturn(TEST_ID);
+ when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+ final List<MediaRoute2Info> routes = new ArrayList<>();
+ routes.add(info);
+ when(mRouterManager.getAllRoutes()).thenReturn(routes);
+
+ final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
+ assertThat(mediaDevice).isNull();
+
+ mInfoMediaManager.mPackageName = "";
+ mInfoMediaManager.mMediaRouterCallback.onRoutesAdded(routes);
+
+ final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
+ assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+ assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+ }
+
+ @Test
public void onControlCategoriesChanged_samePackageName_shouldAddMediaDevice() {
final MediaRoute2Info info = mock(MediaRoute2Info.class);
when(info.getId()).thenReturn(TEST_ID);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index cdf9728..3c52f54 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -45,6 +45,7 @@
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.BackupUtils;
+import android.util.FeatureFlagUtils;
import android.util.Log;
import android.util.Slog;
import android.view.Display;
@@ -280,6 +281,16 @@
Settings.Secure.getMovedToGlobalSettings(movedToGlobal);
Set<String> movedToSecure = getMovedToSecureSettings();
+ Set<String> preservedGlobalSettings = getSettingsToPreserveInRestore(
+ Settings.Global.CONTENT_URI);
+ Set<String> preservedSecureSettings = getSettingsToPreserveInRestore(
+ Settings.Secure.CONTENT_URI);
+ Set<String> preservedSystemSettings = getSettingsToPreserveInRestore(
+ Settings.System.CONTENT_URI);
+ Set<String> preservedSettings = new HashSet<>(preservedGlobalSettings);
+ preservedSettings.addAll(preservedSecureSettings);
+ preservedSettings.addAll(preservedSystemSettings);
+
byte[] restoredWifiSupplicantData = null;
byte[] restoredWifiIpConfigData = null;
@@ -300,7 +311,8 @@
case KEY_SYSTEM :
restoreSettings(data, Settings.System.CONTENT_URI, movedToGlobal,
movedToSecure, R.array.restore_blocked_system_settings,
- dynamicBlockList);
+ dynamicBlockList,
+ preservedSystemSettings);
mSettingsHelper.applyAudioSettings();
break;
@@ -311,7 +323,8 @@
movedToGlobal,
null,
R.array.restore_blocked_secure_settings,
- dynamicBlockList);
+ dynamicBlockList,
+ preservedSecureSettings);
break;
case KEY_GLOBAL :
@@ -321,7 +334,8 @@
null,
movedToSecure,
R.array.restore_blocked_global_settings,
- dynamicBlockList);
+ dynamicBlockList,
+ preservedGlobalSettings);
break;
case KEY_WIFI_SUPPLICANT :
@@ -368,7 +382,8 @@
restoreDeviceSpecificConfig(
restoredDeviceSpecificConfig,
R.array.restore_blocked_device_specific_settings,
- dynamicBlockList);
+ dynamicBlockList,
+ preservedSettings);
break;
default :
@@ -418,7 +433,7 @@
in.readFully(buffer, 0, nBytes);
restoreSettings(buffer, nBytes, Settings.System.CONTENT_URI, movedToGlobal,
movedToSecure, R.array.restore_blocked_system_settings,
- Collections.emptySet());
+ Collections.emptySet(), Collections.emptySet());
// secure settings
nBytes = in.readInt();
@@ -432,7 +447,7 @@
movedToGlobal,
null,
R.array.restore_blocked_secure_settings,
- Collections.emptySet());
+ Collections.emptySet(), Collections.emptySet());
// Global only if sufficiently new
if (version >= FULL_BACKUP_ADDED_GLOBAL) {
@@ -443,7 +458,7 @@
movedToGlobal.clear(); // no redirection; this *is* the global namespace
restoreSettings(buffer, nBytes, Settings.Global.CONTENT_URI, movedToGlobal,
movedToSecure, R.array.restore_blocked_global_settings,
- Collections.emptySet());
+ Collections.emptySet(), Collections.emptySet());
}
// locale
@@ -608,6 +623,40 @@
}
/**
+ * Get names of the settings for which the current value should be preserved during restore.
+ */
+ private Set<String> getSettingsToPreserveInRestore(Uri settingsUri) {
+ if (!FeatureFlagUtils.isEnabled(getApplicationContext(),
+ FeatureFlagUtils.SETTINGS_DO_NOT_RESTORE_PRESERVED)) {
+ return Collections.emptySet();
+ }
+
+ Cursor cursor = getContentResolver().query(settingsUri, new String[] {
+ Settings.NameValueTable.NAME, Settings.NameValueTable.IS_PRESERVED_IN_RESTORE },
+ /* selection */ null, /* selectionArgs */ null, /* sortOrder */ null);
+
+ if (!cursor.moveToFirst()) {
+ Slog.i(TAG, "No settings to be preserved in restore");
+ return Collections.emptySet();
+ }
+
+ int nameIndex = cursor.getColumnIndex(Settings.NameValueTable.NAME);
+ int isPreservedIndex = cursor.getColumnIndex(
+ Settings.NameValueTable.IS_PRESERVED_IN_RESTORE);
+
+ Set<String> preservedSettings = new HashSet<>();
+ while (!cursor.isAfterLast()) {
+ if (Boolean.parseBoolean(cursor.getString(isPreservedIndex))) {
+ preservedSettings.add(getQualifiedKeyForSetting(cursor.getString(nameIndex),
+ settingsUri));
+ }
+ cursor.moveToNext();
+ }
+
+ return preservedSettings;
+ }
+
+ /**
* Serialize the owner info and other lock settings
*/
private byte[] getLockSettings(@UserIdInt int userId) {
@@ -650,7 +699,8 @@
HashSet<String> movedToGlobal,
Set<String> movedToSecure,
int blockedSettingsArrayId,
- Set<String> dynamicBlockList) {
+ Set<String> dynamicBlockList,
+ Set<String> settingsToPreserve) {
byte[] settings = new byte[data.getDataSize()];
try {
data.readEntityData(settings, 0, settings.length);
@@ -665,7 +715,8 @@
movedToGlobal,
movedToSecure,
blockedSettingsArrayId,
- dynamicBlockList);
+ dynamicBlockList,
+ settingsToPreserve);
}
private void restoreSettings(
@@ -675,7 +726,8 @@
HashSet<String> movedToGlobal,
Set<String> movedToSecure,
int blockedSettingsArrayId,
- Set<String> dynamicBlockList) {
+ Set<String> dynamicBlockList,
+ Set<String> settingsToPreserve) {
restoreSettings(
settings,
0,
@@ -684,10 +736,12 @@
movedToGlobal,
movedToSecure,
blockedSettingsArrayId,
- dynamicBlockList);
+ dynamicBlockList,
+ settingsToPreserve);
}
- private void restoreSettings(
+ @VisibleForTesting
+ void restoreSettings(
byte[] settings,
int pos,
int bytes,
@@ -695,31 +749,13 @@
HashSet<String> movedToGlobal,
Set<String> movedToSecure,
int blockedSettingsArrayId,
- Set<String> dynamicBlockList) {
+ Set<String> dynamicBlockList,
+ Set<String> settingsToPreserve) {
if (DEBUG) {
Log.i(TAG, "restoreSettings: " + contentUri);
}
- // Figure out the white list and redirects to the global table. We restore anything
- // in either the backup whitelist or the legacy-restore whitelist for this table.
- final String[] whitelist;
- Map<String, Validator> validators = null;
- if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
- Settings.Secure.LEGACY_RESTORE_SETTINGS,
- DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
- validators = SecureSettingsValidators.VALIDATORS;
- } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
- Settings.System.LEGACY_RESTORE_SETTINGS);
- validators = SystemSettingsValidators.VALIDATORS;
- } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
- whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
- Settings.Global.LEGACY_RESTORE_SETTINGS);
- validators = GlobalSettingsValidators.VALIDATORS;
- } else {
- throw new IllegalArgumentException("Unknown URI: " + contentUri);
- }
+ SettingsBackupWhitelist whitelist = getBackupWhitelist(contentUri);
// Restore only the white list data.
final ArrayMap<String, String> cachedEntries = new ArrayMap<>();
@@ -729,7 +765,7 @@
Set<String> blockedSettings = getBlockedSettings(blockedSettingsArrayId);
- for (String key : whitelist) {
+ for (String key : whitelist.mSettingsWhitelist) {
boolean isBlockedBySystem = blockedSettings != null && blockedSettings.contains(key);
if (isBlockedBySystem || isBlockedByDynamicList(dynamicBlockList, contentUri, key)) {
Log.i(
@@ -742,6 +778,12 @@
continue;
}
+ if (settingsToPreserve.contains(getQualifiedKeyForSetting(key, contentUri))) {
+ Log.i(TAG, "Skipping restore for setting " + key + " as it is marked as "
+ + "preserved");
+ continue;
+ }
+
String value = null;
boolean hasValueToRestore = false;
if (cachedEntries.indexOfKey(key) >= 0) {
@@ -775,7 +817,7 @@
}
// only restore the settings that have valid values
- if (!isValidSettingValue(key, value, validators)) {
+ if (!isValidSettingValue(key, value, whitelist.mSettingsValidators)) {
Log.w(TAG, "Attempted restore of " + key + " setting, but its value didn't pass"
+ " validation, value: " + value);
continue;
@@ -798,11 +840,42 @@
}
}
+ @VisibleForTesting
+ SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) {
+ // Figure out the white list and redirects to the global table. We restore anything
+ // in either the backup whitelist or the legacy-restore whitelist for this table.
+ String[] whitelist;
+ Map<String, Validator> validators = null;
+ if (contentUri.equals(Settings.Secure.CONTENT_URI)) {
+ whitelist = ArrayUtils.concatElements(String.class, SecureSettings.SETTINGS_TO_BACKUP,
+ Settings.Secure.LEGACY_RESTORE_SETTINGS,
+ DeviceSpecificSettings.DEVICE_SPECIFIC_SETTINGS_TO_BACKUP);
+ validators = SecureSettingsValidators.VALIDATORS;
+ } else if (contentUri.equals(Settings.System.CONTENT_URI)) {
+ whitelist = ArrayUtils.concatElements(String.class, SystemSettings.SETTINGS_TO_BACKUP,
+ Settings.System.LEGACY_RESTORE_SETTINGS);
+ validators = SystemSettingsValidators.VALIDATORS;
+ } else if (contentUri.equals(Settings.Global.CONTENT_URI)) {
+ whitelist = ArrayUtils.concatElements(String.class, GlobalSettings.SETTINGS_TO_BACKUP,
+ Settings.Global.LEGACY_RESTORE_SETTINGS);
+ validators = GlobalSettingsValidators.VALIDATORS;
+ } else {
+ throw new IllegalArgumentException("Unknown URI: " + contentUri);
+ }
+
+ return new SettingsBackupWhitelist(whitelist, validators);
+ }
+
private boolean isBlockedByDynamicList(Set<String> dynamicBlockList, Uri areaUri, String key) {
String contentKey = Uri.withAppendedPath(areaUri, key).toString();
return dynamicBlockList.contains(contentKey);
}
+ @VisibleForTesting
+ static String getQualifiedKeyForSetting(String settingName, Uri settingUri) {
+ return Uri.withAppendedPath(settingUri, settingName).toString();
+ }
+
// There may be other sources of blocked settings, so I'm separating out this
// code to make it easy to modify in the future.
@VisibleForTesting
@@ -1089,7 +1162,7 @@
*/
@VisibleForTesting
boolean restoreDeviceSpecificConfig(byte[] data, int blockedSettingsArrayId,
- Set<String> dynamicBlocklist) {
+ Set<String> dynamicBlocklist, Set<String> preservedSettings) {
// We're using an AtomicInteger to wrap the position int and allow called methods to
// modify it.
AtomicInteger pos = new AtomicInteger(0);
@@ -1108,7 +1181,8 @@
null,
null,
blockedSettingsArrayId,
- dynamicBlocklist);
+ dynamicBlocklist,
+ preservedSettings);
updateWindowManagerIfNeeded(originalDensity);
@@ -1240,4 +1314,20 @@
| ((in[pos + 3] & 0xFF) << 0);
return result;
}
+
+ /**
+ * Store the whitelist of settings to be backed up and validators for them.
+ */
+ @VisibleForTesting
+ static class SettingsBackupWhitelist {
+ final String[] mSettingsWhitelist;
+ final Map<String, Validator> mSettingsValidators;
+
+
+ SettingsBackupWhitelist(String[] settingsWhitelist,
+ Map<String, Validator> settingsValidators) {
+ mSettingsWhitelist = settingsWhitelist;
+ mSettingsValidators = settingsValidators;
+ }
+ }
}
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 874e299..c969bfd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -180,10 +180,17 @@
private static final int MUTATION_OPERATION_UPDATE = 3;
private static final int MUTATION_OPERATION_RESET = 4;
+ private static final String[] LEGACY_SQL_COLUMNS = new String[] {
+ Settings.NameValueTable._ID,
+ Settings.NameValueTable.NAME,
+ Settings.NameValueTable.VALUE,
+ };
+
private static final String[] ALL_COLUMNS = new String[] {
Settings.NameValueTable._ID,
Settings.NameValueTable.NAME,
- Settings.NameValueTable.VALUE
+ Settings.NameValueTable.VALUE,
+ Settings.NameValueTable.IS_PRESERVED_IN_RESTORE,
};
public static final int SETTINGS_TYPE_GLOBAL = SettingsState.SETTINGS_TYPE_GLOBAL;
@@ -2353,6 +2360,10 @@
case Settings.NameValueTable.VALUE: {
values[i] = setting.getValue();
} break;
+
+ case Settings.NameValueTable.IS_PRESERVED_IN_RESTORE: {
+ values[i] = String.valueOf(setting.isValuePreservedInRestore());
+ } break;
}
}
@@ -3097,7 +3108,7 @@
SQLiteQueryBuilder queryBuilder = new SQLiteQueryBuilder();
queryBuilder.setTables(table);
- Cursor cursor = queryBuilder.query(database, ALL_COLUMNS,
+ Cursor cursor = queryBuilder.query(database, LEGACY_SQL_COLUMNS,
null, null, null, null, null);
if (cursor == null) {
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index db18213a..9934e59 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -41,13 +41,13 @@
import android.util.Base64;
import android.util.Slog;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import android.util.TimeUtils;
import android.util.Xml;
import android.util.proto.ProtoOutputStream;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import libcore.io.IoUtils;
@@ -429,8 +429,9 @@
mSettings.put(name, newState);
}
- StatsLog.write(StatsLog.SETTING_CHANGED, name, value, newState.value, oldValue, tag,
- makeDefault, getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, value, newState.value,
+ oldValue, tag, makeDefault, getUserIdFromKey(mKey),
+ FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);
@@ -489,9 +490,9 @@
if (key.startsWith(prefix) && !keyValues.containsKey(key)) {
Setting oldState = mSettings.remove(key);
- StatsLog.write(StatsLog.SETTING_CHANGED, key, /* value= */ "", /* newValue= */ "",
- oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
- StatsLog.SETTING_CHANGED__REASON__DELETED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key,
+ /* value= */ "", /* newValue= */ "", oldState.value, /* tag */ "", false,
+ getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);
changedKeys.add(key); // key was removed
}
@@ -516,9 +517,9 @@
continue;
}
- StatsLog.write(StatsLog.SETTING_CHANGED, key, value, state.value, oldValue,
- /* tag */ null, /* make default */ false,
- getUserIdFromKey(mKey), StatsLog.SETTING_CHANGED__REASON__UPDATED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, key, value, state.value,
+ oldValue, /* tag */ null, /* make default */ false,
+ getUserIdFromKey(mKey), FrameworkStatsLog.SETTING_CHANGED__REASON__UPDATED);
addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, state);
}
@@ -544,9 +545,9 @@
Setting oldState = mSettings.remove(name);
- StatsLog.write(StatsLog.SETTING_CHANGED, name, /* value= */ "", /* newValue= */ "",
- oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
- StatsLog.SETTING_CHANGED__REASON__DELETED);
+ FrameworkStatsLog.write(FrameworkStatsLog.SETTING_CHANGED, name, /* value= */ "",
+ /* newValue= */ "", oldState.value, /* tag */ "", false, getUserIdFromKey(mKey),
+ FrameworkStatsLog.SETTING_CHANGED__REASON__DELETED);
updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,
null, oldState.defaultValue, null);
diff --git a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
index e650882..f5334fb 100644
--- a/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
+++ b/packages/SettingsProvider/test/src/com/android/providers/settings/SettingsBackupAgentTest.java
@@ -32,6 +32,8 @@
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
+import android.provider.settings.validators.SettingsValidators;
+import android.provider.settings.validators.Validator;
import android.test.mock.MockContentProvider;
import android.test.mock.MockContentResolver;
@@ -43,6 +45,7 @@
import java.io.ByteArrayOutputStream;
import java.io.IOException;
+import java.nio.ByteBuffer;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
@@ -55,12 +58,24 @@
/** Tests for the SettingsHelperTest */
@RunWith(AndroidJUnit4.class)
public class SettingsBackupAgentTest extends BaseSettingsProviderTest {
-
+ private static final Uri TEST_URI = Uri.EMPTY;
private static final String TEST_DISPLAY_DENSITY_FORCED = "123";
+ private static final String OVERRIDDEN_TEST_SETTING = "overridden_setting";
+ private static final String PRESERVED_TEST_SETTING = "preserved_setting";
+ private static final Map<String, String> DEVICE_SPECIFIC_TEST_VALUES = new HashMap<>();
private static final Map<String, String> TEST_VALUES = new HashMap<>();
+ private static final Map<String, Validator> TEST_VALUES_VALIDATORS = new HashMap<>();
static {
- TEST_VALUES.put(Settings.Secure.DISPLAY_DENSITY_FORCED, TEST_DISPLAY_DENSITY_FORCED);
+ DEVICE_SPECIFIC_TEST_VALUES.put(Settings.Secure.DISPLAY_DENSITY_FORCED,
+ TEST_DISPLAY_DENSITY_FORCED);
+
+ TEST_VALUES.put(OVERRIDDEN_TEST_SETTING, "123");
+ TEST_VALUES.put(PRESERVED_TEST_SETTING, "124");
+
+ TEST_VALUES_VALIDATORS.put(OVERRIDDEN_TEST_SETTING,
+ SettingsValidators.ANY_STRING_VALIDATOR);
+ TEST_VALUES_VALIDATORS.put(PRESERVED_TEST_SETTING, SettingsValidators.ANY_STRING_VALIDATOR);
}
private TestFriendlySettingsBackupAgent mAgentUnderTest;
@@ -83,14 +98,15 @@
byte[] settingsBackup = mAgentUnderTest.getDeviceSpecificConfiguration();
- assertEquals("Not all values backed up.", TEST_VALUES.keySet(), helper.mReadEntries);
+ assertEquals("Not all values backed up.", DEVICE_SPECIFIC_TEST_VALUES.keySet(), helper.mReadEntries);
mAgentUnderTest.restoreDeviceSpecificConfig(
settingsBackup,
R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet(),
Collections.emptySet());
- assertEquals("Not all values were restored.", TEST_VALUES, helper.mWrittenValues);
+ assertEquals("Not all values were restored.", DEVICE_SPECIFIC_TEST_VALUES, helper.mWrittenValues);
}
@Test
@@ -100,12 +116,13 @@
byte[] settingsBackup = mAgentUnderTest.getDeviceSpecificConfiguration();
- assertEquals("Not all values backed up.", TEST_VALUES.keySet(), helper.mReadEntries);
- mAgentUnderTest.setBlockedSettings(TEST_VALUES.keySet().toArray(new String[0]));
+ assertEquals("Not all values backed up.", DEVICE_SPECIFIC_TEST_VALUES.keySet(), helper.mReadEntries);
+ mAgentUnderTest.setBlockedSettings(DEVICE_SPECIFIC_TEST_VALUES.keySet().toArray(new String[0]));
mAgentUnderTest.restoreDeviceSpecificConfig(
settingsBackup,
R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet(),
Collections.emptySet());
assertTrue("Not all values were blocked.", helper.mWrittenValues.isEmpty());
@@ -172,9 +189,50 @@
mAgentUnderTest.restoreDeviceSpecificConfig(
data,
R.array.restore_blocked_device_specific_settings,
+ Collections.emptySet(),
Collections.emptySet()));
}
+ @Test
+ public void testOnRestore_preservedSettingsAreNotRestored() {
+ SettingsBackupAgent.SettingsBackupWhitelist whitelist =
+ new SettingsBackupAgent.SettingsBackupWhitelist(
+ new String[] { OVERRIDDEN_TEST_SETTING, PRESERVED_TEST_SETTING },
+ TEST_VALUES_VALIDATORS);
+ mAgentUnderTest.setSettingsWhitelist(whitelist);
+ mAgentUnderTest.setBlockedSettings();
+ TestSettingsHelper settingsHelper = new TestSettingsHelper(mContext);
+ mAgentUnderTest.mSettingsHelper = settingsHelper;
+
+ byte[] backupData = generateBackupData(TEST_VALUES);
+ mAgentUnderTest.restoreSettings(backupData, /* pos */ 0, backupData.length, TEST_URI, new HashSet<>(),
+ Collections.emptySet(), /* blockedSettingsArrayId */ 0, Collections.emptySet(),
+ new HashSet<>(Collections.singletonList(SettingsBackupAgent.getQualifiedKeyForSetting(PRESERVED_TEST_SETTING, TEST_URI))));
+
+ assertTrue(settingsHelper.mWrittenValues.containsKey(OVERRIDDEN_TEST_SETTING));
+ assertFalse(settingsHelper.mWrittenValues.containsKey(PRESERVED_TEST_SETTING));
+ }
+
+ private byte[] generateBackupData(Map<String, String> keyValueData) {
+ int totalBytes = 0;
+ for (String key : keyValueData.keySet()) {
+ totalBytes += 2 * Integer.BYTES + key.getBytes().length
+ + keyValueData.get(key).getBytes().length;
+ }
+
+ ByteBuffer buffer = ByteBuffer.allocate(totalBytes);
+ for (String key : keyValueData.keySet()) {
+ byte[] keyBytes = key.getBytes();
+ byte[] valueBytes = keyValueData.get(key).getBytes();
+ buffer.putInt(keyBytes.length);
+ buffer.put(keyBytes);
+ buffer.putInt(valueBytes.length);
+ buffer.put(valueBytes);
+ }
+
+ return buffer.array();
+ }
+
private byte[] generateUncorruptedHeader() throws IOException {
try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
mAgentUnderTest.writeHeader(os);
@@ -219,6 +277,7 @@
private static class TestFriendlySettingsBackupAgent extends SettingsBackupAgent {
private Boolean mForcedDeviceInfoRestoreAcceptability = null;
private String[] mBlockedSettings = null;
+ private SettingsBackupWhitelist mSettingsWhitelist = null;
void setForcedDeviceInfoRestoreAcceptability(boolean value) {
mForcedDeviceInfoRestoreAcceptability = value;
@@ -228,6 +287,10 @@
mBlockedSettings = blockedSettings;
}
+ void setSettingsWhitelist(SettingsBackupWhitelist settingsWhitelist) {
+ mSettingsWhitelist = settingsWhitelist;
+ }
+
@Override
protected Set<String> getBlockedSettings(int blockedSettingsArrayId) {
return mBlockedSettings == null
@@ -241,6 +304,15 @@
? super.isSourceAcceptable(data, pos)
: mForcedDeviceInfoRestoreAcceptability;
}
+
+ @Override
+ SettingsBackupWhitelist getBackupWhitelist(Uri contentUri) {
+ if (mSettingsWhitelist == null) {
+ return super.getBackupWhitelist(contentUri);
+ }
+
+ return mSettingsWhitelist;
+ }
}
/** The TestSettingsHelper tracks which values have been backed up and/or restored. */
@@ -257,7 +329,7 @@
@Override
public String onBackupValue(String key, String value) {
mReadEntries.add(key);
- String readValue = TEST_VALUES.get(key);
+ String readValue = DEVICE_SPECIFIC_TEST_VALUES.get(key);
assert readValue != null;
return readValue;
}
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 7d2b85d..84d9bb6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -219,6 +219,9 @@
<!-- Permission required for CTS test - CrossProfileAppsHostSideTest -->
<uses-permission android:name="android.permission.INTERACT_ACROSS_PROFILES"/>
+ <!-- permissions required for CTS test - PhoneStateListenerTest -->
+ <uses-permission android:name="android.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH" />
+
<!-- Permission required for CTS test - UiModeManagerTest -->
<uses-permission android:name="android.permission.ENTER_CAR_MODE_PRIORITIZED"/>
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 26fa1cf..149eaf4 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -646,6 +646,7 @@
android:label="Controls Providers"
android:theme="@style/Theme.SystemUI"
android:exported="true"
+ android:showForAllUsers="true"
android:excludeFromRecents="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
@@ -655,6 +656,7 @@
android:parentActivityName=".controls.management.ControlsProviderSelectorActivity"
android:theme="@style/Theme.SystemUI"
android:excludeFromRecents="true"
+ android:showForAllUsers="true"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation|keyboard|keyboardHidden"
android:visibleToInstantApps="true">
</activity>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 2aa6d95..d72ce5e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -328,6 +328,10 @@
<item type="id" name="action_toggle_overview"/>
+ <!-- Whether or not to show notifications to the user. If disabled, SystemUI will still be
+ registered as a notification listener, but will ignore all notification events. -->
+ <bool name="config_renderNotifications">true</bool>
+
<!-- Whether or not the gear icon on notifications should be shown. The gear is shown when the
the notification is not swiped enough to dismiss it. -->
<bool name="config_showNotificationGear">true</bool>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4e2f7d4..6a04583 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1883,9 +1883,8 @@
final boolean awakeKeyguard = mKeyguardIsVisible && mDeviceInteractive && !mGoingToSleep;
final int user = getCurrentUser();
final int strongAuth = mStrongAuthTracker.getStrongAuthForUser(user);
- final boolean isLockOutOrLockDown =
- containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_LOCKOUT)
- || containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
+ final boolean isLockDown =
+ containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW)
|| containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_USER_LOCKDOWN);
final boolean isEncryptedOrTimedOut =
containsFlag(strongAuth, STRONG_AUTH_REQUIRED_AFTER_BOOT)
@@ -1899,9 +1898,9 @@
boolean becauseCannotSkipBouncer = !getUserCanSkipBouncer(user) || canBypass;
// Scan even when encrypted or timeout to show a preemptive bouncer when bypassing.
- // Lockout/lockdown modes shouldn't scan, since they are more explicit.
+ // Lock-down mode shouldn't scan, since it is more explicit.
boolean strongAuthAllowsScanning = (!isEncryptedOrTimedOut || canBypass && !mBouncer)
- && !isLockOutOrLockDown;
+ && !isLockDown;
// Only listen if this KeyguardUpdateMonitor belongs to the primary user. There is an
// instance of KeyguardUpdateMonitor for each user but KeyguardUpdateMonitor is user-aware.
diff --git a/packages/SystemUI/src/com/android/systemui/DejankUtils.java b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
index 97578e1..3fce55f 100644
--- a/packages/SystemUI/src/com/android/systemui/DejankUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/DejankUtils.java
@@ -61,19 +61,21 @@
|| !isMainThread() || sTemporarilyIgnoreStrictMode) {
return null;
}
+ }
- try {
- String description = binder.getInterfaceDescriptor();
+ try {
+ String description = binder.getInterfaceDescriptor();
+ synchronized (sLock) {
if (sWhitelistedFrameworkClasses.contains(description)) {
return null;
}
- } catch (RemoteException e) {
- e.printStackTrace();
}
-
- StrictMode.noteSlowCall("IPC detected on critical path: " + sBlockingIpcs.peek());
- return null;
+ } catch (RemoteException e) {
+ e.printStackTrace();
}
+
+ StrictMode.noteSlowCall("IPC detected on critical path: " + sBlockingIpcs.peek());
+ return null;
}
@Override
@@ -126,9 +128,11 @@
if (STRICT_MODE_ENABLED && sBlockingIpcs.empty()) {
synchronized (sLock) {
sBlockingIpcs.push("detectBlockingIpcs");
- try {
- runnable.run();
- } finally {
+ }
+ try {
+ runnable.run();
+ } finally {
+ synchronized (sLock) {
sBlockingIpcs.pop();
}
}
@@ -177,9 +181,11 @@
if (STRICT_MODE_ENABLED && !sTemporarilyIgnoreStrictMode) {
synchronized (sLock) {
sTemporarilyIgnoreStrictMode = true;
- try {
- runnable.run();
- } finally {
+ }
+ try {
+ runnable.run();
+ } finally {
+ synchronized (sLock) {
sTemporarilyIgnoreStrictMode = false;
}
}
@@ -196,14 +202,16 @@
if (STRICT_MODE_ENABLED && !sTemporarilyIgnoreStrictMode) {
synchronized (sLock) {
sTemporarilyIgnoreStrictMode = true;
- final T val;
- try {
- val = supplier.get();
- } finally {
+ }
+ final T val;
+ try {
+ val = supplier.get();
+ } finally {
+ synchronized (sLock) {
sTemporarilyIgnoreStrictMode = false;
}
- return val;
}
+ return val;
} else {
return supplier.get();
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
index e954163..a26cce0 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleController.java
@@ -414,7 +414,7 @@
mNotificationEntryManager.addNotificationEntryListener(
new NotificationEntryListener() {
@Override
- public void onNotificationAdded(NotificationEntry entry) {
+ public void onPendingEntryAdded(NotificationEntry entry) {
onEntryAdded(entry);
}
diff --git a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
index 4194352..5b9ea7d 100644
--- a/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
+++ b/packages/SystemUI/src/com/android/systemui/bubbles/BubbleFlyoutView.java
@@ -431,7 +431,7 @@
final float interpolatedRadius = getInterpolatedRadius();
rectPath.addRoundRect(mBgRect, interpolatedRadius,
interpolatedRadius, Path.Direction.CW);
- outline.setConvexPath(rectPath);
+ outline.setPath(rectPath);
// Get rid of the triangle path once it has disappeared behind the flyout.
if (mPercentStillFlyout > 0.5f) {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
index e6cdf50..53841e2 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlStatus.kt
@@ -18,4 +18,8 @@
import android.service.controls.Control
-data class ControlStatus(val control: Control, val favorite: Boolean, val removed: Boolean = false)
\ No newline at end of file
+data class ControlStatus(
+ val control: Control,
+ val favorite: Boolean,
+ val removed: Boolean = false
+)
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
index 265ddd8..588ef5c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/ControlsServiceInfo.kt
@@ -22,7 +22,7 @@
class ControlsServiceInfo(
context: Context,
- serviceInfo: ServiceInfo
+ val serviceInfo: ServiceInfo
) : DefaultAppInfo(
context,
context.packageManager,
diff --git a/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt
new file mode 100644
index 0000000..4f39f22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/controls/UserAwareController.kt
@@ -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.
+ */
+
+package com.android.systemui.controls
+
+import android.os.UserHandle
+
+interface UserAwareController {
+
+ fun changeUser(newUser: UserHandle) {}
+ val currentUserId: Int
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
index 6b7fc4b..12c3ce9 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingController.kt
@@ -19,8 +19,9 @@
import android.content.ComponentName
import android.service.controls.Control
import android.service.controls.actions.ControlAction
+import com.android.systemui.controls.UserAwareController
-interface ControlsBindingController {
+interface ControlsBindingController : UserAwareController {
fun bindAndLoad(component: ComponentName, callback: (List<Control>) -> Unit)
fun bindServices(components: List<ComponentName>)
fun subscribe(controls: List<ControlInfo>)
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
index 2db2cf1..0a2a925 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsBindingControllerImpl.kt
@@ -19,6 +19,7 @@
import android.content.ComponentName
import android.content.Context
import android.os.IBinder
+import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.IControlsActionCallback
import android.service.controls.IControlsLoadCallback
@@ -50,12 +51,17 @@
private val refreshing = AtomicBoolean(false)
+ private var currentUser = context.user
+
+ override val currentUserId: Int
+ get() = currentUser.identifier
+
@GuardedBy("componentMap")
private val tokenMap: MutableMap<IBinder, ControlsProviderLifecycleManager> =
ArrayMap<IBinder, ControlsProviderLifecycleManager>()
@GuardedBy("componentMap")
- private val componentMap: MutableMap<ComponentName, ControlsProviderLifecycleManager> =
- ArrayMap<ComponentName, ControlsProviderLifecycleManager>()
+ private val componentMap: MutableMap<Key, ControlsProviderLifecycleManager> =
+ ArrayMap<Key, ControlsProviderLifecycleManager>()
private val loadCallbackService = object : IControlsLoadCallback.Stub() {
override fun accept(token: IBinder, controls: MutableList<Control>) {
@@ -103,6 +109,7 @@
loadCallbackService,
actionCallbackService,
subscriberService,
+ currentUser,
component
)
}
@@ -110,7 +117,7 @@
private fun retrieveLifecycleManager(component: ComponentName):
ControlsProviderLifecycleManager {
synchronized(componentMap) {
- val provider = componentMap.getOrPut(component) {
+ val provider = componentMap.getOrPut(Key(component, currentUser)) {
createProviderManager(component)
}
tokenMap.putIfAbsent(provider.token, provider)
@@ -137,7 +144,7 @@
val providersWithFavorites = controlsByComponentName.keys
synchronized(componentMap) {
componentMap.forEach {
- if (it.key !in providersWithFavorites) {
+ if (it.key.component !in providersWithFavorites) {
backgroundExecutor.execute { it.value.unbindService() }
}
}
@@ -163,10 +170,40 @@
override fun bindServices(components: List<ComponentName>) {
components.forEach {
val provider = retrieveLifecycleManager(it)
- backgroundExecutor.execute { provider.bindPermanently() }
+ backgroundExecutor.execute { provider.bindService() }
}
}
+ override fun changeUser(newUser: UserHandle) {
+ if (newUser == currentUser) return
+ synchronized(componentMap) {
+ unbindAllProvidersLocked() // unbind all providers from the old user
+ }
+ refreshing.set(false)
+ currentUser = newUser
+ }
+
+ private fun unbindAllProvidersLocked() {
+ componentMap.values.forEach {
+ if (it.user == currentUser) {
+ it.unbindService()
+ }
+ }
+ }
+
+ override fun toString(): String {
+ return StringBuilder(" ControlsBindingController:\n").apply {
+ append(" refreshing=${refreshing.get()}\n")
+ append(" currentUser=$currentUser\n")
+ append(" Providers:\n")
+ synchronized(componentMap) {
+ componentMap.values.forEach {
+ append(" $it\n")
+ }
+ }
+ }.toString()
+ }
+
private abstract inner class CallbackRunnable(val token: IBinder) : Runnable {
protected val provider: ControlsProviderLifecycleManager? =
synchronized(componentMap) {
@@ -183,6 +220,10 @@
Log.e(TAG, "No provider found for token:$token")
return
}
+ if (provider.user != currentUser) {
+ Log.e(TAG, "User ${provider.user} is not current user")
+ return
+ }
synchronized(componentMap) {
if (token !in tokenMap.keys) {
Log.e(TAG, "Provider for token:$token does not exist anymore")
@@ -192,7 +233,7 @@
provider.lastLoadCallback?.invoke(list) ?: run {
Log.w(TAG, "Null callback")
}
- provider.maybeUnbindAndRemoveCallback()
+ provider.unbindService()
}
}
@@ -204,6 +245,10 @@
if (!refreshing.get()) {
Log.d(TAG, "onRefresh outside of window from:${provider?.componentName}")
}
+ if (provider?.user != currentUser) {
+ Log.e(TAG, "User ${provider?.user} is not current user")
+ return
+ }
provider?.let {
lazyController.get().refreshStatus(it.componentName, control)
}
@@ -229,7 +274,7 @@
) : CallbackRunnable(token) {
override fun run() {
provider?.let {
- Log.i(TAG, "onComplete receive from '${provider?.componentName}'")
+ Log.i(TAG, "onComplete receive from '${provider.componentName}'")
}
}
}
@@ -240,7 +285,7 @@
) : CallbackRunnable(token) {
override fun run() {
provider?.let {
- Log.e(TAG, "onError receive from '${provider?.componentName}': $error")
+ Log.e(TAG, "onError receive from '${provider.componentName}': $error")
}
}
}
@@ -251,9 +296,15 @@
@ControlAction.ResponseResult val response: Int
) : CallbackRunnable(token) {
override fun run() {
+ if (provider?.user != currentUser) {
+ Log.e(TAG, "User ${provider?.user} is not current user")
+ return
+ }
provider?.let {
lazyController.get().onActionResponse(it.componentName, controlId, response)
}
}
}
}
+
+private data class Key(val component: ComponentName, val user: UserHandle)
\ No newline at end of file
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 e098faa..b02de45 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsController.kt
@@ -20,8 +20,9 @@
import android.service.controls.Control
import android.service.controls.actions.ControlAction
import com.android.systemui.controls.ControlStatus
+import com.android.systemui.controls.UserAwareController
-interface ControlsController {
+interface ControlsController : UserAwareController {
val available: Boolean
fun getFavoriteControls(): List<ControlInfo>
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 d5b5b5f..6ff1cf8 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsControllerImpl.kt
@@ -17,10 +17,13 @@
package com.android.systemui.controls.controller
import android.app.PendingIntent
+import android.content.BroadcastReceiver
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.content.IntentFilter
import android.os.Environment
+import android.os.UserHandle
import android.provider.Settings
import android.service.controls.Control
import android.service.controls.actions.ControlAction
@@ -29,14 +32,17 @@
import com.android.internal.annotations.GuardedBy
import com.android.systemui.DumpController
import com.android.systemui.Dumpable
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.management.ControlsFavoritingActivity
+import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.util.concurrency.DelayableExecutor
import java.io.FileDescriptor
import java.io.PrintWriter
import java.util.Optional
+import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton
@@ -46,35 +52,101 @@
@Background private val executor: DelayableExecutor,
private val uiController: ControlsUiController,
private val bindingController: ControlsBindingController,
- private val optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
+ private val listingController: ControlsListingController,
+ broadcastDispatcher: BroadcastDispatcher,
+ optionalWrapper: Optional<ControlsFavoritePersistenceWrapper>,
dumpController: DumpController
) : Dumpable, ControlsController {
companion object {
private const val TAG = "ControlsControllerImpl"
const val CONTROLS_AVAILABLE = "systemui.controls_available"
+ const val USER_CHANGE_RETRY_DELAY = 500L // ms
}
- override val available = Settings.Secure.getInt(
+ // Map of map: ComponentName -> (String -> ControlInfo).
+ // Only for current user
+ @GuardedBy("currentFavorites")
+ private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>()
+
+ private var userChanging = true
+ override var available = Settings.Secure.getInt(
context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
- val persistenceWrapper = optionalWrapper.orElseGet {
+ private set
+
+ private var currentUser = context.user
+ override val currentUserId
+ get() = currentUser.identifier
+
+ private val persistenceWrapper = optionalWrapper.orElseGet {
ControlsFavoritePersistenceWrapper(
Environment.buildPath(
- context.filesDir,
- ControlsFavoritePersistenceWrapper.FILE_NAME),
+ context.filesDir,
+ ControlsFavoritePersistenceWrapper.FILE_NAME
+ ),
executor
)
}
- // Map of map: ComponentName -> (String -> ControlInfo)
- @GuardedBy("currentFavorites")
- private val currentFavorites = ArrayMap<ComponentName, MutableMap<String, ControlInfo>>()
-
- init {
+ private fun setValuesForUser(newUser: UserHandle) {
+ Log.d(TAG, "Changing to user: $newUser")
+ currentUser = newUser
+ val userContext = context.createContextAsUser(currentUser, 0)
+ val fileName = Environment.buildPath(
+ userContext.filesDir, ControlsFavoritePersistenceWrapper.FILE_NAME)
+ persistenceWrapper.changeFile(fileName)
+ available = Settings.Secure.getIntForUser(
+ context.contentResolver, CONTROLS_AVAILABLE, 0) != 0
+ synchronized(currentFavorites) {
+ currentFavorites.clear()
+ }
if (available) {
- dumpController.registerDumpable(this)
loadFavorites()
}
+ bindingController.changeUser(newUser)
+ listingController.changeUser(newUser)
+ userChanging = false
+ }
+
+ private val userSwitchReceiver = object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (intent.action == Intent.ACTION_USER_SWITCHED) {
+ userChanging = true
+ val newUser =
+ UserHandle.of(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, sendingUserId))
+ if (currentUser == newUser) {
+ userChanging = false
+ return
+ }
+ setValuesForUser(newUser)
+ }
+ }
+ }
+
+ init {
+ dumpController.registerDumpable(this)
+ if (available) {
+ loadFavorites()
+ }
+ userChanging = false
+ broadcastDispatcher.registerReceiver(
+ userSwitchReceiver,
+ IntentFilter(Intent.ACTION_USER_SWITCHED),
+ executor,
+ UserHandle.ALL
+ )
+ }
+
+ private fun confirmAvailability(): Boolean {
+ if (userChanging) {
+ Log.w(TAG, "Controls not available while user is changing")
+ return false
+ }
+ if (!available) {
+ Log.d(TAG, "Controls not available")
+ return false
+ }
+ return true
}
private fun loadFavorites() {
@@ -91,8 +163,18 @@
componentName: ComponentName,
callback: (List<ControlStatus>) -> Unit
) {
- if (!available) {
- Log.d(TAG, "Controls not available")
+ if (!confirmAvailability()) {
+ if (userChanging) {
+ // Try again later, userChanging should not last forever. If so, we have bigger
+ // problems
+ executor.executeDelayed(
+ { loadForComponent(componentName, callback) },
+ USER_CHANGE_RETRY_DELAY,
+ TimeUnit.MILLISECONDS
+ )
+ } else {
+ callback(emptyList())
+ }
return
}
bindingController.bindAndLoad(componentName) {
@@ -158,10 +240,7 @@
}
override fun subscribeToFavorites() {
- if (!available) {
- Log.d(TAG, "Controls not available")
- return
- }
+ if (!confirmAvailability()) return
// Make a copy of the favorites list
val favorites = synchronized(currentFavorites) {
currentFavorites.flatMap { it.value.values.toList() }
@@ -170,18 +249,12 @@
}
override fun unsubscribe() {
- if (!available) {
- Log.d(TAG, "Controls not available")
- return
- }
+ if (!confirmAvailability()) return
bindingController.unsubscribe()
}
override fun changeFavoriteStatus(controlInfo: ControlInfo, state: Boolean) {
- if (!available) {
- Log.d(TAG, "Controls not available")
- return
- }
+ if (!confirmAvailability()) return
var changed = false
val listOfControls = synchronized(currentFavorites) {
if (state) {
@@ -211,7 +284,7 @@
}
override fun refreshStatus(componentName: ComponentName, control: Control) {
- if (!available) {
+ if (!confirmAvailability()) {
Log.d(TAG, "Controls not available")
return
}
@@ -227,28 +300,24 @@
}
override fun onActionResponse(componentName: ComponentName, controlId: String, response: Int) {
- if (!available) {
- Log.d(TAG, "Controls not available")
- return
- }
+ if (!confirmAvailability()) return
uiController.onActionResponse(componentName, controlId, response)
}
override fun getFavoriteControls(): List<ControlInfo> {
- if (!available) {
- Log.d(TAG, "Controls not available")
- return emptyList()
- }
+ if (!confirmAvailability()) return emptyList()
synchronized(currentFavorites) {
return favoritesAsListLocked()
}
}
override fun action(controlInfo: ControlInfo, action: ControlAction) {
+ if (!confirmAvailability()) return
bindingController.action(controlInfo, action)
}
override fun clearFavorites() {
+ if (!confirmAvailability()) return
val changed = synchronized(currentFavorites) {
currentFavorites.isNotEmpty().also {
currentFavorites.clear()
@@ -261,6 +330,9 @@
override fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<out String>) {
pw.println("ControlsController state:")
+ pw.println(" Available: $available")
+ pw.println(" Changing users: $userChanging")
+ pw.println(" Current user: ${currentUser.identifier}")
pw.println(" Favorites:")
synchronized(currentFavorites) {
currentFavorites.forEach {
@@ -269,5 +341,6 @@
}
}
}
+ pw.println(bindingController.toString())
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
index 6f2d71f..7d1df14 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsFavoritePersistenceWrapper.kt
@@ -16,7 +16,6 @@
package com.android.systemui.controls.controller
-import android.app.ActivityManager
import android.content.ComponentName
import android.util.AtomicFile
import android.util.Log
@@ -32,8 +31,8 @@
import java.io.IOException
class ControlsFavoritePersistenceWrapper(
- val file: File,
- val executor: DelayableExecutor
+ private var file: File,
+ private var executor: DelayableExecutor
) {
companion object {
@@ -47,11 +46,13 @@
private const val TAG_TYPE = "type"
}
- val currentUser: Int
- get() = ActivityManager.getCurrentUser()
+ fun changeFile(fileName: File) {
+ file = fileName
+ }
fun storeFavorites(list: List<ControlInfo>) {
executor.execute {
+ Log.d(TAG, "Saving data to file: $file")
val atomicFile = AtomicFile(file)
val writer = try {
atomicFile.startWrite()
@@ -98,6 +99,7 @@
return emptyList()
}
try {
+ Log.d(TAG, "Reading data from file: $file")
val parser = Xml.newPullParser()
parser.setInput(reader, null)
return parseXml(parser)
@@ -111,7 +113,7 @@
}
private fun parseXml(parser: XmlPullParser): List<ControlInfo> {
- var type: Int = 0
+ var type = 0
val infos = mutableListOf<ControlInfo>()
while (parser.next().also { type = it } != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
@@ -123,9 +125,9 @@
parser.getAttributeValue(null, TAG_COMPONENT))
val id = parser.getAttributeValue(null, TAG_ID)
val title = parser.getAttributeValue(null, TAG_TITLE)
- val type = parser.getAttributeValue(null, TAG_TYPE)?.toInt()
- if (component != null && id != null && title != null && type != null) {
- infos.add(ControlInfo(component, id, title, type))
+ val deviceType = parser.getAttributeValue(null, TAG_TYPE)?.toInt()
+ if (component != null && id != null && title != null && deviceType != null) {
+ infos.add(ControlInfo(component, id, title, deviceType))
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
index 99aa360..b4bd82c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManager.kt
@@ -24,6 +24,7 @@
import android.os.Bundle
import android.os.IBinder
import android.os.RemoteException
+import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.ControlsProviderService.CALLBACK_BUNDLE
import android.service.controls.ControlsProviderService.CALLBACK_TOKEN
@@ -46,6 +47,7 @@
private val loadCallbackService: IControlsLoadCallback.Stub,
private val actionCallbackService: IControlsActionCallback.Stub,
private val subscriberService: IControlsSubscriber.Stub,
+ val user: UserHandle,
val componentName: ComponentName
) : IBinder.DeathRecipient {
@@ -54,9 +56,7 @@
val token: IBinder = Binder()
@GuardedBy("subscriptions")
private val subscriptions = mutableListOf<IControlsSubscription>()
- private var unbindImmediate = false
private var requiresBound = false
- private var isBound = false
@GuardedBy("queuedMessages")
private val queuedMessages: MutableSet<Message> = ArraySet()
private var wrapper: ServiceWrapper? = null
@@ -96,30 +96,22 @@
}
bindTryCount++
try {
- isBound = context.bindService(intent, serviceConnection, BIND_FLAGS)
+ context.bindServiceAsUser(intent, serviceConnection, BIND_FLAGS, user)
} catch (e: SecurityException) {
Log.e(TAG, "Failed to bind to service", e)
- isBound = false
}
} else {
if (DEBUG) {
Log.d(TAG, "Unbinding service $intent")
}
bindTryCount = 0
- wrapper = null
- if (isBound) {
+ wrapper?.run {
context.unbindService(serviceConnection)
- isBound = false
}
+ wrapper = null
}
}
- fun bindPermanently() {
- unbindImmediate = false
- unqueueMessage(Message.Unbind)
- bindService(true)
- }
-
private val serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName, service: IBinder) {
if (DEBUG) Log.d(TAG, "onServiceConnected $name")
@@ -133,7 +125,7 @@
override fun onServiceDisconnected(name: ComponentName?) {
if (DEBUG) Log.d(TAG, "onServiceDisconnected $name")
- isBound = false
+ wrapper = null
bindService(false)
}
}
@@ -152,7 +144,9 @@
load()
}
queue.filter { it is Message.Subscribe }.flatMap { (it as Message.Subscribe).list }.run {
- subscribe(this)
+ if (this.isNotEmpty()) {
+ subscribe(this)
+ }
}
queue.filter { it is Message.Action }.forEach {
val msg = it as Message.Action
@@ -193,6 +187,15 @@
}
}
+ private fun invokeOrQueue(f: () -> Unit, msg: Message) {
+ wrapper?.run {
+ f()
+ } ?: run {
+ queueMessage(msg)
+ bindService(true)
+ }
+ }
+
fun maybeBindAndLoad(callback: LoadCallback) {
unqueueMessage(Message.Unbind)
lastLoadCallback = callback
@@ -201,22 +204,12 @@
Log.d(TAG, "Timeout waiting onLoad for $componentName")
loadCallbackService.accept(token, emptyList())
}, LOAD_TIMEOUT, TimeUnit.MILLISECONDS)
- if (isBound) {
- load()
- } else {
- queueMessage(Message.Load)
- unbindImmediate = true
- bindService(true)
- }
+
+ invokeOrQueue(::load, Message.Load)
}
fun maybeBindAndSubscribe(controlIds: List<String>) {
- if (isBound) {
- subscribe(controlIds)
- } else {
- queueMessage(Message.Subscribe(controlIds))
- bindService(true)
- }
+ invokeOrQueue({ subscribe(controlIds) }, Message.Subscribe(controlIds))
}
private fun subscribe(controlIds: List<String>) {
@@ -230,12 +223,7 @@
}
fun maybeBindAndSendAction(controlId: String, action: ControlAction) {
- if (isBound) {
- action(controlId, action)
- } else {
- queueMessage(Message.Action(controlId, action))
- bindService(true)
- }
+ invokeOrQueue({ action(controlId, action) }, Message.Action(controlId, action))
}
private fun action(controlId: String, action: ControlAction) {
@@ -272,18 +260,25 @@
}
}
- fun maybeUnbindAndRemoveCallback() {
- lastLoadCallback = null
- onLoadCanceller?.run()
- onLoadCanceller = null
- if (unbindImmediate) {
- bindService(false)
- }
+ fun bindService() {
+ unqueueMessage(Message.Unbind)
+ bindService(true)
}
fun unbindService() {
- unbindImmediate = true
- maybeUnbindAndRemoveCallback()
+ lastLoadCallback = null
+ onLoadCanceller?.run()
+ onLoadCanceller = null
+
+ bindService(false)
+ }
+
+ override fun toString(): String {
+ return StringBuilder("ControlsProviderLifecycleManager(").apply {
+ append("component=$componentName")
+ append(", user=$user")
+ append(")")
+ }.toString()
}
sealed class Message {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
index d62bb4d..22c6908 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/AppAdapter.kt
@@ -23,6 +23,7 @@
import android.widget.ImageView
import android.widget.TextView
import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleOwner
import androidx.recyclerview.widget.RecyclerView
import com.android.settingslib.widget.CandidateInfo
import com.android.systemui.R
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 01c4fef..7ee4fd5 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsFavoritingActivity.kt
@@ -22,15 +22,18 @@
import android.view.LayoutInflater
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.broadcast.BroadcastDispatcher
import com.android.systemui.controls.controller.ControlInfo
import com.android.systemui.controls.controller.ControlsControllerImpl
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.CurrentUserTracker
import java.util.concurrent.Executor
import javax.inject.Inject
class ControlsFavoritingActivity @Inject constructor(
@Main private val executor: Executor,
- private val controller: ControlsControllerImpl
+ private val controller: ControlsControllerImpl,
+ broadcastDispatcher: BroadcastDispatcher
) : Activity() {
companion object {
@@ -42,11 +45,24 @@
private lateinit var recyclerView: RecyclerView
private lateinit var adapter: ControlAdapter
+ private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
+ private val startingUser = controller.currentUserId
+
+ override fun onUserSwitched(newUserId: Int) {
+ if (newUserId != startingUser) {
+ stopTracking()
+ finish()
+ }
+ }
+ }
+
+ private var component: ComponentName? = null
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
val app = intent.getCharSequenceExtra(EXTRA_APP)
- val component = intent.getParcelableExtra<ComponentName>(EXTRA_COMPONENT)
+ component = intent.getParcelableExtra<ComponentName>(EXTRA_COMPONENT)
// If we have no component name, there's not much we can do.
val callback = component?.let {
@@ -68,6 +84,11 @@
}
setContentView(recyclerView)
+ currentUserTracker.startTracking()
+ }
+
+ override fun onResume() {
+ super.onResume()
component?.let {
controller.loadForComponent(it) {
executor.execute {
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
index 09e0ce9..34db684 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingController.kt
@@ -18,14 +18,17 @@
import android.content.ComponentName
import com.android.settingslib.widget.CandidateInfo
+import com.android.systemui.controls.UserAwareController
import com.android.systemui.statusbar.policy.CallbackController
interface ControlsListingController :
- CallbackController<ControlsListingController.ControlsListingCallback> {
+ CallbackController<ControlsListingController.ControlsListingCallback>,
+ UserAwareController {
fun getCurrentServices(): List<CandidateInfo>
fun getAppLabel(name: ComponentName): CharSequence? = ""
+ @FunctionalInterface
interface ControlsListingCallback {
fun onServicesUpdated(list: List<CandidateInfo>)
}
diff --git a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
index 3949c592..882382c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsListingControllerImpl.kt
@@ -19,6 +19,7 @@
import android.content.ComponentName
import android.content.Context
import android.content.pm.ServiceInfo
+import android.os.UserHandle
import android.service.controls.ControlsProviderService
import android.util.Log
import com.android.internal.annotations.VisibleForTesting
@@ -31,6 +32,16 @@
import javax.inject.Inject
import javax.inject.Singleton
+private fun createServiceListing(context: Context): ServiceListing {
+ return ServiceListing.Builder(context).apply {
+ setIntentAction(ControlsProviderService.SERVICE_CONTROLS)
+ setPermission("android.permission.BIND_CONTROLS")
+ setNoun("Controls Provider")
+ setSetting("controls_providers")
+ setTag("controls_providers")
+ }.build()
+}
+
/**
* Provides a listing of components to be used as ControlsServiceProvider.
*
@@ -43,41 +54,55 @@
class ControlsListingControllerImpl @VisibleForTesting constructor(
private val context: Context,
@Background private val backgroundExecutor: Executor,
- private val serviceListing: ServiceListing
+ private val serviceListingBuilder: (Context) -> ServiceListing
) : ControlsListingController {
@Inject
constructor(context: Context, executor: Executor): this(
context,
executor,
- ServiceListing.Builder(context)
- .setIntentAction(ControlsProviderService.SERVICE_CONTROLS)
- .setPermission("android.permission.BIND_CONTROLS")
- .setNoun("Controls Provider")
- .setSetting("controls_providers")
- .setTag("controls_providers")
- .build()
+ ::createServiceListing
)
+ private var serviceListing = serviceListingBuilder(context)
+
companion object {
private const val TAG = "ControlsListingControllerImpl"
}
private var availableServices = emptyList<ServiceInfo>()
- init {
- serviceListing.addCallback {
- Log.d(TAG, "ServiceConfig reloaded")
- availableServices = it.toList()
+ override var currentUserId = context.userId
+ private set
- backgroundExecutor.execute {
- callbacks.forEach {
- it.onServicesUpdated(getCurrentServices())
- }
+ private val serviceListingCallback = ServiceListing.Callback {
+ Log.d(TAG, "ServiceConfig reloaded")
+ availableServices = it.toList()
+
+ backgroundExecutor.execute {
+ callbacks.forEach {
+ it.onServicesUpdated(getCurrentServices())
}
}
}
+ init {
+ serviceListing.addCallback(serviceListingCallback)
+ }
+
+ override fun changeUser(newUser: UserHandle) {
+ backgroundExecutor.execute {
+ callbacks.clear()
+ availableServices = emptyList()
+ serviceListing.setListening(false)
+ serviceListing.removeCallback(serviceListingCallback)
+ currentUserId = newUser.identifier
+ val contextForUser = context.createContextAsUser(newUser, 0)
+ serviceListing = serviceListingBuilder(contextForUser)
+ serviceListing.addCallback(serviceListingCallback)
+ }
+ }
+
// All operations in background thread
private val callbacks = mutableSetOf<ControlsListingController.ControlsListingCallback>()
@@ -91,6 +116,7 @@
*/
override fun addCallback(listener: ControlsListingController.ControlsListingCallback) {
backgroundExecutor.execute {
+ Log.d(TAG, "Subscribing callback")
callbacks.add(listener)
if (callbacks.size == 1) {
serviceListing.setListening(true)
@@ -108,6 +134,7 @@
*/
override fun removeCallback(listener: ControlsListingController.ControlsListingCallback) {
backgroundExecutor.execute {
+ Log.d(TAG, "Unsubscribing callback")
callbacks.remove(listener)
if (callbacks.size == 0) {
serviceListing.setListening(false)
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 69af516..5ff949c 100644
--- a/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
+++ b/packages/SystemUI/src/com/android/systemui/controls/management/ControlsProviderSelectorActivity.kt
@@ -22,7 +22,10 @@
import android.view.LayoutInflater
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Background
import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.settings.CurrentUserTracker
import com.android.systemui.util.LifecycleActivity
import java.util.concurrent.Executor
import javax.inject.Inject
@@ -32,7 +35,9 @@
*/
class ControlsProviderSelectorActivity @Inject constructor(
@Main private val executor: Executor,
- private val listingController: ControlsListingController
+ @Background private val backExecutor: Executor,
+ private val listingController: ControlsListingController,
+ broadcastDispatcher: BroadcastDispatcher
) : LifecycleActivity() {
companion object {
@@ -40,6 +45,16 @@
}
private lateinit var recyclerView: RecyclerView
+ private val currentUserTracker = object : CurrentUserTracker(broadcastDispatcher) {
+ private val startingUser = listingController.currentUserId
+
+ override fun onUserSwitched(newUserId: Int) {
+ if (newUserId != startingUser) {
+ stopTracking()
+ finish()
+ }
+ }
+ }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -50,6 +65,7 @@
recyclerView.layoutManager = LinearLayoutManager(applicationContext)
setContentView(recyclerView)
+ currentUserTracker.startTracking()
}
/**
@@ -57,13 +73,17 @@
* @param component a component name for a [ControlsProviderService]
*/
fun launchFavoritingActivity(component: ComponentName?) {
- component?.let {
- val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java).apply {
- putExtra(ControlsFavoritingActivity.EXTRA_APP, listingController.getAppLabel(it))
- putExtra(ControlsFavoritingActivity.EXTRA_COMPONENT, it)
- flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP
+ backExecutor.execute {
+ component?.let {
+ val intent = Intent(applicationContext, ControlsFavoritingActivity::class.java)
+ .apply {
+ putExtra(ControlsFavoritingActivity.EXTRA_APP,
+ listingController.getAppLabel(it))
+ putExtra(ControlsFavoritingActivity.EXTRA_COMPONENT, it)
+ flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_SINGLE_TOP
+ }
+ startActivity(intent)
}
- startActivity(intent)
}
}
}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f793b3df9..7b54199 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -38,6 +38,7 @@
import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinder;
import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
+import com.android.systemui.statusbar.notification.dagger.NotificationsModule;
import com.android.systemui.statusbar.notification.people.PeopleHubModule;
import com.android.systemui.statusbar.notification.row.dagger.NotificationRowComponent;
import com.android.systemui.statusbar.phone.KeyguardLiftController;
@@ -64,6 +65,7 @@
AssistModule.class,
ConcurrencyModule.class,
LogModule.class,
+ NotificationsModule.class,
PeopleHubModule.class,
},
subcomponents = {StatusBarComponent.class, NotificationRowComponent.class})
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
index 43db85b..6f655bb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeFactory.java
@@ -118,6 +118,7 @@
new DozeWallpaperState(mWallpaperManager, mBiometricUnlockController,
mDozeParameters),
new DozeDockHandler(config, machine, mDockManager),
+ new DozeSuppressedHandler(dozeService, config, machine),
new DozeAuthRemover(dozeService)
});
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
index 8afdf1a..96ae6c9 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLog.java
@@ -266,6 +266,14 @@
mLogger.logSensorTriggered(reason);
}
+ /**
+ * Appends doze suppressed event to the logs
+ * @param suppressedState The {@link DozeMachine.State} that was suppressed
+ */
+ public void traceDozeSuppressed(DozeMachine.State suppressedState) {
+ mLogger.logDozeSuppressed(suppressedState);
+ }
+
private class SummaryStats {
private int mCount;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
index 42decd5..732745a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeLogger.kt
@@ -194,6 +194,14 @@
"Sensor triggered, type=${reasonToString(int1)}"
})
}
+
+ fun logDozeSuppressed(state: DozeMachine.State) {
+ buffer.log(TAG, INFO, {
+ str1 = state.name
+ }, {
+ "Doze state suppressed, state=$str1"
+ })
+ }
}
private const val TAG = "DozeLog"
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
index 03c25ee..6e81d3a 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeMachine.java
@@ -102,6 +102,10 @@
}
}
+ boolean isAlwaysOn() {
+ return this == DOZE_AOD || this == DOZE_AOD_DOCKED;
+ }
+
int screenState(DozeParameters parameters) {
switch (this) {
case UNINITIALIZED:
@@ -324,6 +328,11 @@
if (mState == State.FINISH) {
return State.FINISH;
}
+ if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT) && requestedState.isAlwaysOn()) {
+ Log.i(TAG, "Doze is suppressed. Suppressing state: " + requestedState);
+ mDozeLog.traceDozeSuppressed(requestedState);
+ return State.DOZE;
+ }
if ((mState == State.DOZE_AOD_PAUSED || mState == State.DOZE_AOD_PAUSING
|| mState == State.DOZE_AOD || mState == State.DOZE)
&& requestedState == State.DOZE_PULSE_DONE) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 3abeea9..e50f1fb 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -18,7 +18,6 @@
import static com.android.systemui.doze.DozeMachine.State.DOZE;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD;
-import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_DOCKED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSED;
import static com.android.systemui.doze.DozeMachine.State.DOZE_AOD_PAUSING;
import static com.android.systemui.doze.DozeMachine.State.DOZE_PULSE_DONE;
@@ -90,10 +89,10 @@
}
final boolean messagePending = mHandler.hasCallbacks(mApplyPendingScreenState);
- final boolean pulseEnding = oldState == DOZE_PULSE_DONE && isAlwaysOnState(newState);
+ final boolean pulseEnding = oldState == DOZE_PULSE_DONE && newState.isAlwaysOn();
final boolean turningOn = (oldState == DOZE_AOD_PAUSED || oldState == DOZE)
- && isAlwaysOnState(newState);
- final boolean turningOff = (isAlwaysOnState(oldState) && newState == DOZE)
+ && newState.isAlwaysOn();
+ final boolean turningOff = (newState.isAlwaysOn() && newState == DOZE)
|| (oldState == DOZE_AOD_PAUSING && newState == DOZE_AOD_PAUSED);
final boolean justInitialized = oldState == DozeMachine.State.INITIALIZED;
if (messagePending || justInitialized || pulseEnding || turningOn) {
@@ -132,10 +131,6 @@
}
}
- private boolean isAlwaysOnState(DozeMachine.State state) {
- return state == DOZE_AOD || state == DOZE_AOD_DOCKED;
- }
-
private void applyPendingScreenState() {
applyScreenState(mPendingScreenState);
mPendingScreenState = Display.STATE_UNKNOWN;
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java
new file mode 100644
index 0000000..3a5c1a0
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSuppressedHandler.java
@@ -0,0 +1,124 @@
+/*
+ * 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.doze;
+
+import static java.util.Objects.requireNonNull;
+
+import android.app.ActivityManager;
+import android.content.ContentResolver;
+import android.content.Context;
+import android.database.ContentObserver;
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.util.Log;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+/** Handles updating the doze state when doze is suppressed. */
+public final class DozeSuppressedHandler implements DozeMachine.Part {
+
+ private static final String TAG = DozeSuppressedHandler.class.getSimpleName();
+ private static final boolean DEBUG = DozeService.DEBUG;
+
+ private final ContentResolver mResolver;
+ private final AmbientDisplayConfiguration mConfig;
+ private final DozeMachine mMachine;
+ private final DozeSuppressedSettingObserver mSettingObserver;
+ private final Handler mHandler = new Handler();
+
+ public DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config,
+ DozeMachine machine) {
+ this(context, config, machine, null);
+ }
+
+ @VisibleForTesting
+ DozeSuppressedHandler(Context context, AmbientDisplayConfiguration config, DozeMachine machine,
+ DozeSuppressedSettingObserver observer) {
+ mResolver = context.getContentResolver();
+ mConfig = requireNonNull(config);
+ mMachine = requireNonNull(machine);
+ if (observer == null) {
+ mSettingObserver = new DozeSuppressedSettingObserver(mHandler);
+ } else {
+ mSettingObserver = observer;
+ }
+ }
+
+ @Override
+ public void transitionTo(DozeMachine.State oldState, DozeMachine.State newState) {
+ switch (newState) {
+ case INITIALIZED:
+ mSettingObserver.register();
+ break;
+ case FINISH:
+ mSettingObserver.unregister();
+ break;
+ default:
+ // no-op
+ }
+ }
+
+ /**
+ * Listens to changes to the DOZE_SUPPRESSED secure setting and updates the doze state
+ * accordingly.
+ */
+ final class DozeSuppressedSettingObserver extends ContentObserver {
+ private boolean mRegistered;
+
+ private DozeSuppressedSettingObserver(Handler handler) {
+ super(handler);
+ }
+
+ @Override
+ public void onChange(boolean selfChange, Uri uri, int userId) {
+ if (userId != ActivityManager.getCurrentUser()) {
+ return;
+ }
+ final DozeMachine.State nextState;
+ if (mConfig.alwaysOnEnabled(UserHandle.USER_CURRENT)
+ && !mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) {
+ nextState = DozeMachine.State.DOZE_AOD;
+ } else {
+ nextState = DozeMachine.State.DOZE;
+ }
+ mMachine.requestState(nextState);
+ }
+
+ void register() {
+ if (mRegistered) {
+ return;
+ }
+ mResolver.registerContentObserver(
+ Settings.Secure.getUriFor(Settings.Secure.SUPPRESS_DOZE),
+ false, this, UserHandle.USER_CURRENT);
+ Log.d(TAG, "Register");
+ mRegistered = true;
+ }
+
+ void unregister() {
+ if (!mRegistered) {
+ return;
+ }
+ mResolver.unregisterContentObserver(this);
+ Log.d(TAG, "Unregister");
+ mRegistered = false;
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
index b9c056d..305a4c8 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeTriggers.java
@@ -127,6 +127,11 @@
mDozeLog.tracePulseDropped("pulseOnNotificationsDisabled");
return;
}
+ if (mConfig.dozeSuppressed(UserHandle.USER_CURRENT)) {
+ runIfNotNull(onPulseSuppressedListener);
+ mDozeLog.tracePulseDropped("dozeSuppressed");
+ return;
+ }
requestPulse(DozeLog.PULSE_REASON_NOTIFICATION, false /* performedProxCheck */,
onPulseSuppressedListener);
mDozeLog.traceNotificationPulse();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
index f33c931..45c07a3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsDialog.java
@@ -1801,6 +1801,7 @@
void dismissImmediately() {
mShowing = false;
+ if (mControlsUiController != null) mControlsUiController.hide();
dismissPanel();
resetOrientation();
completeDismiss();
diff --git a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
index dd1856a..c9c38d3 100644
--- a/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/globalactions/GlobalActionsImpl.java
@@ -30,17 +30,17 @@
import android.widget.TextView;
import com.android.internal.R;
-import com.android.internal.colorextraction.ColorExtractor.GradientColors;
import com.android.internal.colorextraction.drawable.ScrimDrawable;
import com.android.keyguard.KeyguardUpdateMonitor;
import com.android.settingslib.Utils;
import com.android.systemui.Dependency;
-import com.android.systemui.colorextraction.SysuiColorExtractor;
import com.android.systemui.plugins.GlobalActions;
import com.android.systemui.plugins.GlobalActionsPanelPlugin;
import com.android.systemui.plugins.PluginListener;
import com.android.systemui.shared.plugins.PluginManager;
+import com.android.systemui.statusbar.BlurUtils;
import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.ScrimController;
import com.android.systemui.statusbar.policy.DeviceProvisionedController;
import com.android.systemui.statusbar.policy.ExtensionController;
import com.android.systemui.statusbar.policy.KeyguardStateController;
@@ -59,6 +59,7 @@
private final KeyguardStateController mKeyguardStateController;
private final DeviceProvisionedController mDeviceProvisionedController;
private final ExtensionController.Extension<GlobalActionsPanelPlugin> mPanelExtension;
+ private final BlurUtils mBlurUtils;
private GlobalActionsPanelPlugin mPlugin;
private final CommandQueue mCommandQueue;
private GlobalActionsDialog mGlobalActionsDialog;
@@ -68,13 +69,14 @@
@Inject
public GlobalActionsImpl(Context context, CommandQueue commandQueue,
- Lazy<GlobalActionsDialog> globalActionsDialogLazy) {
+ Lazy<GlobalActionsDialog> globalActionsDialogLazy, BlurUtils blurUtils) {
mContext = context;
mGlobalActionsDialogLazy = globalActionsDialogLazy;
mKeyguardStateController = Dependency.get(KeyguardStateController.class);
mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
mPluginManager = Dependency.get(PluginManager.class);
mCommandQueue = commandQueue;
+ mBlurUtils = blurUtils;
mCommandQueue.addCallback(this);
mPanelExtension = Dependency.get(ExtensionController.class)
.newExtension(GlobalActionsPanelPlugin.class)
@@ -110,7 +112,6 @@
@Override
public void showShutdownUi(boolean isReboot, String reason) {
ScrimDrawable background = new ScrimDrawable();
- background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
Dialog d = new Dialog(mContext,
com.android.systemui.R.style.Theme_SystemUI_Dialog_GlobalActions);
@@ -160,8 +161,13 @@
reasonView.setText(rebootReasonMessage);
}
- GradientColors colors = Dependency.get(SysuiColorExtractor.class).getNeutralColors();
- background.setColor(colors.getMainColor(), false);
+ if (mBlurUtils.supportsBlursOnWindows()) {
+ background.setAlpha((int) (ScrimController.GRADIENT_SCRIM_ALPHA_BUSY * 255));
+ mBlurUtils.applyBlur(d.getWindow().getDecorView().getViewRootImpl(),
+ mBlurUtils.radiusForRatio(1));
+ } else {
+ background.setAlpha((int) (SHUTDOWN_SCRIM_ALPHA * 255));
+ }
d.show();
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index 3fcd1c1..476af20 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -116,6 +116,7 @@
@Override
public void onClick(View v) {
+ if (!hasFooter()) return;
mHandler.sendEmptyMessage(H.CLICK);
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
index de8e6ea..7ebebaa 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/TriangleShape.java
@@ -70,6 +70,6 @@
@Override
public void getOutline(@NonNull Outline outline) {
- outline.setConvexPath(mTriangularPath);
+ outline.setPath(mTriangularPath);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
index e6082dd..e7e1ba8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/SaveImageInBackgroundTask.java
@@ -106,7 +106,7 @@
// Initialize screenshot notification smart actions provider.
mSmartActionsEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_SYSTEMUI,
- SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, false);
+ SystemUiDeviceConfigFlags.ENABLE_SCREENSHOT_NOTIFICATION_SMART_ACTIONS, true);
if (mSmartActionsEnabled) {
mSmartActionsProvider =
SystemUIFactory.getInstance()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
index 015c323..269a7a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/BypassHeadsUpNotifier.kt
@@ -43,10 +43,10 @@
private val headsUpManager: HeadsUpManagerPhone,
private val notificationLockscreenUserManager: NotificationLockscreenUserManager,
private val mediaManager: NotificationMediaManager,
+ private val entryManager: NotificationEntryManager,
tunerService: TunerService
) : StatusBarStateController.StateListener, NotificationMediaManager.MediaListener {
- private lateinit var entryManager: NotificationEntryManager
private var currentMediaEntry: NotificationEntry? = null
private var enabled = true
@@ -70,8 +70,7 @@
}, Settings.Secure.SHOW_MEDIA_WHEN_BYPASSING)
}
- fun setUp(entryManager: NotificationEntryManager) {
- this.entryManager = entryManager
+ fun setUp() {
mediaManager.addCallback(this)
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
index 8ac4d30..cb8cef8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifCollection.java
@@ -92,8 +92,8 @@
* {@link #addNotificationLifetimeExtender(NotifLifetimeExtender)}).
*
* Interested parties can register listeners
- * ({@link #addCollectionListener(NotifCollectionListener)}) to be informed when notifications are
- * added, updated, or removed.
+ * ({@link #addCollectionListener(NotifCollectionListener)}) to be informed when notifications
+ * events occur.
*/
@MainThread
@Singleton
@@ -230,6 +230,8 @@
entry = new NotificationEntry(sbn, ranking);
mNotificationSet.put(sbn.getKey(), entry);
+ dispatchOnEntryInit(entry);
+
if (rankingMap != null) {
applyRanking(rankingMap);
}
@@ -297,6 +299,7 @@
}
dispatchOnEntryRemoved(entry, reason, dismissedByUserStats != null /* removedByUser */);
+ dispatchOnEntryCleanUp(entry);
}
rebuildList();
@@ -378,6 +381,14 @@
return ranking;
}
+ private void dispatchOnEntryInit(NotificationEntry entry) {
+ mAmDispatchingToOtherCode = true;
+ for (NotifCollectionListener listener : mNotifCollectionListeners) {
+ listener.onEntryInit(entry);
+ }
+ mAmDispatchingToOtherCode = false;
+ }
+
private void dispatchOnEntryAdded(NotificationEntry entry) {
mAmDispatchingToOtherCode = true;
for (NotifCollectionListener listener : mNotifCollectionListeners) {
@@ -413,6 +424,14 @@
mAmDispatchingToOtherCode = false;
}
+ private void dispatchOnEntryCleanUp(NotificationEntry entry) {
+ mAmDispatchingToOtherCode = true;
+ for (NotifCollectionListener listener : mNotifCollectionListeners) {
+ listener.onEntryCleanUp(entry);
+ }
+ mAmDispatchingToOtherCode = false;
+ }
+
private final BatchableNotificationHandler mNotifHandler = new BatchableNotificationHandler() {
@Override
public void onNotificationPosted(StatusBarNotification sbn, RankingMap rankingMap) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
index 0377f57..9142388 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotifPipeline.java
@@ -90,7 +90,8 @@
}
/**
- * Registers a listener to be informed when notifications are added, removed or updated.
+ * Registers a listener to be informed when there is a notification entry event such as an add,
+ * update, or remove.
*/
public void addCollectionListener(NotifCollectionListener listener) {
mNotifCollection.addCollectionListener(listener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
index 6adcabd..ff6da12 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/notifcollection/NotifCollectionListener.java
@@ -18,15 +18,25 @@
import android.service.notification.NotificationListenerService;
-import com.android.systemui.statusbar.notification.collection.NotifCollection;
import com.android.systemui.statusbar.notification.collection.NotifCollection.CancellationReason;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
/**
- * Listener interface for {@link NotifCollection}.
+ * Listener interface for {@link NotificationEntry} events.
*/
public interface NotifCollectionListener {
/**
+ * Called whenever a new {@link NotificationEntry} is initialized. This should be used for
+ * initializing any decorated state tied to the notification.
+ *
+ * Do not reference other registered {@link NotifCollectionListener} implementations here as
+ * there is no guarantee of order and they may not have had a chance to initialize yet. Instead,
+ * use {@link #onEntryAdded} which is called after all initialization.
+ */
+ default void onEntryInit(NotificationEntry entry) {
+ }
+
+ /**
* Called whenever a notification with a new key is posted.
*/
default void onEntryAdded(NotificationEntry entry) {
@@ -51,6 +61,18 @@
}
/**
+ * Called whenever a {@link NotificationEntry} is considered deleted. This should be used for
+ * cleaning up any state tied to the notification.
+ *
+ * This is the deletion parallel of {@link #onEntryInit} and similarly means that you cannot
+ * expect other {@link NotifCollectionListener} implementations to still have valid state for
+ * the entry during this call. Instead, use {@link #onEntryRemoved} which will be called before
+ * deletion.
+ */
+ default void onEntryCleanUp(NotificationEntry entry) {
+ }
+
+ /**
* Called whenever the RankingMap is updated by system server. By the time this listener is
* called, the Rankings of all entries will have been updated.
*/
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
new file mode 100644
index 0000000..c7666e4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.dagger;
+
+import android.content.Context;
+
+import com.android.systemui.R;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
+import com.android.systemui.statusbar.notification.init.NotificationsControllerImpl;
+import com.android.systemui.statusbar.notification.init.NotificationsControllerStub;
+
+import javax.inject.Singleton;
+
+import dagger.Lazy;
+import dagger.Module;
+import dagger.Provides;
+
+/** Module for classes related to the notifications data pipeline */
+@Module
+public class NotificationsModule {
+ /** Initializes the notification data pipeline (can be disabled via config). */
+ @Singleton
+ @Provides
+ static NotificationsController provideNotificationsController(
+ Context context,
+ Lazy<NotificationsControllerImpl> realController,
+ Lazy<NotificationsControllerStub> stubController) {
+ if (context.getResources().getBoolean(R.bool.config_renderNotifications)) {
+ return realController.get();
+ } else {
+ return stubController.get();
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
new file mode 100644
index 0000000..9da8b8a3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsController.kt
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.init
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.StatusBar
+import java.io.FileDescriptor
+import java.io.PrintWriter
+
+/**
+ * The master controller for all notifications-related work
+ *
+ * Split into two implementations: [NotificationsControllerImpl] (most cases) and
+ * [NotificationsControllerStub] (for builds that disable notification rendering).
+ */
+interface NotificationsController {
+ fun initialize(
+ statusBar: StatusBar,
+ presenter: NotificationPresenter,
+ listContainer: NotificationListContainer,
+ notificationActivityStarter: NotificationActivityStarter,
+ bindRowCallback: NotificationRowBinderImpl.BindRowCallback
+ )
+
+ fun requestNotificationUpdate(reason: String)
+ fun resetUserExpandedStates()
+ fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption)
+ fun getActiveNotificationsCount(): Int
+ fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int)
+ fun dump(fd: FileDescriptor, pw: PrintWriter, args: Array<String>, dumpTruck: Boolean)
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
new file mode 100644
index 0000000..61e3192
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerImpl.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.init
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.bubbles.BubbleController
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
+import com.android.systemui.statusbar.FeatureFlags
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.NotificationClicker
+import com.android.systemui.statusbar.notification.NotificationEntryManager
+import com.android.systemui.statusbar.notification.NotificationListController
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
+import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.NotificationGroupAlertTransferHelper
+import com.android.systemui.statusbar.phone.NotificationGroupManager
+import com.android.systemui.statusbar.phone.StatusBar
+import com.android.systemui.statusbar.policy.DeviceProvisionedController
+import com.android.systemui.statusbar.policy.HeadsUpManager
+import com.android.systemui.statusbar.policy.RemoteInputUriController
+import dagger.Lazy
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import java.util.Optional
+import javax.inject.Inject
+import javax.inject.Singleton
+
+/**
+ * Master controller for all notifications-related work
+ *
+ * At the moment exposes a number of event-handler-esque methods; these are for historical reasons.
+ * Once we migrate away from the need for such things, this class becomes primarily a place to do
+ * any initialization work that notifications require.
+ */
+@Singleton
+class NotificationsControllerImpl @Inject constructor(
+ private val featureFlags: FeatureFlags,
+ private val notificationListener: NotificationListener,
+ private val entryManager: NotificationEntryManager,
+ private val newNotifPipeline: Lazy<NotifPipelineInitializer>,
+ private val deviceProvisionedController: DeviceProvisionedController,
+ private val notificationRowBinder: NotificationRowBinderImpl,
+ private val remoteInputUriController: RemoteInputUriController,
+ private val bubbleController: BubbleController,
+ private val groupManager: NotificationGroupManager,
+ private val groupAlertTransferHelper: NotificationGroupAlertTransferHelper,
+ private val headsUpManager: HeadsUpManager
+) : NotificationsController {
+
+ override fun initialize(
+ statusBar: StatusBar,
+ presenter: NotificationPresenter,
+ listContainer: NotificationListContainer,
+ notificationActivityStarter: NotificationActivityStarter,
+ bindRowCallback: NotificationRowBinderImpl.BindRowCallback
+ ) {
+ notificationListener.registerAsSystemService()
+
+ val listController =
+ NotificationListController(
+ entryManager,
+ listContainer,
+ deviceProvisionedController)
+ listController.bind()
+
+ notificationRowBinder.setNotificationClicker(
+ NotificationClicker(
+ Optional.of(statusBar),
+ bubbleController,
+ notificationActivityStarter))
+ notificationRowBinder.setUpWithPresenter(
+ presenter,
+ listContainer,
+ headsUpManager,
+ bindRowCallback)
+
+ if (featureFlags.isNewNotifPipelineEnabled) {
+ newNotifPipeline.get().initialize(notificationListener, notificationRowBinder)
+ }
+
+ if (featureFlags.isNewNotifPipelineRenderingEnabled) {
+ // TODO
+ } else {
+ notificationRowBinder.setInflationCallback(entryManager)
+
+ remoteInputUriController.attach(entryManager)
+ groupAlertTransferHelper.bind(entryManager, groupManager)
+ headsUpManager.addListener(groupManager)
+ headsUpManager.addListener(groupAlertTransferHelper)
+ groupManager.setHeadsUpManager(headsUpManager)
+ groupAlertTransferHelper.setHeadsUpManager(headsUpManager)
+
+ entryManager.attach(notificationListener)
+ }
+ }
+
+ override fun dump(
+ fd: FileDescriptor,
+ pw: PrintWriter,
+ args: Array<String>,
+ dumpTruck: Boolean
+ ) {
+ if (dumpTruck) {
+ entryManager.dump(pw, " ")
+ }
+ groupManager.dump(fd, pw, args)
+ }
+
+ // TODO: Convert all functions below this line into listeners instead of public methods
+
+ override fun requestNotificationUpdate(reason: String) {
+ entryManager.updateNotifications(reason)
+ }
+
+ override fun resetUserExpandedStates() {
+ for (entry in entryManager.visibleNotifications) {
+ entry.resetUserExpansion()
+ }
+ }
+
+ override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {
+ if (snoozeOption.snoozeCriterion != null) {
+ notificationListener.snoozeNotification(sbn.key, snoozeOption.snoozeCriterion.id)
+ } else {
+ notificationListener.snoozeNotification(
+ sbn.key,
+ snoozeOption.minutesToSnoozeFor * 60 * 1000.toLong())
+ }
+ }
+
+ override fun getActiveNotificationsCount(): Int {
+ return entryManager.activeNotificationsCount
+ }
+
+ override fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int) {
+ notificationListener.snoozeNotification(
+ sbn.key,
+ hoursToSnooze * 60 * 60 * 1000.toLong())
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
new file mode 100644
index 0000000..ded855d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/init/NotificationsControllerStub.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.notification.init
+
+import android.service.notification.StatusBarNotification
+import com.android.systemui.plugins.statusbar.NotificationSwipeActionHelper.SnoozeOption
+import com.android.systemui.statusbar.NotificationListener
+import com.android.systemui.statusbar.NotificationPresenter
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl
+import com.android.systemui.statusbar.notification.stack.NotificationListContainer
+import com.android.systemui.statusbar.phone.StatusBar
+import java.io.FileDescriptor
+import java.io.PrintWriter
+import javax.inject.Inject
+
+/**
+ * Implementation of [NotificationsController] that's used when notifications rendering is disabled.
+ */
+class NotificationsControllerStub @Inject constructor(
+ private val notificationListener: NotificationListener
+) : NotificationsController {
+
+ override fun initialize(
+ statusBar: StatusBar,
+ presenter: NotificationPresenter,
+ listContainer: NotificationListContainer,
+ notificationActivityStarter: NotificationActivityStarter,
+ bindRowCallback: NotificationRowBinderImpl.BindRowCallback
+ ) {
+ // Always connect the listener even if notification-handling is disabled. Being a listener
+ // grants special permissions and it's not clear if other things will break if we lose those
+ notificationListener.registerAsSystemService()
+ }
+
+ override fun requestNotificationUpdate(reason: String) {
+ }
+
+ override fun resetUserExpandedStates() {
+ }
+
+ override fun setNotificationSnoozed(sbn: StatusBarNotification, snoozeOption: SnoozeOption) {
+ }
+
+ override fun setNotificationSnoozed(sbn: StatusBarNotification, hoursToSnooze: Int) {
+ }
+
+ override fun getActiveNotificationsCount(): Int {
+ return 0
+ }
+
+ override fun dump(
+ fd: FileDescriptor,
+ pw: PrintWriter,
+ args: Array<String>,
+ dumpTruck: Boolean
+ ) {
+ pw.println()
+ pw.println("Notification handling disabled")
+ pw.println()
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
index 28f4136..049cafa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableOutlineView.java
@@ -93,7 +93,7 @@
} else {
Path clipPath = getClipPath(false /* ignoreTranslation */);
if (clipPath != null) {
- outline.setConvexPath(clipPath);
+ outline.setPath(clipPath);
}
}
outline.setAlpha(mOutlineAlpha);
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 1726b488..11f7079 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -168,12 +168,10 @@
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.CrossFadeHelper;
import com.android.systemui.statusbar.EmptyShadeView;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.GestureRecorder;
import com.android.systemui.statusbar.KeyboardShortcuts;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationPresenter;
@@ -191,15 +189,11 @@
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationActivityStarter;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationClicker;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
-import com.android.systemui.statusbar.notification.NotificationListController;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
@@ -218,7 +212,6 @@
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
@@ -356,7 +349,6 @@
private final Object mQueueLock = new Object();
- private final FeatureFlags mFeatureFlags;
private final StatusBarIconController mIconController;
private final PulseExpansionHandler mPulseExpansionHandler;
private final NotificationWakeUpCoordinator mWakeUpCoordinator;
@@ -365,7 +357,6 @@
private final HeadsUpManagerPhone mHeadsUpManager;
private final DynamicPrivacyController mDynamicPrivacyController;
private final BypassHeadsUpNotifier mBypassHeadsUpNotifier;
- private final Lazy<NotifPipelineInitializer> mNewNotifPipeline;
private final FalsingManager mFalsingManager;
private final BroadcastDispatcher mBroadcastDispatcher;
private final ConfigurationController mConfigurationController;
@@ -374,7 +365,6 @@
private final Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
private final Provider<StatusBarComponent.Builder> mStatusBarComponentBuilder;
private final PluginManager mPluginManager;
- private final RemoteInputUriController mRemoteInputUriController;
private final Optional<Divider> mDividerOptional;
private final StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
@@ -387,8 +377,8 @@
private final KeyguardDismissUtil mKeyguardDismissUtil;
private final ExtensionController mExtensionController;
private final UserInfoControllerImpl mUserInfoControllerImpl;
- private final NotificationRowBinderImpl mNotificationRowBinder;
private final DismissCallbackRegistry mDismissCallbackRegistry;
+ private NotificationsController mNotificationsController;
// expanded notifications
// the sliding/resizing panel within the notification window
@@ -412,8 +402,6 @@
private final NotificationGutsManager mGutsManager;
private final NotificationLogger mNotificationLogger;
- private final NotificationEntryManager mEntryManager;
- private NotificationListController mNotificationListController;
private final NotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
private final NotificationViewHierarchyManager mViewHierarchyManager;
private final KeyguardViewMediator mKeyguardViewMediator;
@@ -589,7 +577,7 @@
@Override
public void onStrongAuthStateChanged(int userId) {
super.onStrongAuthStateChanged(userId);
- mEntryManager.updateNotifications("onStrongAuthStateChanged");
+ mNotificationsController.requestNotificationUpdate("onStrongAuthStateChanged");
}
};
private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper());
@@ -614,7 +602,7 @@
@SuppressWarnings("OptionalUsedAsFieldOrParameterType")
public StatusBar(
Context context,
- FeatureFlags featureFlags,
+ NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -626,13 +614,11 @@
HeadsUpManagerPhone headsUpManagerPhone,
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
- Lazy<NotifPipelineInitializer> newNotifPipeline,
FalsingManager falsingManager,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationEntryManager notificationEntryManager,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -653,12 +639,10 @@
VibratorHelper vibratorHelper,
BubbleController bubbleController,
NotificationGroupManager groupManager,
- NotificationGroupAlertTransferHelper groupAlertTransferHelper,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
- NotificationListener notificationListener,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
LockscreenLockIconController lockscreenLockIconController,
@@ -676,7 +660,6 @@
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
@@ -692,10 +675,9 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- NotificationRowBinderImpl notificationRowBinder,
DismissCallbackRegistry dismissCallbackRegistry) {
super(context);
- mFeatureFlags = featureFlags;
+ mNotificationsController = notificationsController;
mLightBarController = lightBarController;
mAutoHideController = autoHideController;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
@@ -707,13 +689,11 @@
mHeadsUpManager = headsUpManagerPhone;
mDynamicPrivacyController = dynamicPrivacyController;
mBypassHeadsUpNotifier = bypassHeadsUpNotifier;
- mNewNotifPipeline = newNotifPipeline;
mFalsingManager = falsingManager;
mBroadcastDispatcher = broadcastDispatcher;
mRemoteInputQuickSettingsDisabler = remoteInputQuickSettingsDisabler;
mGutsManager = notificationGutsManager;
mNotificationLogger = notificationLogger;
- mEntryManager = notificationEntryManager;
mNotificationInterruptionStateProvider = notificationInterruptionStateProvider;
mViewHierarchyManager = notificationViewHierarchyManager;
mKeyguardViewMediator = keyguardViewMediator;
@@ -734,12 +714,10 @@
mVibratorHelper = vibratorHelper;
mBubbleController = bubbleController;
mGroupManager = groupManager;
- mGroupAlertTransferHelper = groupAlertTransferHelper;
mVisualStabilityManager = visualStabilityManager;
mDeviceProvisionedController = deviceProvisionedController;
mNavigationBarController = navigationBarController;
mAssistManagerLazy = assistManagerLazy;
- mNotificationListener = notificationListener;
mConfigurationController = configurationController;
mNotificationShadeWindowController = notificationShadeWindowController;
mLockscreenLockIconController = lockscreenLockIconController;
@@ -757,7 +735,6 @@
mRecentsOptional = recentsOptional;
mStatusBarComponentBuilder = statusBarComponentBuilder;
mPluginManager = pluginManager;
- mRemoteInputUriController = remoteInputUriController;
mDividerOptional = dividerOptional;
mStatusBarNotificationActivityStarterBuilder = statusBarNotificationActivityStarterBuilder;
mShadeController = shadeController;
@@ -771,12 +748,11 @@
mKeyguardDismissUtil = keyguardDismissUtil;
mExtensionController = extensionController;
mUserInfoControllerImpl = userInfoControllerImpl;
- mNotificationRowBinder = notificationRowBinder;
mDismissCallbackRegistry = dismissCallbackRegistry;
mBubbleExpandListener =
(isExpanding, key) -> {
- mEntryManager.updateNotifications("onBubbleExpandChanged");
+ mNotificationsController.requestNotificationUpdate("onBubbleExpandChanged");
updateScrimController();
};
@@ -786,11 +762,10 @@
@Override
public void start() {
- mNotificationListener.registerAsSystemService();
mScreenLifecycle.addObserver(mScreenObserver);
mWakefulnessLifecycle.addObserver(mWakefulnessObserver);
mUiModeManager = mContext.getSystemService(UiModeManager.class);
- mBypassHeadsUpNotifier.setUp(mEntryManager);
+ mBypassHeadsUpNotifier.setUp();
mBubbleController.setExpandListener(mBubbleExpandListener);
mActivityIntentHelper = new ActivityIntentHelper(mContext);
@@ -1060,12 +1035,8 @@
mConfigurationController.addCallback(mHeadsUpManager);
mHeadsUpManager.addListener(this);
mHeadsUpManager.addListener(mNotificationPanelViewController.getOnHeadsUpChangedListener());
- mHeadsUpManager.addListener(mGroupManager);
- mHeadsUpManager.addListener(mGroupAlertTransferHelper);
mHeadsUpManager.addListener(mVisualStabilityManager);
mNotificationPanelViewController.setHeadsUpManager(mHeadsUpManager);
- mGroupManager.setHeadsUpManager(mHeadsUpManager);
- mGroupAlertTransferHelper.setHeadsUpManager(mHeadsUpManager);
mNotificationLogger.setHeadsUpManager(mHeadsUpManager);
createNavigationBar(result);
@@ -1243,16 +1214,10 @@
mPresenter = new StatusBarNotificationPresenter(mContext, mNotificationPanelViewController,
mHeadsUpManager, mNotificationShadeWindowView, mStackScroller, mDozeScrimController,
mScrimController, mActivityLaunchAnimator, mDynamicPrivacyController,
- mNotificationAlertingManager, mNotificationRowBinder, mKeyguardStateController,
+ mNotificationAlertingManager, mKeyguardStateController,
mKeyguardIndicationController,
this /* statusBar */, mShadeController, mCommandQueue, mInitController);
- mNotificationListController =
- new NotificationListController(
- mEntryManager,
- (NotificationListContainer) mStackScroller,
- mDeviceProvisionedController);
-
mNotificationShelf.setOnActivatedListener(mPresenter);
mRemoteInputManager.getController().addCallback(mNotificationShadeWindowController);
@@ -1266,22 +1231,12 @@
mGutsManager.setNotificationActivityStarter(mNotificationActivityStarter);
- if (!mFeatureFlags.isNewNotifPipelineRenderingEnabled()) {
- mNotificationRowBinder.setInflationCallback(mEntryManager);
- }
-
- mRemoteInputUriController.attach(mEntryManager);
-
- mNotificationRowBinder.setNotificationClicker(new NotificationClicker(
- Optional.of(this), mBubbleController, mNotificationActivityStarter));
-
- mGroupAlertTransferHelper.bind(mEntryManager, mGroupManager);
- mNotificationListController.bind();
-
- if (mFeatureFlags.isNewNotifPipelineEnabled()) {
- mNewNotifPipeline.get().initialize(mNotificationListener, mNotificationRowBinder);
- }
- mEntryManager.attach(mNotificationListener);
+ mNotificationsController.initialize(
+ this,
+ mPresenter,
+ (NotificationListContainer) mStackScroller,
+ mNotificationActivityStarter,
+ mPresenter);
}
/**
@@ -1518,7 +1473,7 @@
* @param reason why we're requesting a notification update
*/
public void requestNotificationUpdate(String reason) {
- mEntryManager.updateNotifications(reason);
+ mNotificationsController.requestNotificationUpdate(reason);
}
/**
@@ -1726,7 +1681,7 @@
@Override
public void onHeadsUpStateChanged(NotificationEntry entry, boolean isHeadsUp) {
- mEntryManager.updateNotifications("onHeadsUpStateChanged");
+ mNotificationsController.requestNotificationUpdate("onHeadsUpStateChanged");
if (mStatusBarStateController.isDozing() && isHeadsUp) {
entry.setPulseSuppressed(false);
mDozeServiceHost.fireNotificationPulse(entry);
@@ -2485,11 +2440,9 @@
mStatusBarKeyguardViewManager.dump(pw);
}
- if (DUMPTRUCK) {
- synchronized (mEntryManager) {
- mEntryManager.dump(pw, " ");
- }
+ mNotificationsController.dump(fd, pw, args, DUMPTRUCK);
+ if (DUMPTRUCK) {
if (false) {
pw.println("see the logcat for a dump of the views we have created.");
// must happen on ui thread
@@ -2512,11 +2465,6 @@
} else {
pw.println(" mHeadsUpManager: null");
}
- if (mGroupManager != null) {
- mGroupManager.dump(fd, pw, args);
- } else {
- pw.println(" mGroupManager: null");
- }
if (mBubbleController != null) {
mBubbleController.dump(fd, pw, args);
@@ -2747,9 +2695,7 @@
};
public void resetUserExpandedStates() {
- for (NotificationEntry entry : mEntryManager.getVisibleNotifications()) {
- entry.resetUserExpansion();
- }
+ mNotificationsController.resetUserExpandedStates();
}
private void executeWhenUnlocked(OnDismissAction action, boolean requiresShadeOpen) {
@@ -2855,7 +2801,7 @@
try {
// consider the transition from peek to expanded to be a panel open,
// but not one that clears notification effects.
- int notificationLoad = mEntryManager.getActiveNotificationsCount();
+ int notificationLoad = mNotificationsController.getActiveNotificationsCount();
mBarService.onPanelRevealed(false, notificationLoad);
} catch (RemoteException ex) {
// Won't fail unless the world has ended.
@@ -2873,7 +2819,7 @@
!mPresenter.isPresenterFullyCollapsed() &&
(mState == StatusBarState.SHADE
|| mState == StatusBarState.SHADE_LOCKED);
- int notificationLoad = mEntryManager.getActiveNotificationsCount();
+ int notificationLoad = mNotificationsController.getActiveNotificationsCount();
if (pinnedHeadsUp && mPresenter.isPresenterFullyCollapsed()) {
notificationLoad = 1;
}
@@ -3514,7 +3460,7 @@
updateQsExpansionEnabled();
mKeyguardViewMediator.setDozing(mDozing);
- mEntryManager.updateNotifications("onDozingChanged");
+ mNotificationsController.requestNotificationUpdate("onDozingChanged");
updateDozingState();
mDozeServiceHost.updateDozing();
updateScrimController();
@@ -3965,7 +3911,6 @@
protected ViewGroup mStackScroller;
private final NotificationGroupManager mGroupManager;
- private final NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
// handling reordering
private final VisualStabilityManager mVisualStabilityManager;
@@ -4032,21 +3977,12 @@
}
};
- private final NotificationListener mNotificationListener;
-
public void setNotificationSnoozed(StatusBarNotification sbn, SnoozeOption snoozeOption) {
- if (snoozeOption.getSnoozeCriterion() != null) {
- mNotificationListener.snoozeNotification(sbn.getKey(),
- snoozeOption.getSnoozeCriterion().getId());
- } else {
- mNotificationListener.snoozeNotification(sbn.getKey(),
- snoozeOption.getMinutesToSnoozeFor() * 60 * 1000);
- }
+ mNotificationsController.setNotificationSnoozed(sbn, snoozeOption);
}
public void setNotificationSnoozed(StatusBarNotification sbn, int hoursToSnooze) {
- mNotificationListener.snoozeNotification(sbn.getKey(),
- hoursToSnooze * 60 * 60 * 1000);
+ mNotificationsController.setNotificationSnoozed(sbn, hoursToSnooze);
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
index 7615bf8..15a0e08 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarModule.java
@@ -46,9 +46,7 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.NavigationBarController;
-import com.android.systemui.statusbar.NotificationListener;
import com.android.systemui.statusbar.NotificationLockscreenUserManager;
import com.android.systemui.statusbar.NotificationMediaManager;
import com.android.systemui.statusbar.NotificationRemoteInputManager;
@@ -61,12 +59,10 @@
import com.android.systemui.statusbar.notification.BypassHeadsUpNotifier;
import com.android.systemui.statusbar.notification.DynamicPrivacyController;
import com.android.systemui.statusbar.notification.NotificationAlertingManager;
-import com.android.systemui.statusbar.notification.NotificationEntryManager;
import com.android.systemui.statusbar.notification.NotificationInterruptionStateProvider;
import com.android.systemui.statusbar.notification.NotificationWakeUpCoordinator;
import com.android.systemui.statusbar.notification.VisualStabilityManager;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.phone.dagger.StatusBarComponent;
@@ -77,7 +73,6 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
import com.android.systemui.volume.VolumeComponent;
@@ -105,7 +100,7 @@
@Singleton
static StatusBar provideStatusBar(
Context context,
- FeatureFlags featureFlags,
+ NotificationsController notificationsController,
LightBarController lightBarController,
AutoHideController autoHideController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -117,13 +112,11 @@
HeadsUpManagerPhone headsUpManagerPhone,
DynamicPrivacyController dynamicPrivacyController,
BypassHeadsUpNotifier bypassHeadsUpNotifier,
- Lazy<NotifPipelineInitializer> newNotifPipeline,
FalsingManager falsingManager,
BroadcastDispatcher broadcastDispatcher,
RemoteInputQuickSettingsDisabler remoteInputQuickSettingsDisabler,
NotificationGutsManager notificationGutsManager,
NotificationLogger notificationLogger,
- NotificationEntryManager notificationEntryManager,
NotificationInterruptionStateProvider notificationInterruptionStateProvider,
NotificationViewHierarchyManager notificationViewHierarchyManager,
KeyguardViewMediator keyguardViewMediator,
@@ -144,12 +137,10 @@
VibratorHelper vibratorHelper,
BubbleController bubbleController,
NotificationGroupManager groupManager,
- NotificationGroupAlertTransferHelper groupAlertTransferHelper,
VisualStabilityManager visualStabilityManager,
DeviceProvisionedController deviceProvisionedController,
NavigationBarController navigationBarController,
Lazy<AssistManager> assistManagerLazy,
- NotificationListener notificationListener,
ConfigurationController configurationController,
NotificationShadeWindowController notificationShadeWindowController,
LockscreenLockIconController lockscreenLockIconController,
@@ -167,7 +158,6 @@
Optional<Recents> recentsOptional,
Provider<StatusBarComponent.Builder> statusBarComponentBuilder,
PluginManager pluginManager,
- RemoteInputUriController remoteInputUriController,
Optional<Divider> dividerOptional,
LightsOutNotifController lightsOutNotifController,
StatusBarNotificationActivityStarter.Builder
@@ -183,11 +173,10 @@
KeyguardDismissUtil keyguardDismissUtil,
ExtensionController extensionController,
UserInfoControllerImpl userInfoControllerImpl,
- NotificationRowBinderImpl notificationRowBinder,
DismissCallbackRegistry dismissCallbackRegistry) {
return new StatusBar(
context,
- featureFlags,
+ notificationsController,
lightBarController,
autoHideController,
keyguardUpdateMonitor,
@@ -199,13 +188,11 @@
headsUpManagerPhone,
dynamicPrivacyController,
bypassHeadsUpNotifier,
- newNotifPipeline,
falsingManager,
broadcastDispatcher,
remoteInputQuickSettingsDisabler,
notificationGutsManager,
notificationLogger,
- notificationEntryManager,
notificationInterruptionStateProvider,
notificationViewHierarchyManager,
keyguardViewMediator,
@@ -226,12 +213,10 @@
vibratorHelper,
bubbleController,
groupManager,
- groupAlertTransferHelper,
visualStabilityManager,
deviceProvisionedController,
navigationBarController,
assistManagerLazy,
- notificationListener,
configurationController,
notificationShadeWindowController,
lockscreenLockIconController,
@@ -249,7 +234,6 @@
recentsOptional,
statusBarComponentBuilder,
pluginManager,
- remoteInputUriController,
dividerOptional,
lightsOutNotifController,
statusBarNotificationActivityStarterBuilder,
@@ -264,7 +248,6 @@
keyguardDismissUtil,
extensionController,
userInfoControllerImpl,
- notificationRowBinder,
dismissCallbackRegistry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
index 1336b2d..2485513 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenter.java
@@ -141,7 +141,6 @@
ActivityLaunchAnimator activityLaunchAnimator,
DynamicPrivacyController dynamicPrivacyController,
NotificationAlertingManager notificationAlertingManager,
- NotificationRowBinderImpl notificationRowBinder,
KeyguardStateController keyguardStateController,
KeyguardIndicationController keyguardIndicationController,
StatusBar statusBar,
@@ -216,8 +215,6 @@
mEntryManager.addNotificationLifetimeExtender(mGutsManager);
mEntryManager.addNotificationLifetimeExtenders(
remoteInputManager.getLifetimeExtenders());
- notificationRowBinder.setUpWithPresenter(this, notifListContainer, mHeadsUpManager,
- this);
mNotificationInterruptionStateProvider.setUpWithPresenter(
this, mHeadsUpManager, this::canHeadsUp);
mLockscreenUserManager.setUpWithPresenter(this);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
index 795cbb9..7e4ba92 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardUpdateMonitorTest.java
@@ -437,14 +437,14 @@
}
@Test
- public void testIgnoresAuth_whenLockout() {
+ public void testTriesToAuthenticate_whenLockout() {
mKeyguardUpdateMonitor.dispatchStartedWakingUp();
mTestableLooper.processAllMessages();
when(mStrongAuthTracker.getStrongAuthForUser(anyInt())).thenReturn(
KeyguardUpdateMonitor.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT);
mKeyguardUpdateMonitor.onKeyguardVisibilityChanged(true);
- verify(mFaceManager, never()).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
+ verify(mFaceManager).authenticate(any(), any(), anyInt(), any(), any(), anyInt());
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
index 5cfb4b3..333b4a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/bubbles/BubbleControllerTest.java
@@ -274,7 +274,7 @@
@Test
public void testRemoveBubble_withDismissedNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -317,7 +317,7 @@
assertFalse(mBubbleController.isStackExpanded());
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -347,8 +347,8 @@
@Test
public void testCollapseAfterChangingExpandedBubble() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
- mEntryListener.onNotificationAdded(mRow2.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
@@ -390,7 +390,7 @@
@Test
public void testExpansionRemovesShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -416,7 +416,7 @@
@Test
public void testUpdateWhileExpanded_DoesntChangeShowInShadeAndDot() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// We should have bubbles & their notifs should not be suppressed
@@ -452,8 +452,8 @@
@Test
public void testRemoveLastExpandedCollapses() {
// Mark it as a bubble and add it explicitly
- mEntryListener.onNotificationAdded(mRow.getEntry());
- mEntryListener.onNotificationAdded(mRow2.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow2.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
mBubbleController.updateBubble(mRow2.getEntry());
verify(mBubbleStateChangeListener).onHasBubblesChanged(true);
@@ -496,7 +496,7 @@
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, false /* enableFlag */);
// Add the auto expand bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Expansion shouldn't change
@@ -514,7 +514,7 @@
Notification.BubbleMetadata.FLAG_AUTO_EXPAND_BUBBLE, true /* enableFlag */);
// Add the auto expand bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Expansion should change
@@ -532,7 +532,7 @@
Notification.BubbleMetadata.FLAG_SUPPRESS_NOTIFICATION, true /* enableFlag */);
// Add the suppress notif bubble
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Notif should be suppressed because we were foreground
@@ -576,7 +576,7 @@
public void testExpandStackAndSelectBubble_removedFirst() {
final String key = mRow.getEntry().getKey();
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
// Simulate notification cancellation.
@@ -588,7 +588,7 @@
@Test
public void testMarkNewNotificationAsShowInShade() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
mRow.getEntry()));
@@ -598,7 +598,7 @@
@Test
public void testAddNotif_notBubble() {
- mEntryListener.onNotificationAdded(mNonBubbleNotifRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mNonBubbleNotifRow.getEntry());
mEntryListener.onPreEntryUpdated(mNonBubbleNotifRow.getEntry());
verify(mBubbleStateChangeListener, never()).onHasBubblesChanged(anyBoolean());
@@ -643,7 +643,7 @@
@Test
public void testRemoveBubble_succeeds_appCancel() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -658,7 +658,7 @@
@Test
public void removeBubble_fails_clearAll() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -681,7 +681,7 @@
@Test
public void removeBubble_fails_userDismissNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -704,7 +704,7 @@
@Test
public void removeBubble_succeeds_userDismissBubble_userDimissNotif() {
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
mBubbleController.updateBubble(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
@@ -730,7 +730,7 @@
mock(BubbleController.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
@@ -753,7 +753,7 @@
mock(BubbleController.NotificationSuppressionChangedListener.class);
mBubbleData.setSuppressionChangedListener(listener);
- mEntryListener.onNotificationAdded(mRow.getEntry());
+ mEntryListener.onPendingEntryAdded(mRow.getEntry());
assertTrue(mBubbleController.hasBubbles());
assertFalse(mBubbleController.isBubbleNotificationSuppressedFromShade(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
index 7c8c7c8..89c1636 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsBindingControllerImplTest.kt
@@ -19,6 +19,7 @@
import android.content.ComponentName
import android.content.Context
import android.os.Binder
+import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.DeviceTypes
import android.testing.AndroidTestingRunner
@@ -38,6 +39,7 @@
import org.mockito.Mockito.`when`
import org.mockito.Mockito.mock
import org.mockito.Mockito.never
+import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
import org.mockito.MockitoAnnotations
@@ -55,6 +57,9 @@
@Mock
private lateinit var mockControlsController: ControlsController
+ private val user = UserHandle.of(mContext.userId)
+ private val otherUser = UserHandle.of(user.identifier + 1)
+
private val executor = FakeExecutor(FakeSystemClock())
private lateinit var controller: ControlsBindingController
private val providers = TestableControlsBindingControllerImpl.providers
@@ -75,6 +80,11 @@
}
@Test
+ fun testStartOnUser() {
+ assertEquals(user.identifier, controller.currentUserId)
+ }
+
+ @Test
fun testBindAndLoad() {
val callback: (List<Control>) -> Unit = {}
controller.bindAndLoad(TEST_COMPONENT_NAME_1, callback)
@@ -93,7 +103,7 @@
assertEquals(setOf(TEST_COMPONENT_NAME_1, TEST_COMPONENT_NAME_2),
providers.map { it.componentName }.toSet())
providers.forEach {
- verify(it).bindPermanently()
+ verify(it).bindService()
}
}
@@ -145,6 +155,41 @@
verify(it).unsubscribe()
}
}
+
+ @Test
+ fun testCurrentUserId() {
+ controller.changeUser(otherUser)
+ assertEquals(otherUser.identifier, controller.currentUserId)
+ }
+
+ @Test
+ fun testChangeUsers_providersHaveCorrectUser() {
+ controller.bindServices(listOf(TEST_COMPONENT_NAME_1))
+ controller.changeUser(otherUser)
+ controller.bindServices(listOf(TEST_COMPONENT_NAME_2))
+
+ val provider1 = providers.first { it.componentName == TEST_COMPONENT_NAME_1 }
+ assertEquals(user, provider1.user)
+ val provider2 = providers.first { it.componentName == TEST_COMPONENT_NAME_2 }
+ assertEquals(otherUser, provider2.user)
+ }
+
+ @Test
+ fun testChangeUsers_providersUnbound() {
+ controller.bindServices(listOf(TEST_COMPONENT_NAME_1))
+ controller.changeUser(otherUser)
+
+ val provider1 = providers.first { it.componentName == TEST_COMPONENT_NAME_1 }
+ verify(provider1).unbindService()
+
+ controller.bindServices(listOf(TEST_COMPONENT_NAME_2))
+ controller.changeUser(user)
+
+ reset(provider1)
+ val provider2 = providers.first { it.componentName == TEST_COMPONENT_NAME_2 }
+ verify(provider2).unbindService()
+ verify(provider1, never()).unbindService()
+ }
}
class TestableControlsBindingControllerImpl(
@@ -157,13 +202,17 @@
val providers = mutableSetOf<ControlsProviderLifecycleManager>()
}
+ // Replaces the real provider with a mock and puts the mock in a visible set.
+ // The mock has the same componentName and user as the real one would have
override fun createProviderManager(component: ComponentName):
ControlsProviderLifecycleManager {
+ val realProvider = super.createProviderManager(component)
val provider = mock(ControlsProviderLifecycleManager::class.java)
val token = Binder()
- `when`(provider.componentName).thenReturn(component)
+ `when`(provider.componentName).thenReturn(realProvider.componentName)
`when`(provider.token).thenReturn(token)
+ `when`(provider.user).thenReturn(realProvider.user)
providers.add(provider)
return provider
}
-}
\ No newline at end of file
+}
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 be86a9c..897091f 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
@@ -17,7 +17,12 @@
package com.android.systemui.controls.controller
import android.app.PendingIntent
+import android.content.BroadcastReceiver
import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
+import android.content.Intent
+import android.os.UserHandle
import android.provider.Settings
import android.service.controls.Control
import android.service.controls.DeviceTypes
@@ -26,6 +31,8 @@
import androidx.test.filters.SmallTest
import com.android.systemui.DumpController
import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.controls.management.ControlsListingController
import com.android.systemui.controls.ControlStatus
import com.android.systemui.controls.ui.ControlsUiController
import com.android.systemui.util.concurrency.FakeExecutor
@@ -37,10 +44,11 @@
import org.junit.runner.RunWith
import org.mockito.ArgumentCaptor
import org.mockito.ArgumentMatchers
-import org.mockito.ArgumentMatchers.eq
import org.mockito.Captor
import org.mockito.Mock
+import org.mockito.Mockito
import org.mockito.Mockito.`when`
+import org.mockito.Mockito.mock
import org.mockito.Mockito.never
import org.mockito.Mockito.reset
import org.mockito.Mockito.verify
@@ -61,18 +69,25 @@
private lateinit var pendingIntent: PendingIntent
@Mock
private lateinit var persistenceWrapper: ControlsFavoritePersistenceWrapper
+ @Mock
+ private lateinit var broadcastDispatcher: BroadcastDispatcher
+ @Mock
+ private lateinit var listingController: ControlsListingController
@Captor
private lateinit var controlInfoListCaptor: ArgumentCaptor<List<ControlInfo>>
@Captor
private lateinit var controlLoadCallbackCaptor: ArgumentCaptor<(List<Control>) -> Unit>
+ @Captor
+ private lateinit var broadcastReceiverCaptor: ArgumentCaptor<BroadcastReceiver>
private lateinit var delayableExecutor: FakeExecutor
private lateinit var controller: ControlsController
companion object {
fun <T> capture(argumentCaptor: ArgumentCaptor<T>): T = argumentCaptor.capture()
- fun <T : Any> safeEq(value: T): T = eq(value) ?: value
+ fun <T> eq(value: T): T = Mockito.eq(value) ?: value
+ fun <T> any(): T = Mockito.any<T>()
private val TEST_COMPONENT = ComponentName("test.pkg", "test.class")
private const val TEST_CONTROL_ID = "control1"
@@ -89,24 +104,39 @@
TEST_COMPONENT_2, TEST_CONTROL_ID_2, TEST_CONTROL_TITLE_2, TEST_DEVICE_TYPE_2)
}
+ private val user = mContext.userId
+ private val otherUser = user + 1
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
Settings.Secure.putInt(mContext.contentResolver,
ControlsControllerImpl.CONTROLS_AVAILABLE, 1)
+ Settings.Secure.putIntForUser(mContext.contentResolver,
+ ControlsControllerImpl.CONTROLS_AVAILABLE, 1, otherUser)
delayableExecutor = FakeExecutor(FakeSystemClock())
+ val wrapper = object : ContextWrapper(mContext) {
+ override fun createContextAsUser(user: UserHandle, flags: Int): Context {
+ return baseContext
+ }
+ }
+
controller = ControlsControllerImpl(
- mContext,
+ wrapper,
delayableExecutor,
uiController,
bindingController,
+ listingController,
+ broadcastDispatcher,
Optional.of(persistenceWrapper),
dumpController
)
assertTrue(controller.available)
+ verify(broadcastDispatcher).registerReceiver(
+ capture(broadcastReceiverCaptor), any(), any(), eq(UserHandle.ALL))
}
private fun builderFromInfo(controlInfo: ControlInfo): Control.StatelessBuilder {
@@ -115,6 +145,11 @@
}
@Test
+ fun testStartOnUser() {
+ assertEquals(user, controller.currentUserId)
+ }
+
+ @Test
fun testStartWithoutFavorites() {
assertTrue(controller.getFavoriteControls().isEmpty())
}
@@ -127,6 +162,8 @@
delayableExecutor,
uiController,
bindingController,
+ listingController,
+ broadcastDispatcher,
Optional.of(persistenceWrapper),
dumpController
)
@@ -190,7 +227,7 @@
controller.loadForComponent(TEST_COMPONENT) {}
reset(persistenceWrapper)
- verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT),
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
capture(controlLoadCallbackCaptor))
controlLoadCallbackCaptor.value.invoke(listOf(control))
@@ -262,7 +299,7 @@
assertEquals(ControlStatus(control, false), controlStatus)
}
- verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT),
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
capture(controlLoadCallbackCaptor))
controlLoadCallbackCaptor.value.invoke(listOf(control))
@@ -287,7 +324,7 @@
assertEquals(ControlStatus(control2, false), controlStatus2)
}
- verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT),
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
capture(controlLoadCallbackCaptor))
controlLoadCallbackCaptor.value.invoke(listOf(control, control2))
@@ -309,7 +346,7 @@
assertTrue(controlStatus.removed)
}
- verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT),
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
capture(controlLoadCallbackCaptor))
controlLoadCallbackCaptor.value.invoke(emptyList())
@@ -325,7 +362,7 @@
controller.loadForComponent(TEST_COMPONENT) {}
- verify(bindingController).bindAndLoad(safeEq(TEST_COMPONENT),
+ verify(bindingController).bindAndLoad(eq(TEST_COMPONENT),
capture(controlLoadCallbackCaptor))
controlLoadCallbackCaptor.value.invoke(listOf(control))
@@ -358,4 +395,26 @@
controller.clearFavorites()
assertTrue(controller.getFavoriteControls().isEmpty())
}
-}
+
+ @Test
+ fun testSwitchUsers() {
+ controller.changeFavoriteStatus(TEST_CONTROL_INFO, true)
+
+ reset(persistenceWrapper)
+ val intent = Intent(Intent.ACTION_USER_SWITCHED).apply {
+ putExtra(Intent.EXTRA_USER_HANDLE, otherUser)
+ }
+ val pendingResult = mock(BroadcastReceiver.PendingResult::class.java)
+ `when`(pendingResult.sendingUserId).thenReturn(otherUser)
+ broadcastReceiverCaptor.value.pendingResult = pendingResult
+
+ broadcastReceiverCaptor.value.onReceive(mContext, intent)
+
+ verify(persistenceWrapper).changeFile(any())
+ verify(persistenceWrapper).readFavorites()
+ verify(bindingController).changeUser(UserHandle.of(otherUser))
+ verify(listingController).changeUser(UserHandle.of(otherUser))
+ assertTrue(controller.getFavoriteControls().isEmpty())
+ assertEquals(otherUser, controller.currentUserId)
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
index 4fc1cca..40566dc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/controller/ControlsProviderLifecycleManagerTest.kt
@@ -17,6 +17,7 @@
package com.android.systemui.controls.controller
import android.content.ComponentName
+import android.os.UserHandle
import android.service.controls.Control
import android.service.controls.IControlsActionCallback
import android.service.controls.IControlsLoadCallback
@@ -86,6 +87,7 @@
loadCallback,
actionCallback,
subscriber,
+ UserHandle.of(0),
componentName
)
}
@@ -97,13 +99,13 @@
@Test
fun testBindService() {
- manager.bindPermanently()
+ manager.bindService()
assertTrue(mContext.isBound(componentName))
}
@Test
fun testUnbindService() {
- manager.bindPermanently()
+ manager.bindService()
manager.unbindService()
assertFalse(mContext.isBound(componentName))
}
@@ -123,7 +125,7 @@
fun testMaybeUnbind_bindingAndCallback() {
manager.maybeBindAndLoad {}
- manager.maybeUnbindAndRemoveCallback()
+ manager.unbindService()
assertFalse(mContext.isBound(componentName))
assertNull(manager.lastLoadCallback)
}
@@ -148,4 +150,4 @@
eq(actionCallback))
assertEquals(action, wrapperCaptor.getValue().getWrappedAction())
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
index f09aab9..85e937e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/controls/management/ControlsListingControllerImplTest.kt
@@ -17,12 +17,15 @@
package com.android.systemui.controls.management
import android.content.ComponentName
+import android.content.Context
+import android.content.ContextWrapper
import android.content.pm.ServiceInfo
+import android.os.UserHandle
import android.testing.AndroidTestingRunner
import androidx.test.filters.SmallTest
import com.android.settingslib.applications.ServiceListing
-import com.android.settingslib.widget.CandidateInfo
import com.android.systemui.SysuiTestCase
+import com.android.systemui.controls.ControlsServiceInfo
import com.android.systemui.util.concurrency.FakeExecutor
import com.android.systemui.util.time.FakeSystemClock
import org.junit.After
@@ -69,13 +72,22 @@
private var serviceListingCallbackCaptor =
ArgumentCaptor.forClass(ServiceListing.Callback::class.java)
+ private val user = mContext.userId
+ private val otherUser = user + 1
+
@Before
fun setUp() {
MockitoAnnotations.initMocks(this)
`when`(serviceInfo.componentName).thenReturn(componentName)
- controller = ControlsListingControllerImpl(mContext, executor, mockSL)
+ val wrapper = object : ContextWrapper(mContext) {
+ override fun createContextAsUser(user: UserHandle, flags: Int): Context {
+ return baseContext
+ }
+ }
+
+ controller = ControlsListingControllerImpl(wrapper, executor, { mockSL })
verify(mockSL).addCallback(capture(serviceListingCallbackCaptor))
}
@@ -86,6 +98,11 @@
}
@Test
+ fun testStartsOnUser() {
+ assertEquals(user, controller.currentUserId)
+ }
+
+ @Test
fun testNoServices_notListening() {
assertTrue(controller.getCurrentServices().isEmpty())
}
@@ -167,8 +184,9 @@
controller.addCallback(mockCallbackOther)
@Suppress("unchecked_cast")
- val captor: ArgumentCaptor<List<CandidateInfo>> =
- ArgumentCaptor.forClass(List::class.java) as ArgumentCaptor<List<CandidateInfo>>
+ val captor: ArgumentCaptor<List<ControlsServiceInfo>> =
+ ArgumentCaptor.forClass(List::class.java)
+ as ArgumentCaptor<List<ControlsServiceInfo>>
executor.runAllReady()
reset(mockCallback)
@@ -185,4 +203,11 @@
assertEquals(1, captor.value.size)
assertEquals(componentName.flattenToString(), captor.value[0].key)
}
+
+ @Test
+ fun testChangeUser() {
+ controller.changeUser(UserHandle.of(otherUser))
+ executor.runAllReady()
+ assertEquals(otherUser, controller.currentUserId)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
index 752e145..00d333fb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeConfigurationUtil.java
@@ -53,6 +53,7 @@
when(config.pickupGestureEnabled(anyInt())).thenReturn(false);
when(config.pulseOnNotificationEnabled(anyInt())).thenReturn(true);
when(config.alwaysOnEnabled(anyInt())).thenReturn(false);
+ when(config.dozeSuppressed(anyInt())).thenReturn(false);
when(config.enabled(anyInt())).thenReturn(true);
when(config.getWakeLockScreenDebounce()).thenReturn(0L);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
index f4cf314..63cbca9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeMachineTest.java
@@ -139,6 +139,65 @@
}
@Test
+ public void testInitialize_dozeSuppressed_alwaysOnDisabled_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
+ public void testInitialize_dozeSuppressed_alwaysOnEnabled_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
+ public void testInitialize_dozeSuppressed_afterDocked_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
+ public void testInitialize_dozeSuppressed_alwaysOnDisabled_afterDockPaused_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
+ when(mDockManager.isDocked()).thenReturn(true);
+ when(mDockManager.isHidden()).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
+ public void testInitialize_dozeSuppressed_alwaysOnEnabled_afterDockPaused_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+ when(mDockManager.isHidden()).thenReturn(true);
+
+ mMachine.requestState(INITIALIZED);
+
+ verify(mPartMock).transitionTo(INITIALIZED, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testPulseDone_goesToDoze() {
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(false);
mMachine.requestState(INITIALIZED);
@@ -165,6 +224,20 @@
}
@Test
+ public void testPulseDone_dozeSuppressed_goesToSuppressed() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+
+ mMachine.requestState(DOZE_PULSE_DONE);
+
+ verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testPulseDone_afterDocked_goesToDockedAoD() {
when(mDockManager.isDocked()).thenReturn(true);
mMachine.requestState(INITIALIZED);
@@ -178,6 +251,20 @@
}
@Test
+ public void testPulseDone_dozeSuppressed_afterDocked_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+
+ mMachine.requestState(DOZE_PULSE_DONE);
+
+ verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testPulseDone_afterDockPaused_goesToDoze() {
when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
when(mDockManager.isDocked()).thenReturn(true);
@@ -193,6 +280,22 @@
}
@Test
+ public void testPulseDone_dozeSuppressed_afterDockPaused_goesToDoze() {
+ when(mConfigMock.dozeSuppressed(anyInt())).thenReturn(true);
+ when(mConfigMock.alwaysOnEnabled(anyInt())).thenReturn(true);
+ when(mDockManager.isDocked()).thenReturn(true);
+ when(mDockManager.isHidden()).thenReturn(true);
+ mMachine.requestState(INITIALIZED);
+ mMachine.requestPulse(DozeLog.PULSE_REASON_NOTIFICATION);
+ mMachine.requestState(DOZE_PULSING);
+
+ mMachine.requestState(DOZE_PULSE_DONE);
+
+ verify(mPartMock).transitionTo(DOZE_PULSE_DONE, DOZE);
+ assertEquals(DOZE, mMachine.getState());
+ }
+
+ @Test
public void testFinished_staysFinished() {
mMachine.requestState(INITIALIZED);
mMachine.requestState(FINISH);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java
new file mode 100644
index 0000000..5bdca76
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/doze/DozeSuppressedHandlerTest.java
@@ -0,0 +1,77 @@
+/*
+ * 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.doze;
+
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+
+import android.hardware.display.AmbientDisplayConfiguration;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.doze.DozeSuppressedHandler.DozeSuppressedSettingObserver;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class DozeSuppressedHandlerTest extends SysuiTestCase {
+ @Mock private DozeMachine mMachine;
+ @Mock private DozeSuppressedSettingObserver mObserver;
+ private AmbientDisplayConfiguration mConfig;
+ private DozeSuppressedHandler mSuppressedHandler;
+
+ @Before
+ public void setUp() throws Exception {
+ MockitoAnnotations.initMocks(this);
+ mConfig = DozeConfigurationUtil.createMockConfig();
+ mSuppressedHandler = new DozeSuppressedHandler(mContext, mConfig, mMachine, mObserver);
+ }
+
+ @Test
+ public void transitionTo_initialized_registersObserver() throws Exception {
+ mSuppressedHandler.transitionTo(DozeMachine.State.UNINITIALIZED,
+ DozeMachine.State.INITIALIZED);
+
+ verify(mObserver).register();
+ }
+
+ @Test
+ public void transitionTo_finish_unregistersObserver() throws Exception {
+ mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED,
+ DozeMachine.State.FINISH);
+
+ verify(mObserver).unregister();
+ }
+
+ @Test
+ public void transitionTo_doze_doesNothing() throws Exception {
+ mSuppressedHandler.transitionTo(DozeMachine.State.INITIALIZED,
+ DozeMachine.State.DOZE);
+
+ verify(mObserver, never()).register();
+ verify(mObserver, never()).unregister();
+ }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
index 47933ba..e58a3a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSSecurityFooterTest.java
@@ -16,8 +16,11 @@
import static junit.framework.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.Context;
@@ -447,6 +450,21 @@
view.findViewById(R.id.vpn_subtitle).getVisibility());
}
+ @Test
+ public void testNoClickWhenGone() {
+ QSTileHost mockHost = mock(QSTileHost.class);
+ mFooter.setHostEnvironment(mockHost);
+ mFooter.refreshState();
+
+ TestableLooper.get(this).processAllMessages();
+
+ assertFalse(mFooter.hasFooter());
+ mFooter.onClick(mFooter.getView());
+
+ // Proxy for dialog being created
+ verify(mockHost, never()).collapsePanels();
+ }
+
private CharSequence addLink(CharSequence description) {
final SpannableStringBuilder message = new SpannableStringBuilder();
message.append(description);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
index 9a7e97b..b652980 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/NotifCollectionTest.java
@@ -139,9 +139,10 @@
.setRank(4747));
// THEN the listener is notified
- verify(mCollectionListener).onEntryAdded(mEntryCaptor.capture());
-
+ verify(mCollectionListener).onEntryInit(mEntryCaptor.capture());
NotificationEntry entry = mEntryCaptor.getValue();
+
+ verify(mCollectionListener).onEntryAdded(entry);
assertEquals(notif1.key, entry.getKey());
assertEquals(notif1.sbn, entry.getSbn());
assertEquals(notif1.ranking, entry.getRanking());
@@ -236,6 +237,7 @@
// THEN the listener is notified
verify(mCollectionListener).onEntryRemoved(entry, REASON_APP_CANCEL, false);
+ verify(mCollectionListener).onEntryCleanUp(entry);
assertEquals(notif.sbn, entry.getSbn());
assertEquals(notif.ranking, entry.getRanking());
}
@@ -606,6 +608,10 @@
private final Map<String, NotificationEntry> mLastSeenEntries = new ArrayMap<>();
@Override
+ public void onEntryInit(NotificationEntry entry) {
+ }
+
+ @Override
public void onEntryAdded(NotificationEntry entry) {
mLastSeenEntries.put(entry.getKey(), entry);
}
@@ -618,6 +624,10 @@
public void onEntryRemoved(NotificationEntry entry, int reason, boolean removedByUser) {
}
+ @Override
+ public void onEntryCleanUp(NotificationEntry entry) {
+ }
+
public NotificationEntry getEntry(String key) {
if (!mLastSeenEntries.containsKey(key)) {
throw new RuntimeException("Key not found: " + key);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
index dd896be..b9d2d22 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.java
@@ -54,7 +54,6 @@
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -113,10 +112,9 @@
notificationShadeWindowView, mock(NotificationListContainerViewGroup.class),
mock(DozeScrimController.class), mock(ScrimController.class),
mock(ActivityLaunchAnimator.class), mock(DynamicPrivacyController.class),
- mock(NotificationAlertingManager.class),
- mock(NotificationRowBinderImpl.class), mock(KeyguardStateController.class),
- mock(KeyguardIndicationController.class),
- mStatusBar, mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
+ mock(NotificationAlertingManager.class), mock(KeyguardStateController.class),
+ mock(KeyguardIndicationController.class), mStatusBar,
+ mock(ShadeControllerImpl.class), mCommandQueue, mInitController);
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
index e90e398..db17a6e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarTest.java
@@ -95,7 +95,6 @@
import com.android.systemui.shared.plugins.PluginManager;
import com.android.systemui.stackdivider.Divider;
import com.android.systemui.statusbar.CommandQueue;
-import com.android.systemui.statusbar.FeatureFlags;
import com.android.systemui.statusbar.KeyguardIndicationController;
import com.android.systemui.statusbar.NavigationBarController;
import com.android.systemui.statusbar.NotificationListener;
@@ -120,8 +119,7 @@
import com.android.systemui.statusbar.notification.VisualStabilityManager;
import com.android.systemui.statusbar.notification.collection.NotificationEntry;
import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
-import com.android.systemui.statusbar.notification.collection.inflation.NotificationRowBinderImpl;
-import com.android.systemui.statusbar.notification.collection.init.NotifPipelineInitializer;
+import com.android.systemui.statusbar.notification.init.NotificationsController;
import com.android.systemui.statusbar.notification.logging.NotificationLogger;
import com.android.systemui.statusbar.notification.row.NotificationGutsManager;
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout;
@@ -133,10 +131,8 @@
import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.NetworkController;
import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
-import com.android.systemui.statusbar.policy.RemoteInputUriController;
import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
import com.android.systemui.util.concurrency.FakeExecutor;
import com.android.systemui.util.time.FakeSystemClock;
import com.android.systemui.volume.VolumeComponent;
@@ -149,7 +145,6 @@
import java.io.ByteArrayOutputStream;
import java.io.PrintWriter;
-import java.util.ArrayList;
import java.util.Optional;
import javax.inject.Provider;
@@ -166,7 +161,7 @@
private PowerManager mPowerManager;
private TestableNotificationInterruptionStateProvider mNotificationInterruptionStateProvider;
- @Mock private FeatureFlags mFeatureFlags;
+ @Mock private NotificationsController mNotificationsController;
@Mock private LightBarController mLightBarController;
@Mock private StatusBarIconController mStatusBarIconController;
@Mock private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@@ -180,7 +175,6 @@
@Mock private IDreamManager mDreamManager;
@Mock private ScrimController mScrimController;
@Mock private DozeScrimController mDozeScrimController;
- @Mock private ArrayList<NotificationEntry> mNotificationList;
@Mock private Lazy<BiometricUnlockController> mBiometricUnlockControllerLazy;
@Mock private BiometricUnlockController mBiometricUnlockController;
@Mock private NotificationInterruptionStateProvider.HeadsUpSuppressor mHeadsUpSuppressor;
@@ -190,7 +184,6 @@
@Mock private NotificationLockscreenUserManager mLockscreenUserManager;
@Mock private NotificationRemoteInputManager mRemoteInputManager;
@Mock private RemoteInputController mRemoteInputController;
- @Mock private RemoteInputUriController mRemoteInputUriController;
@Mock private StatusBarStateControllerImpl mStatusBarStateController;
@Mock private BatteryController mBatteryController;
@Mock private DeviceProvisionedController mDeviceProvisionedController;
@@ -214,8 +207,6 @@
@Mock private NotificationWakeUpCoordinator mNotificationWakeUpCoordinator;
@Mock private KeyguardBypassController mKeyguardBypassController;
@Mock private DynamicPrivacyController mDynamicPrivacyController;
- @Mock private NotifPipelineInitializer mNewNotifPipeline;
- @Mock private ZenModeController mZenModeController;
@Mock private AutoHideController mAutoHideController;
@Mock private NotificationViewHierarchyManager mNotificationViewHierarchyManager;
@Mock private UserSwitcherController mUserSwitcherController;
@@ -223,7 +214,6 @@
@Mock private VibratorHelper mVibratorHelper;
@Mock private BubbleController mBubbleController;
@Mock private NotificationGroupManager mGroupManager;
- @Mock private NotificationGroupAlertTransferHelper mGroupAlertTransferHelper;
@Mock private NotificationShadeWindowController mNotificationShadeWindowController;
@Mock private NotificationIconAreaController mNotificationIconAreaController;
@Mock private NotificationShadeWindowViewController mNotificationShadeWindowViewController;
@@ -247,7 +237,6 @@
@Mock private ViewMediatorCallback mViewMediatorCallback;
@Mock private DismissCallbackRegistry mDismissCallbackRegistry;
@Mock private ScreenPinningRequest mScreenPinningRequest;
- @Mock private NotificationEntryManager mEntryManager;
@Mock private LockscreenLockIconController mLockscreenLockIconController;
@Mock private StatusBarNotificationActivityStarter.Builder
mStatusBarNotificationActivityStarterBuilder;
@@ -256,7 +245,6 @@
@Mock private KeyguardDismissUtil mKeyguardDismissUtil;
@Mock private ExtensionController mExtensionController;
@Mock private UserInfoControllerImpl mUserInfoControllerImpl;
- @Mock private NotificationRowBinderImpl mNotificationRowBinder;
private ShadeController mShadeController;
private FakeExecutor mUiBgExecutor = new FakeExecutor(new FakeSystemClock());
private InitController mInitController = new InitController();
@@ -280,7 +268,7 @@
mMetricsLogger = new FakeMetricsLogger();
NotificationLogger notificationLogger = new NotificationLogger(mNotificationListener,
- mUiBgExecutor, mEntryManager, mStatusBarStateController,
+ mUiBgExecutor, mock(NotificationEntryManager.class), mStatusBarStateController,
mExpansionStateLogger);
notificationLogger.setVisibilityReporter(mock(Runnable.class));
@@ -334,7 +322,7 @@
mStatusBar = new StatusBar(
mContext,
- mFeatureFlags,
+ mNotificationsController,
mLightBarController,
mAutoHideController,
mKeyguardUpdateMonitor,
@@ -346,7 +334,6 @@
mHeadsUpManager,
mDynamicPrivacyController,
mBypassHeadsUpNotifier,
- () -> mNewNotifPipeline,
new FalsingManagerFake(),
mBroadcastDispatcher,
new RemoteInputQuickSettingsDisabler(
@@ -356,7 +343,6 @@
),
mNotificationGutsManager,
notificationLogger,
- mEntryManager,
mNotificationInterruptionStateProvider,
mNotificationViewHierarchyManager,
mKeyguardViewMediator,
@@ -377,12 +363,10 @@
mVibratorHelper,
mBubbleController,
mGroupManager,
- mGroupAlertTransferHelper,
mVisualStabilityManager,
mDeviceProvisionedController,
mNavigationBarController,
() -> mAssistManager,
- mNotificationListener,
configurationController,
mNotificationShadeWindowController,
mLockscreenLockIconController,
@@ -399,7 +383,6 @@
Optional.of(mRecents),
mStatusBarComponentBuilderProvider,
mPluginManager,
- mRemoteInputUriController,
Optional.of(mDivider),
mLightsOutNotifController,
mStatusBarNotificationActivityStarterBuilder,
@@ -414,7 +397,6 @@
mKeyguardDismissUtil,
mExtensionController,
mUserInfoControllerImpl,
- mNotificationRowBinder,
mDismissCallbackRegistry);
when(mNotificationShadeWindowView.findViewById(R.id.lock_icon_container)).thenReturn(
@@ -675,7 +657,7 @@
public void testPanelOpenForHeadsUp() {
when(mDeviceProvisionedController.isDeviceProvisioned()).thenReturn(true);
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(true);
- when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
+ when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(true);
mStatusBar.setBarStateForTest(StatusBarState.SHADE);
@@ -693,7 +675,7 @@
@Test
public void testPanelOpenAndClear() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
+ when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
mStatusBar.setBarStateForTest(StatusBarState.SHADE);
@@ -712,7 +694,7 @@
@Test
public void testPanelOpenAndNoClear() {
when(mHeadsUpManager.hasPinnedHeadsUp()).thenReturn(false);
- when(mEntryManager.getActiveNotificationsCount()).thenReturn(5);
+ when(mNotificationsController.getActiveNotificationsCount()).thenReturn(5);
when(mNotificationPresenter.isPresenterFullyCollapsed()).thenReturn(false);
mStatusBar.setBarStateForTest(StatusBarState.KEYGUARD);
diff --git a/packages/Tethering/common/TetheringLib/jarjar-rules.txt b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
index 35e0f88..1403bba 100644
--- a/packages/Tethering/common/TetheringLib/jarjar-rules.txt
+++ b/packages/Tethering/common/TetheringLib/jarjar-rules.txt
@@ -1 +1,2 @@
rule android.annotation.** com.android.networkstack.tethering.annotation.@1
+rule com.android.internal.annotations.** com.android.networkstack.tethering.annotation.@1
\ No newline at end of file
diff --git a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
index 37ce1d57..53a358f 100644
--- a/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
+++ b/packages/Tethering/common/TetheringLib/src/android/net/TetheringManager.java
@@ -30,6 +30,9 @@
import android.util.ArrayMap;
import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+
+import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -37,6 +40,7 @@
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Executor;
+import java.util.function.Supplier;
/**
* This class provides the APIs to control the tethering service.
@@ -50,17 +54,23 @@
public class TetheringManager {
private static final String TAG = TetheringManager.class.getSimpleName();
private static final int DEFAULT_TIMEOUT_MS = 60_000;
+ private static final long CONNECTOR_POLL_INTERVAL_MILLIS = 200L;
- private static TetheringManager sInstance;
+ @GuardedBy("mConnectorWaitQueue")
+ @Nullable
+ private ITetheringConnector mConnector;
+ @GuardedBy("mConnectorWaitQueue")
+ @NonNull
+ private final List<ConnectorConsumer> mConnectorWaitQueue = new ArrayList<>();
+ private final Supplier<IBinder> mConnectorSupplier;
- private final ITetheringConnector mConnector;
private final TetheringCallbackInternal mCallback;
private final Context mContext;
private final ArrayMap<TetheringEventCallback, ITetheringEventCallback>
mTetheringEventCallbacks = new ArrayMap<>();
- private TetheringConfigurationParcel mTetheringConfiguration;
- private TetherStatesParcel mTetherStatesParcel;
+ private volatile TetheringConfigurationParcel mTetheringConfiguration;
+ private volatile TetherStatesParcel mTetherStatesParcel;
/**
* Broadcast Action: A tetherable connection has come or gone.
@@ -162,29 +172,139 @@
/**
* Create a TetheringManager object for interacting with the tethering service.
*
+ * @param context Context for the manager.
+ * @param connectorSupplier Supplier for the manager connector; may return null while the
+ * service is not connected.
* {@hide}
*/
- public TetheringManager(@NonNull final Context context, @NonNull final IBinder service) {
+ public TetheringManager(@NonNull final Context context,
+ @NonNull Supplier<IBinder> connectorSupplier) {
mContext = context;
- mConnector = ITetheringConnector.Stub.asInterface(service);
mCallback = new TetheringCallbackInternal();
+ mConnectorSupplier = connectorSupplier;
final String pkgName = mContext.getOpPackageName();
+
+ final IBinder connector = mConnectorSupplier.get();
+ // If the connector is available on start, do not start a polling thread. This introduces
+ // differences in the thread that sends the oneway binder calls to the service between the
+ // first few seconds after boot and later, but it avoids always having differences between
+ // the first usage of TetheringManager from a process and subsequent usages (so the
+ // difference is only on boot). On boot binder calls may be queued until the service comes
+ // up and be sent from a worker thread; later, they are always sent from the caller thread.
+ // Considering that it's just oneway binder calls, and ordering is preserved, this seems
+ // better than inconsistent behavior persisting after boot.
+ if (connector != null) {
+ mConnector = ITetheringConnector.Stub.asInterface(connector);
+ } else {
+ startPollingForConnector();
+ }
+
Log.i(TAG, "registerTetheringEventCallback:" + pkgName);
+ getConnector(c -> c.registerTetheringEventCallback(mCallback, pkgName));
+ }
+
+ private void startPollingForConnector() {
+ new Thread(() -> {
+ while (true) {
+ try {
+ Thread.sleep(200);
+ } catch (InterruptedException e) {
+ // Not much to do here, the system needs to wait for the connector
+ }
+
+ final IBinder connector = mConnectorSupplier.get();
+ if (connector != null) {
+ onTetheringConnected(ITetheringConnector.Stub.asInterface(connector));
+ return;
+ }
+ }
+ }).start();
+ }
+
+ private interface ConnectorConsumer {
+ void onConnectorAvailable(ITetheringConnector connector) throws RemoteException;
+ }
+
+ private void onTetheringConnected(ITetheringConnector connector) {
+ // Process the connector wait queue in order, including any items that are added
+ // while processing.
+ //
+ // 1. Copy the queue to a local variable under lock.
+ // 2. Drain the local queue with the lock released (otherwise, enqueuing future commands
+ // would block on the lock).
+ // 3. Acquire the lock again. If any new tasks were queued during step 2, goto 1.
+ // If not, set mConnector to non-null so future tasks are run immediately, not queued.
+ //
+ // For this to work, all calls to the tethering service must use getConnector(), which
+ // ensures that tasks are added to the queue with the lock held.
+ //
+ // Once mConnector is set to non-null, it will never be null again. If the network stack
+ // process crashes, no recovery is possible.
+ // TODO: evaluate whether it is possible to recover from network stack process crashes
+ // (though in most cases the system will have crashed when the network stack process
+ // crashes).
+ do {
+ final List<ConnectorConsumer> localWaitQueue;
+ synchronized (mConnectorWaitQueue) {
+ localWaitQueue = new ArrayList<>(mConnectorWaitQueue);
+ mConnectorWaitQueue.clear();
+ }
+
+ // Allow more tasks to be added at the end without blocking while draining the queue.
+ for (ConnectorConsumer task : localWaitQueue) {
+ try {
+ task.onConnectorAvailable(connector);
+ } catch (RemoteException e) {
+ // Most likely the network stack process crashed, which is likely to crash the
+ // system. Keep processing other requests but report the error loudly.
+ Log.wtf(TAG, "Error processing request for the tethering connector", e);
+ }
+ }
+
+ synchronized (mConnectorWaitQueue) {
+ if (mConnectorWaitQueue.size() == 0) {
+ mConnector = connector;
+ return;
+ }
+ }
+ } while (true);
+ }
+
+ /**
+ * Asynchronously get the ITetheringConnector to execute some operation.
+ *
+ * <p>If the connector is already available, the operation will be executed on the caller's
+ * thread. Otherwise it will be queued and executed on a worker thread. The operation should be
+ * limited to performing oneway binder calls to minimize differences due to threading.
+ */
+ private void getConnector(ConnectorConsumer consumer) {
+ final ITetheringConnector connector;
+ synchronized (mConnectorWaitQueue) {
+ connector = mConnector;
+ if (connector == null) {
+ mConnectorWaitQueue.add(consumer);
+ return;
+ }
+ }
+
try {
- mConnector.registerTetheringEventCallback(mCallback, pkgName);
+ consumer.onConnectorAvailable(connector);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
}
private interface RequestHelper {
- void runRequest(IIntResultListener listener);
+ void runRequest(ITetheringConnector connector, IIntResultListener listener);
}
+ // Used to dispatch legacy ConnectivityManager methods that expect tethering to be able to
+ // return results and perform operations synchronously.
+ // TODO: remove once there are no callers of these legacy methods.
private class RequestDispatcher {
private final ConditionVariable mWaiting;
- public int mRemoteResult;
+ public volatile int mRemoteResult;
private final IIntResultListener mListener = new IIntResultListener.Stub() {
@Override
@@ -199,7 +319,7 @@
}
int waitForResult(final RequestHelper request) {
- request.runRequest(mListener);
+ getConnector(c -> request.runRequest(c, mListener));
if (!mWaiting.block(DEFAULT_TIMEOUT_MS)) {
throw new IllegalStateException("Callback timeout");
}
@@ -222,7 +342,7 @@
}
private class TetheringCallbackInternal extends ITetheringEventCallback.Stub {
- private int mError = TETHER_ERROR_NO_ERROR;
+ private volatile int mError = TETHER_ERROR_NO_ERROR;
private final ConditionVariable mWaitForCallback = new ConditionVariable();
@Override
@@ -280,9 +400,9 @@
Log.i(TAG, "tether caller:" + callerPkg);
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.tether(iface, callerPkg, listener);
+ connector.tether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -304,9 +424,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.untether(iface, callerPkg, listener);
+ connector.untether(iface, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -330,9 +450,9 @@
final RequestDispatcher dispatcher = new RequestDispatcher();
- return dispatcher.waitForResult(listener -> {
+ return dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.setUsbTethering(enable, callerPkg, listener);
+ connector.setUsbTethering(enable, callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -467,11 +587,7 @@
});
}
};
- try {
- mConnector.startTethering(request.getParcel(), callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.startTethering(request.getParcel(), callerPkg, listener));
}
/**
@@ -509,15 +625,15 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
-
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopTethering(type, callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopTethering(type, callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: provide an API to obtain result
+ // This has never been possible as stopTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
}
/**
@@ -591,12 +707,8 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "getLatestTetheringEntitlementResult caller:" + callerPkg);
- try {
- mConnector.requestLatestTetheringEntitlementResult(type, receiver, showEntitlementUi,
- callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.requestLatestTetheringEntitlementResult(
+ type, receiver, showEntitlementUi, callerPkg));
}
/**
@@ -832,11 +944,7 @@
});
}
};
- try {
- mConnector.registerTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+ getConnector(c -> c.registerTetheringEventCallback(remoteCallback, callerPkg));
mTetheringEventCallbacks.put(callback, remoteCallback);
}
}
@@ -860,11 +968,8 @@
if (remoteCallback == null) {
throw new IllegalArgumentException("callback was not registered.");
}
- try {
- mConnector.unregisterTetheringEventCallback(remoteCallback, callerPkg);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
- }
+
+ getConnector(c -> c.unregisterTetheringEventCallback(remoteCallback, callerPkg));
}
}
@@ -1002,9 +1107,9 @@
final String callerPkg = mContext.getOpPackageName();
final RequestDispatcher dispatcher = new RequestDispatcher();
- final int ret = dispatcher.waitForResult(listener -> {
+ final int ret = dispatcher.waitForResult((connector, listener) -> {
try {
- mConnector.isTetheringSupported(callerPkg, listener);
+ connector.isTetheringSupported(callerPkg, listener);
} catch (RemoteException e) {
throw new IllegalStateException(e);
}
@@ -1027,13 +1132,14 @@
final String callerPkg = mContext.getOpPackageName();
Log.i(TAG, "stopAllTethering caller:" + callerPkg);
- final RequestDispatcher dispatcher = new RequestDispatcher();
- dispatcher.waitForResult(listener -> {
- try {
- mConnector.stopAllTethering(callerPkg, listener);
- } catch (RemoteException e) {
- throw new IllegalStateException(e);
+ getConnector(c -> c.stopAllTethering(callerPkg, new IIntResultListener.Stub() {
+ @Override
+ public void onResult(int resultCode) {
+ // TODO: add an API parameter to send result to caller.
+ // This has never been possible as stopAllTethering has always been void and never
+ // taken a callback object. The only indication that callers have is if the call
+ // results in a TETHER_STATE_CHANGE broadcast.
}
- });
+ }));
}
}
diff --git a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
index 7dc5c5f..020b32a 100644
--- a/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
+++ b/packages/Tethering/src/com/android/server/connectivity/tethering/TetheringService.java
@@ -77,8 +77,8 @@
mLog.mark("onCreate");
mDeps = getTetheringDependencies();
mContext = mDeps.getContext();
- mTethering = makeTethering(mDeps);
mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
+ mTethering = makeTethering(mDeps);
}
/**
diff --git a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
index 9501073..fcb113e 100644
--- a/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
+++ b/packages/WallpaperCropper/src/com/android/photos/views/TiledImageRenderer.java
@@ -26,7 +26,6 @@
import android.util.Pools.Pool;
import android.util.Pools.SynchronizedPool;
import android.view.View;
-import android.view.WindowManager;
import com.android.gallery3d.common.Utils;
import com.android.gallery3d.glrenderer.BasicTexture;
@@ -164,9 +163,7 @@
private static boolean isHighResolution(Context context) {
DisplayMetrics metrics = new DisplayMetrics();
- WindowManager wm = (WindowManager)
- context.getSystemService(Context.WINDOW_SERVICE);
- wm.getDefaultDisplay().getMetrics(metrics);
+ context.getDisplay().getMetrics(metrics);
return metrics.heightPixels > 2048 || metrics.widthPixels > 2048;
}
diff --git a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
index f878b4d..6112da5 100644
--- a/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
+++ b/packages/WallpaperCropper/src/com/android/wallpapercropper/WallpaperCropActivity.java
@@ -37,9 +37,9 @@
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
+import android.util.Size;
import android.view.Display;
import android.view.View;
-import android.view.WindowManager;
import android.widget.Toast;
import com.android.gallery3d.common.Utils;
@@ -231,18 +231,18 @@
return x * aspectRatio + y;
}
- static protected Point getDefaultWallpaperSize(Resources res, WindowManager windowManager) {
+ static protected Point getDefaultWallpaperSize(Resources res, Display display) {
if (sDefaultWallpaperSize == null) {
Point minDims = new Point();
Point maxDims = new Point();
- windowManager.getDefaultDisplay().getCurrentSizeRange(minDims, maxDims);
+ display.getCurrentSizeRange(minDims, maxDims);
int maxDim = Math.max(maxDims.x, maxDims.y);
int minDim = Math.max(minDims.x, minDims.y);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
Point realSize = new Point();
- windowManager.getDefaultDisplay().getRealSize(realSize);
+ display.getRealSize(realSize);
maxDim = Math.max(realSize.x, realSize.y);
minDim = Math.min(realSize.x, realSize.y);
}
@@ -331,8 +331,7 @@
// this device
int rotation = getRotationFromExif(res, resId);
Point inSize = mCropView.getSourceDimensions();
- Point outSize = getDefaultWallpaperSize(getResources(),
- getWindowManager());
+ Point outSize = getDefaultWallpaperSize(getResources(), getDisplay());
RectF crop = getMaxCropRect(
inSize.x, inSize.y, outSize.x, outSize.y, false);
Runnable onEndCrop = new Runnable() {
@@ -359,14 +358,11 @@
// Get the crop
boolean ltr = mCropView.getLayoutDirection() == View.LAYOUT_DIRECTION_LTR;
- Display d = getWindowManager().getDefaultDisplay();
-
- Point displaySize = new Point();
- d.getSize(displaySize);
- boolean isPortrait = displaySize.x < displaySize.y;
+ Size windowSize = getWindowManager().getCurrentWindowMetrics().getSize();
+ boolean isPortrait = windowSize.getWidth() < windowSize.getHeight();
Point defaultWallpaperSize = getDefaultWallpaperSize(getResources(),
- getWindowManager());
+ getDisplay());
// Get the crop
RectF cropRect = mCropView.getCrop();
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
index 5ac3b69..667364c9 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/EventDispatcher.java
@@ -301,7 +301,7 @@
* @param policyFlags The policy flags associated with the event.
*/
void sendUpForInjectedDownPointers(MotionEvent prototype, int policyFlags) {
- int pointerIdBits = 0;
+ int pointerIdBits = prototype.getPointerIdBits();
final int pointerCount = prototype.getPointerCount();
for (int i = 0; i < pointerCount; i++) {
final int pointerId = prototype.getPointerId(i);
@@ -309,10 +309,10 @@
if (!isInjectedPointerDown(pointerId)) {
continue;
}
- pointerIdBits |= (1 << pointerId);
- final int action = computeInjectionAction(MotionEvent.ACTION_UP, i);
+ final int action = computeInjectionAction(MotionEvent.ACTION_POINTER_UP, i);
sendMotionEvent(
prototype, action, mState.getLastReceivedEvent(), pointerIdBits, policyFlags);
+ pointerIdBits &= ~(1 << pointerId);
}
}
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
index 1fe162c..5d170d3 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureManifold.java
@@ -18,9 +18,17 @@
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_2_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SINGLE_TAP;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_DOWN;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_LEFT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_RIGHT;
+import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_SWIPE_UP;
import static android.accessibilityservice.AccessibilityService.GESTURE_3_FINGER_TRIPLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP;
import static android.accessibilityservice.AccessibilityService.GESTURE_DOUBLE_TAP_AND_HOLD;
@@ -110,6 +118,7 @@
mGestures.add(new Swipe(context, UP, DOWN, GESTURE_SWIPE_UP_AND_DOWN, this));
mGestures.add(new Swipe(context, UP, LEFT, GESTURE_SWIPE_UP_AND_LEFT, this));
mGestures.add(new Swipe(context, UP, RIGHT, GESTURE_SWIPE_UP_AND_RIGHT, this));
+ // Set up multi-finger gestures to be enabled later.
// Two-finger taps.
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 2, 1, GESTURE_2_FINGER_SINGLE_TAP, this));
@@ -124,6 +133,24 @@
new MultiFingerMultiTap(mContext, 3, 2, GESTURE_3_FINGER_DOUBLE_TAP, this));
mMultiFingerGestures.add(
new MultiFingerMultiTap(mContext, 3, 3, GESTURE_3_FINGER_TRIPLE_TAP, this));
+ // Two-finger swipes.
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 2, DOWN, GESTURE_2_FINGER_SWIPE_DOWN, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 2, LEFT, GESTURE_2_FINGER_SWIPE_LEFT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 2, RIGHT, GESTURE_2_FINGER_SWIPE_RIGHT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 2, UP, GESTURE_2_FINGER_SWIPE_UP, this));
+ // Three-finger swipes.
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 3, DOWN, GESTURE_3_FINGER_SWIPE_DOWN, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 3, LEFT, GESTURE_3_FINGER_SWIPE_LEFT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 3, RIGHT, GESTURE_3_FINGER_SWIPE_RIGHT, this));
+ mMultiFingerGestures.add(
+ new MultiFingerSwipe(context, 3, UP, GESTURE_3_FINGER_SWIPE_UP, this));
}
/**
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
index 0f5dd08..ac67480 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/GestureUtils.java
@@ -8,6 +8,9 @@
*/
public final class GestureUtils {
+ public static int MM_PER_CM = 10;
+ public static float CM_PER_INCH = 2.54f;
+
private GestureUtils() {
/* cannot be instantiated */
}
@@ -85,4 +88,12 @@
return true;
}
+
+ /**
+ * Gets the index of the pointer that went up or down from a motion event.
+ */
+ public static int getActionIndex(MotionEvent event) {
+ return (event.getAction()
+ & MotionEvent.ACTION_POINTER_INDEX_MASK) >> MotionEvent.ACTION_POINTER_INDEX_SHIFT;
+ }
}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
new file mode 100644
index 0000000..8249239
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/MultiFingerSwipe.java
@@ -0,0 +1,496 @@
+/*
+ * 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.accessibility.gestures;
+
+import static android.view.MotionEvent.INVALID_POINTER_ID;
+
+import static com.android.server.accessibility.gestures.GestureUtils.MM_PER_CM;
+import static com.android.server.accessibility.gestures.GestureUtils.getActionIndex;
+import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS;
+import static com.android.server.accessibility.gestures.Swipe.CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS;
+import static com.android.server.accessibility.gestures.Swipe.GESTURE_CONFIRM_CM;
+import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.os.Handler;
+import android.util.DisplayMetrics;
+import android.util.Slog;
+import android.util.TypedValue;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+
+/**
+ * This class is responsible for matching one-finger swipe gestures. Each instance matches one swipe
+ * gesture. A swipe is specified as a series of one or more directions e.g. left, left and up, etc.
+ * At this time swipes with more than two directions are not supported.
+ */
+class MultiFingerSwipe extends GestureMatcher {
+
+ // Direction constants.
+ public static final int LEFT = 0;
+ public static final int RIGHT = 1;
+ public static final int UP = 2;
+ public static final int DOWN = 3;
+ // This is the calculated movement threshold used track if the user is still
+ // moving their finger.
+ private final float mGestureDetectionThresholdPixels;
+
+ // Buffer for storing points for gesture detection.
+ private final ArrayList<PointF>[] mStrokeBuffers;
+
+ // The swipe direction for this matcher.
+ private int mDirection;
+ private int[] mPointerIds;
+ // The starting point of each finger's path in the gesture.
+ private PointF[] mBase;
+ // The most recent entry in each finger's gesture path.
+ private PointF[] mPreviousGesturePoint;
+ private int mTargetFingerCount;
+ private int mCurrentFingerCount;
+ // Whether the appropriate number of fingers have gone down at some point. This is reset only on
+ // clear.
+ private boolean mTargetFingerCountReached = false;
+ // Constants for sampling motion event points.
+ // We sample based on a minimum distance between points, primarily to improve accuracy by
+ // reducing noisy minor changes in direction.
+ private static final float MIN_CM_BETWEEN_SAMPLES = 0.25f;
+ private final float mMinPixelsBetweenSamplesX;
+ private final float mMinPixelsBetweenSamplesY;
+ // The minmimum distance the finger must travel before we evaluate the initial direction of the
+ // swipe.
+ // Anything less is still considered a touch.
+ private int mTouchSlop;
+
+ MultiFingerSwipe(
+ Context context,
+ int fingerCount,
+ int direction,
+ int gesture,
+ GestureMatcher.StateChangeListener listener) {
+ super(gesture, new Handler(context.getMainLooper()), listener);
+ mTargetFingerCount = fingerCount;
+ mPointerIds = new int[mTargetFingerCount];
+ mBase = new PointF[mTargetFingerCount];
+ mPreviousGesturePoint = new PointF[mTargetFingerCount];
+ mStrokeBuffers = new ArrayList[mTargetFingerCount];
+ mDirection = direction;
+ DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
+ mGestureDetectionThresholdPixels =
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, MM_PER_CM, displayMetrics)
+ * GESTURE_CONFIRM_CM;
+ // Calculate minimum gesture velocity
+ final float pixelsPerCmX = displayMetrics.xdpi / GestureUtils.CM_PER_INCH;
+ final float pixelsPerCmY = displayMetrics.ydpi / GestureUtils.CM_PER_INCH;
+ mMinPixelsBetweenSamplesX = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmX;
+ mMinPixelsBetweenSamplesY = MIN_CM_BETWEEN_SAMPLES * pixelsPerCmY;
+ mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
+ clear();
+ }
+
+ @Override
+ protected void clear() {
+ mTargetFingerCountReached = false;
+ mCurrentFingerCount = 0;
+ for (int i = 0; i < mTargetFingerCount; ++i) {
+ mPointerIds[i] = INVALID_POINTER_ID;
+ if (mBase[i] == null) {
+ mBase[i] = new PointF();
+ }
+ mBase[i].x = Float.NaN;
+ mBase[i].y = Float.NaN;
+ if (mPreviousGesturePoint[i] == null) {
+ mPreviousGesturePoint[i] = new PointF();
+ }
+ mPreviousGesturePoint[i].x = Float.NaN;
+ mPreviousGesturePoint[i].y = Float.NaN;
+ if (mStrokeBuffers[i] == null) {
+ mStrokeBuffers[i] = new ArrayList<>(100);
+ }
+ mStrokeBuffers[i].clear();
+ }
+ super.clear();
+ }
+
+ @Override
+ protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (mCurrentFingerCount > 0) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mCurrentFingerCount = 1;
+ final int actionIndex = getActionIndex(rawEvent);
+ final int pointerId = rawEvent.getPointerId(actionIndex);
+ int pointerIndex = rawEvent.getPointerCount() - 1;
+ if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ // Nonsensical pointer id.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ if (mPointerIds[pointerIndex] != INVALID_POINTER_ID) {
+ // Inconsistent event stream.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mPointerIds[pointerIndex] = pointerId;
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ if (Float.isNaN(mBase[pointerIndex].x) && Float.isNaN(mBase[pointerIndex].y)) {
+ final float x = rawEvent.getX(actionIndex);
+ final float y = rawEvent.getY(actionIndex);
+ if (x < 0f || y < 0f) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mBase[pointerIndex].x = x;
+ mBase[pointerIndex].y = y;
+ mPreviousGesturePoint[pointerIndex].x = x;
+ mPreviousGesturePoint[pointerIndex].y = y;
+ } else {
+ // This event doesn't make sense in the middle of a gesture.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ }
+
+ @Override
+ protected void onPointerDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (event.getPointerCount() > mTargetFingerCount) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mCurrentFingerCount += 1;
+ if (mCurrentFingerCount != rawEvent.getPointerCount()) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ if (mCurrentFingerCount == mTargetFingerCount) {
+ mTargetFingerCountReached = true;
+ }
+ final int actionIndex = getActionIndex(rawEvent);
+ final int pointerId = rawEvent.getPointerId(actionIndex);
+ if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ // Nonsensical pointer id.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ int pointerIndex = mCurrentFingerCount - 1;
+ if (mPointerIds[pointerIndex] != INVALID_POINTER_ID) {
+ // Inconsistent event stream.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mPointerIds[pointerIndex] = pointerId;
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ if (Float.isNaN(mBase[pointerIndex].x) && Float.isNaN(mBase[pointerIndex].y)) {
+ final float x = rawEvent.getX(actionIndex);
+ final float y = rawEvent.getY(actionIndex);
+ if (x < 0f || y < 0f) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mBase[pointerIndex].x = x;
+ mBase[pointerIndex].y = y;
+ mPreviousGesturePoint[pointerIndex].x = x;
+ mPreviousGesturePoint[pointerIndex].y = y;
+ } else {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ }
+
+ @Override
+ protected void onPointerUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (!mTargetFingerCountReached) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mCurrentFingerCount -= 1;
+ final int actionIndex = getActionIndex(event);
+ final int pointerId = event.getPointerId(actionIndex);
+ if (pointerId < 0 || pointerId > rawEvent.getPointerCount() - 1) {
+ // Nonsensical pointer id.
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final int pointerIndex = Arrays.binarySearch(mPointerIds, pointerId);
+ if (pointerIndex < 0) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final float x = rawEvent.getX(actionIndex);
+ final float y = rawEvent.getY(actionIndex);
+ if (x < 0f || y < 0f) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final float dX = Math.abs(x - mPreviousGesturePoint[pointerIndex].x);
+ final float dY = Math.abs(y - mPreviousGesturePoint[pointerIndex].y);
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ mStrokeBuffers[pointerIndex].add(new PointF(x, y));
+ }
+ // We will evaluate all the paths on ACTION_UP.
+ }
+
+ @Override
+ protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ for (int pointerIndex = 0; pointerIndex < rawEvent.getPointerCount(); ++pointerIndex) {
+ if (DEBUG) {
+ Slog.d(getGestureName(), "Processing move on finger " + pointerIndex);
+ }
+ int index = rawEvent.findPointerIndex(mPointerIds[pointerIndex]);
+ final float x = rawEvent.getX(index);
+ final float y = rawEvent.getY(index);
+ if (x < 0f || y < 0f) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final float dX = Math.abs(x - mPreviousGesturePoint[pointerIndex].x);
+ final float dY = Math.abs(y - mPreviousGesturePoint[pointerIndex].y);
+ final double moveDelta =
+ Math.hypot(
+ Math.abs(x - mBase[pointerIndex].x),
+ Math.abs(y - mBase[pointerIndex].y));
+ if (DEBUG) {
+ Slog.d(
+ getGestureName(),
+ "moveDelta:"
+ + Double.toString(moveDelta)
+ + " mGestureDetectionThreshold: "
+ + Float.toString(mGestureDetectionThresholdPixels));
+ }
+ if (getState() == STATE_CLEAR) {
+ if (moveDelta < mTouchSlop) {
+ // This still counts as a touch not a swipe.
+ continue;
+ } else if (mStrokeBuffers[pointerIndex].size() == 0) {
+ // First, make sure we have the right number of fingers down.
+ if (mCurrentFingerCount != mTargetFingerCount) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ // Then, make sure the pointer is going in the right direction.
+ int direction =
+ toDirection(x - mBase[pointerIndex].x, y - mBase[pointerIndex].y);
+ if (direction != mDirection) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ } else {
+ // This is confirmed to be some kind of swipe so start tracking points.
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ for (int i = 0; i < mTargetFingerCount; ++i) {
+ mStrokeBuffers[i].add(new PointF(mBase[i]));
+ }
+ }
+ }
+ if (moveDelta > mGestureDetectionThresholdPixels) {
+ // Try to cancel if the finger starts to go the wrong way.
+ // Note that this only works because this matcher assumes one direction.
+ int direction =
+ toDirection(x - mBase[pointerIndex].x, y - mBase[pointerIndex].y);
+ if (direction != mDirection) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ // If the pointer has moved more than the threshold,
+ // update the stored values.
+ mBase[pointerIndex].x = x;
+ mBase[pointerIndex].y = y;
+ mPreviousGesturePoint[pointerIndex].x = x;
+ mPreviousGesturePoint[pointerIndex].y = y;
+ if (getState() == STATE_CLEAR) {
+ startGesture(event, rawEvent, policyFlags);
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ }
+ }
+ }
+ if (getState() == STATE_GESTURE_STARTED) {
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ // Sample every 2.5 MM in order to guard against minor variations in path.
+ mPreviousGesturePoint[pointerIndex].x = x;
+ mPreviousGesturePoint[pointerIndex].y = y;
+ mStrokeBuffers[pointerIndex].add(new PointF(x, y));
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
+ }
+ }
+ }
+ }
+
+ @Override
+ protected void onUp(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ if (getState() != STATE_GESTURE_STARTED) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ mCurrentFingerCount = 0;
+ final int actionIndex = getActionIndex(event);
+ final int pointerId = event.getPointerId(actionIndex);
+ final int pointerIndex = Arrays.binarySearch(mPointerIds, pointerId);
+ if (pointerIndex < 0) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final float x = rawEvent.getX(actionIndex);
+ final float y = rawEvent.getY(actionIndex);
+ if (x < 0f || y < 0f) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ final float dX = Math.abs(x - mPreviousGesturePoint[pointerIndex].x);
+ final float dY = Math.abs(y - mPreviousGesturePoint[pointerIndex].y);
+ if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
+ mStrokeBuffers[pointerIndex].add(new PointF(x, y));
+ }
+ recognizeGesture(event, rawEvent, policyFlags);
+ }
+
+ /**
+ * queues a transition to STATE_GESTURE_CANCEL based on the current state. If we have
+ * transitioned to STATE_GESTURE_STARTED the delay is longer.
+ */
+ private void cancelAfterPauseThreshold(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ cancelPendingTransitions();
+ switch (getState()) {
+ case STATE_CLEAR:
+ cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS, event, rawEvent, policyFlags);
+ break;
+ case STATE_GESTURE_STARTED:
+ cancelAfter(CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS, event, rawEvent, policyFlags);
+ break;
+ default:
+ break;
+ }
+ }
+ /**
+ * Looks at the sequence of motions in mStrokeBuffer, classifies the gesture, then transitions
+ * to the complete or cancel state depending on the result.
+ */
+ private void recognizeGesture(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ // Check the path of each finger against the specified direction.
+ // Note that we sample every 2.5 MMm, and the direction matching is extremely tolerant (each
+ // direction has a 90-degree arch of tolerance) meaning that minor perpendicular movements
+ // should not create false negatives.
+ for (int i = 0; i < mTargetFingerCount; ++i) {
+ if (DEBUG) {
+ Slog.d(getGestureName(), "Recognizing finger: " + i);
+ }
+ if (mStrokeBuffers[i].size() < 2) {
+ Slog.d(getGestureName(), "Too few points.");
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ ArrayList<PointF> path = mStrokeBuffers[i];
+
+ if (DEBUG) {
+ Slog.d(getGestureName(), "path=" + path.toString());
+ }
+ // Classify line segments, and call Listener callbacks.
+ if (!recognizeGesturePath(event, rawEvent, policyFlags, path)) {
+ cancelGesture(event, rawEvent, policyFlags);
+ return;
+ }
+ }
+ // If we reach this point then all paths match.
+ completeGesture(event, rawEvent, policyFlags);
+ }
+
+ /**
+ * Tests the path of a given finger against the direction specified in this matcher.
+ *
+ * @return True if the path matches the specified direction for this matcher, otherwise false.
+ */
+ private boolean recognizeGesturePath(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags, ArrayList<PointF> path) {
+
+ final int displayId = event.getDisplayId();
+ for (int i = 0; i < path.size() - 1; ++i) {
+ PointF start = path.get(i);
+ PointF end = path.get(i + 1);
+
+ float dX = end.x - start.x;
+ float dY = end.y - start.y;
+ int direction = toDirection(dX, dY);
+ if (direction != mDirection) {
+ if (DEBUG) {
+ Slog.d(
+ getGestureName(),
+ "Found direction "
+ + directionToString(direction)
+ + " when expecting "
+ + directionToString(mDirection));
+ }
+ return false;
+ }
+ }
+ if (DEBUG) {
+ Slog.d(getGestureName(), "Completed.");
+ }
+ return true;
+ }
+
+ private static int toDirection(float dX, float dY) {
+ if (Math.abs(dX) > Math.abs(dY)) {
+ // Horizontal
+ return (dX < 0) ? LEFT : RIGHT;
+ } else {
+ // Vertical
+ return (dY < 0) ? UP : DOWN;
+ }
+ }
+
+ public static String directionToString(int direction) {
+ switch (direction) {
+ case LEFT:
+ return "left";
+ case RIGHT:
+ return "right";
+ case UP:
+ return "up";
+ case DOWN:
+ return "down";
+ default:
+ return "Unknown Direction";
+ }
+ }
+
+ @Override
+ String getGestureName() {
+ StringBuilder builder = new StringBuilder();
+ builder.append(mTargetFingerCount).append("-finger ");
+ builder.append("Swipe ").append(directionToString(mDirection));
+ return builder.toString();
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder(super.toString());
+ if (getState() != STATE_GESTURE_CANCELED) {
+ builder.append(", mBase: ")
+ .append(mBase.toString())
+ .append(", mGestureDetectionThreshold:")
+ .append(mGestureDetectionThresholdPixels)
+ .append(", mMinPixelsBetweenSamplesX:")
+ .append(mMinPixelsBetweenSamplesX)
+ .append(", mMinPixelsBetweenSamplesY:")
+ .append(mMinPixelsBetweenSamplesY);
+ }
+ return builder.toString();
+ }
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/SecondFingerMultiTap.java b/services/accessibility/java/com/android/server/accessibility/gestures/SecondFingerMultiTap.java
index 8a566fc..ada251f 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/SecondFingerMultiTap.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/SecondFingerMultiTap.java
@@ -18,6 +18,8 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import static com.android.server.accessibility.gestures.GestureUtils.getActionIndex;
+
import android.content.Context;
import android.os.Handler;
import android.view.MotionEvent;
@@ -155,11 +157,6 @@
return moveDelta <= slop;
}
- private int getActionIndex(MotionEvent event) {
- return event.getAction()
- & MotionEvent.ACTION_POINTER_INDEX_MASK << MotionEvent.ACTION_POINTER_INDEX_SHIFT;
- }
-
@Override
public String toString() {
return super.toString()
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
index a285c10..9108c69 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/Swipe.java
@@ -16,10 +16,10 @@
package com.android.server.accessibility.gestures;
+import static com.android.server.accessibility.gestures.GestureUtils.MM_PER_CM;
import static com.android.server.accessibility.gestures.TouchExplorer.DEBUG;
import android.content.Context;
-import android.gesture.GesturePoint;
import android.graphics.PointF;
import android.os.Handler;
import android.util.DisplayMetrics;
@@ -44,10 +44,10 @@
public static final int DOWN = 3;
// This is the calculated movement threshold used track if the user is still
// moving their finger.
- private final float mGestureDetectionThreshold;
+ private final float mGestureDetectionThresholdPixels;
// Buffer for storing points for gesture detection.
- private final ArrayList<GesturePoint> mStrokeBuffer = new ArrayList<GesturePoint>(100);
+ private final ArrayList<PointF> mStrokeBuffer = new ArrayList<>(100);
// The minimal delta between moves to add a gesture point.
private static final int TOUCH_TOLERANCE_PIX = 3;
@@ -56,7 +56,7 @@
private static final float MIN_PREDICTION_SCORE = 2.0f;
// Distance a finger must travel before we decide if it is a gesture or not.
- private static final int GESTURE_CONFIRM_CM = 1;
+ public static final int GESTURE_CONFIRM_CM = 1;
// Time threshold used to determine if an interaction is a gesture or not.
// If the first movement of 1cm takes longer than this value, we assume it's
@@ -67,17 +67,16 @@
// all gestures started with the initial movement taking less than 100ms.
// When touch exploring, the first movement almost always takes longer than
// 200ms.
- private static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
+ public static final long CANCEL_ON_PAUSE_THRESHOLD_NOT_STARTED_MS = 150;
// Time threshold used to determine if a gesture should be cancelled. If
// the finger takes more than this time to move 1cm, the ongoing gesture is
// cancelled.
- private static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
+ public static final long CANCEL_ON_PAUSE_THRESHOLD_STARTED_MS = 300;
private int[] mDirections;
private float mBaseX;
private float mBaseY;
- private long mBaseTime;
private float mPreviousGestureX;
private float mPreviousGestureY;
// Constants for sampling motion event points.
@@ -119,8 +118,8 @@
super(gesture, new Handler(context.getMainLooper()), listener);
mDirections = directions;
DisplayMetrics displayMetrics = context.getResources().getDisplayMetrics();
- mGestureDetectionThreshold =
- TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, 10, displayMetrics)
+ mGestureDetectionThresholdPixels =
+ TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_MM, MM_PER_CM, displayMetrics)
* GESTURE_CONFIRM_CM;
// Calculate minimum gesture velocity
final float pixelsPerCmX = displayMetrics.xdpi / 2.54f;
@@ -135,18 +134,16 @@
protected void clear() {
mBaseX = Float.NaN;
mBaseY = Float.NaN;
- mBaseTime = 0;
mStrokeBuffer.clear();
super.clear();
}
@Override
protected void onDown(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cancelAfterDelay(event, rawEvent, policyFlags);
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
if (Float.isNaN(mBaseX) && Float.isNaN(mBaseY)) {
mBaseX = rawEvent.getX();
mBaseY = rawEvent.getY();
- mBaseTime = event.getEventTime();
mPreviousGestureX = mBaseX;
mPreviousGestureY = mBaseY;
}
@@ -157,10 +154,8 @@
protected void onMove(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
final float x = rawEvent.getX();
final float y = rawEvent.getY();
- final long time = event.getEventTime();
final float dX = Math.abs(x - mPreviousGestureX);
final float dY = Math.abs(y - mPreviousGestureY);
- final long timeDelta = time - mBaseTime;
final double moveDelta = Math.hypot(Math.abs(x - mBaseX), Math.abs(y - mBaseY));
if (DEBUG) {
Slog.d(
@@ -168,7 +163,7 @@
"moveDelta:"
+ Double.toString(moveDelta)
+ " mGestureDetectionThreshold: "
- + Float.toString(mGestureDetectionThreshold));
+ + Float.toString(mGestureDetectionThresholdPixels));
}
if (getState() == STATE_CLEAR) {
if (moveDelta < mTouchSlop) {
@@ -176,25 +171,24 @@
return;
} else if (mStrokeBuffer.size() == 0) {
// First, make sure the pointer is going in the right direction.
- cancelAfterDelay(event, rawEvent, policyFlags);
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
int direction = toDirection(x - mBaseX, y - mBaseY);
if (direction != mDirections[0]) {
cancelGesture(event, rawEvent, policyFlags);
return;
} else {
// This is confirmed to be some kind of swipe so start tracking points.
- mStrokeBuffer.add(new GesturePoint(mBaseX, mBaseY, mBaseTime));
+ mStrokeBuffer.add(new PointF(mBaseX, mBaseY));
}
}
- if (moveDelta > mGestureDetectionThreshold) {
+ if (moveDelta > mGestureDetectionThresholdPixels) {
// If the pointer has moved more than the threshold,
// update the stored values.
mBaseX = x;
mBaseY = y;
- mBaseTime = time;
if (getState() == STATE_CLEAR) {
startGesture(event, rawEvent, policyFlags);
- cancelAfterDelay(event, rawEvent, policyFlags);
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
}
}
}
@@ -202,8 +196,8 @@
if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
mPreviousGestureX = x;
mPreviousGestureY = y;
- mStrokeBuffer.add(new GesturePoint(x, y, time));
- cancelAfterDelay(event, rawEvent, policyFlags);
+ mStrokeBuffer.add(new PointF(x, y));
+ cancelAfterPauseThreshold(event, rawEvent, policyFlags);
}
}
}
@@ -217,11 +211,10 @@
final float x = rawEvent.getX();
final float y = rawEvent.getY();
- final long time = event.getEventTime();
final float dX = Math.abs(x - mPreviousGestureX);
final float dY = Math.abs(y - mPreviousGestureY);
if (dX >= mMinPixelsBetweenSamplesX || dY >= mMinPixelsBetweenSamplesY) {
- mStrokeBuffer.add(new GesturePoint(x, y, time));
+ mStrokeBuffer.add(new PointF(x, y));
}
recognizeGesture(event, rawEvent, policyFlags);
}
@@ -240,7 +233,8 @@
* queues a transition to STATE_GESTURE_CANCEL based on the current state. If we have
* transitioned to STATE_GESTURE_STARTED the delay is longer.
*/
- private void cancelAfterDelay(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
+ private void cancelAfterPauseThreshold(
+ MotionEvent event, MotionEvent rawEvent, int policyFlags) {
cancelPendingTransitions();
switch (getState()) {
case STATE_CLEAR:
@@ -275,7 +269,7 @@
// 90 degrees.
ArrayList<PointF> path = new ArrayList<>();
- PointF lastDelimiter = new PointF(mStrokeBuffer.get(0).x, mStrokeBuffer.get(0).y);
+ PointF lastDelimiter = mStrokeBuffer.get(0);
path.add(lastDelimiter);
float dX = 0; // Sum of unit vectors from last delimiter to each following point
@@ -283,9 +277,9 @@
int count = 0; // Number of points since last delimiter
float length = 0; // Vector length from delimiter to most recent point
- PointF next = new PointF();
+ PointF next = null;
for (int i = 1; i < mStrokeBuffer.size(); ++i) {
- next = new PointF(mStrokeBuffer.get(i).x, mStrokeBuffer.get(i).y);
+ next = mStrokeBuffer.get(i);
if (count > 0) {
// Average of unit vectors from delimiter to following points
float currentDX = dX / count;
@@ -428,7 +422,7 @@
.append(", mBaseY: ")
.append(mBaseY)
.append(", mGestureDetectionThreshold:")
- .append(mGestureDetectionThreshold)
+ .append(mGestureDetectionThresholdPixels)
.append(", mMinPixelsBetweenSamplesX:")
.append(mMinPixelsBetweenSamplesX)
.append(", mMinPixelsBetweenSamplesY:")
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 97f27ca..7151d2b 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -98,7 +98,6 @@
import android.util.proto.ProtoOutputStream;
import android.view.Display;
import android.view.View;
-import android.view.WindowManager;
import android.widget.RemoteViews;
import com.android.internal.R;
@@ -282,8 +281,7 @@
}
private void computeMaximumWidgetBitmapMemory() {
- WindowManager wm = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE);
- Display display = wm.getDefaultDisplay();
+ Display display = mContext.getDisplay();
Point size = new Point();
display.getRealSize(size);
// Cap memory usage at 1.5 times the size of the display
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 4f18f35..1a4fc32 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -154,6 +154,13 @@
@GuardedBy("mLock")
private FillEventHistory mEventHistory;
+ /**
+ * The last inline augmented autofill selection. Note that we don't log the selection from the
+ * dropdown UI since the service owns the UI in that case.
+ */
+ @GuardedBy("mLock")
+ private FillEventHistory mAugmentedAutofillEventHistory;
+
/** Shared instance, doesn't need to be logged */
private final AutofillCompatState mAutofillCompatState;
@@ -707,6 +714,13 @@
}
}
+ void setLastAugmentedAutofillResponse(int sessionId) {
+ synchronized (mLock) {
+ mAugmentedAutofillEventHistory = new FillEventHistory(sessionId, /* clientState= */
+ null);
+ }
+ }
+
/**
* Resets the last fill selection.
*/
@@ -716,6 +730,12 @@
}
}
+ void resetLastAugmentedAutofillResponse() {
+ synchronized (mLock) {
+ mAugmentedAutofillEventHistory = null;
+ }
+ }
+
@GuardedBy("mLock")
private boolean isValidEventLocked(String method, int sessionId) {
if (mEventHistory == null) {
@@ -798,6 +818,32 @@
}
}
+ void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
+ @Nullable Bundle clientState) {
+ synchronized (mLock) {
+ if (mAugmentedAutofillEventHistory == null
+ || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
+ return;
+ }
+ mAugmentedAutofillEventHistory.addEvent(
+ new Event(Event.TYPE_DATASET_SELECTED, suggestionId, clientState, null, null,
+ null, null, null, null, null, null));
+ }
+ }
+
+ void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState) {
+ synchronized (mLock) {
+ if (mAugmentedAutofillEventHistory == null
+ || mAugmentedAutofillEventHistory.getSessionId() != sessionId) {
+ return;
+ }
+ mAugmentedAutofillEventHistory.addEvent(
+ new Event(Event.TYPE_DATASETS_SHOWN, null, clientState, null, null, null,
+ null, null, null, null, null));
+
+ }
+ }
+
/**
* Updates the last fill response when an autofill context is committed.
*/
@@ -881,8 +927,8 @@
* Gets the fill event history.
*
* @param callingUid The calling uid
- *
- * @return The history or {@code null} if there is none.
+ * @return The history for the autofill or the augmented autofill events depending on the {@code
+ * callingUid}, or {@code null} if there is none.
*/
FillEventHistory getFillEventHistory(int callingUid) {
synchronized (mLock) {
@@ -890,6 +936,10 @@
&& isCalledByServiceLocked("getFillEventHistory", callingUid)) {
return mEventHistory;
}
+ if (mAugmentedAutofillEventHistory != null && isCalledByAugmentedAutofillServiceLocked(
+ "getFillEventHistory", callingUid)) {
+ return mAugmentedAutofillEventHistory;
+ }
}
return null;
}
@@ -1163,8 +1213,32 @@
Slog.v(TAG, "getRemoteAugmentedAutofillServiceLocked(): " + componentName);
}
- mRemoteAugmentedAutofillService = new RemoteAugmentedAutofillService(getContext(),
- componentName, mUserId, new RemoteAugmentedAutofillServiceCallbacks() {
+ final RemoteAugmentedAutofillServiceCallbacks callbacks =
+ new RemoteAugmentedAutofillServiceCallbacks() {
+ @Override
+ public void resetLastResponse() {
+ AutofillManagerServiceImpl.this.resetLastAugmentedAutofillResponse();
+ }
+
+ @Override
+ public void setLastResponse(int sessionId) {
+ AutofillManagerServiceImpl.this.setLastAugmentedAutofillResponse(
+ sessionId);
+ }
+
+ @Override
+ public void logAugmentedAutofillShown(int sessionId, Bundle clientState) {
+ AutofillManagerServiceImpl.this.logAugmentedAutofillShown(sessionId,
+ clientState);
+ }
+
+ @Override
+ public void logAugmentedAutofillSelected(int sessionId, String suggestionId,
+ Bundle clientState) {
+ AutofillManagerServiceImpl.this.logAugmentedAutofillSelected(sessionId,
+ suggestionId, clientState);
+ }
+
@Override
public void onServiceDied(@NonNull RemoteAugmentedAutofillService service) {
Slog.w(TAG, "remote augmented autofill service died");
@@ -1175,8 +1249,10 @@
}
mRemoteAugmentedAutofillService = null;
}
- }, mMaster.isInstantServiceAllowed(), mMaster.verbose,
- mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
+ };
+ mRemoteAugmentedAutofillService = new RemoteAugmentedAutofillService(getContext(),
+ componentName, mUserId, callbacks, mMaster.isInstantServiceAllowed(),
+ mMaster.verbose, mMaster.mAugmentedServiceIdleUnbindTimeoutMs,
mMaster.mAugmentedServiceRequestTimeoutMs);
}
diff --git a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
index c7be80c..cb6c8f5 100644
--- a/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
+++ b/services/autofill/java/com/android/server/autofill/InlineSuggestionFactory.java
@@ -28,7 +28,6 @@
import android.view.SurfaceControl;
import android.view.View;
import android.view.autofill.AutofillId;
-import android.view.autofill.IAutoFillManagerClient;
import android.view.inputmethod.InlineSuggestion;
import android.view.inputmethod.InlineSuggestionInfo;
import android.view.inputmethod.InlineSuggestionsResponse;
@@ -49,15 +48,24 @@
private static final String TAG = "InlineSuggestionFactory";
/**
+ * Callback from the inline suggestion Ui.
+ */
+ public interface InlineSuggestionUiCallback {
+ /**
+ * Callback to autofill a dataset to the client app.
+ */
+ void autofill(@NonNull Dataset dataset);
+ }
+
+ /**
* Creates an {@link InlineSuggestionsResponse} with the {@code datasets} provided by
* augmented autofill service.
*/
public static InlineSuggestionsResponse createAugmentedInlineSuggestionsResponse(
- int sessionId,
@NonNull Dataset[] datasets,
@NonNull AutofillId autofillId,
@NonNull Context context,
- @NonNull IAutoFillManagerClient client) {
+ @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback) {
if (sDebug) Slog.d(TAG, "createAugmentedInlineSuggestionsResponse called");
final ArrayList<InlineSuggestion> inlineSuggestions = new ArrayList<>();
@@ -74,8 +82,8 @@
Slog.w(TAG, "InlinePresentation not found in dataset");
return null;
}
- InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(sessionId, dataset,
- inlinePresentation, inlineSuggestionUi, client);
+ InlineSuggestion inlineSuggestion = createAugmentedInlineSuggestion(dataset,
+ inlinePresentation, inlineSuggestionUi, inlineSuggestionUiCallback);
inlineSuggestions.add(inlineSuggestion);
}
return new InlineSuggestionsResponse(inlineSuggestions);
@@ -114,22 +122,17 @@
return new InlineSuggestionsResponse(inlineSuggestions);
}
- private static InlineSuggestion createAugmentedInlineSuggestion(int sessionId,
- @NonNull Dataset dataset,
+ private static InlineSuggestion createAugmentedInlineSuggestion(@NonNull Dataset dataset,
@NonNull InlinePresentation inlinePresentation,
@NonNull InlineSuggestionUi inlineSuggestionUi,
- @NonNull IAutoFillManagerClient client) {
+ @NonNull InlineSuggestionUiCallback inlineSuggestionUiCallback) {
// TODO(b/146453195): fill in the autofill hint properly.
final InlineSuggestionInfo inlineSuggestionInfo = new InlineSuggestionInfo(
inlinePresentation.getInlinePresentationSpec(),
InlineSuggestionInfo.SOURCE_PLATFORM, new String[]{""},
InlineSuggestionInfo.TYPE_SUGGESTION);
final View.OnClickListener onClickListener = v -> {
- try {
- client.autofill(sessionId, dataset.getFieldIds(), dataset.getFieldValues());
- } catch (RemoteException e) {
- Slog.w(TAG, "Encounter exception autofilling the values");
- }
+ inlineSuggestionUiCallback.autofill(dataset);
};
final InlineSuggestion inlineSuggestion = new InlineSuggestion(inlineSuggestionInfo,
createInlineContentProvider(inlinePresentation, inlineSuggestionUi,
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index 5fbdd25..5e6f6fea 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -69,6 +69,7 @@
private final int mIdleUnbindTimeoutMs;
private final int mRequestTimeoutMs;
private final ComponentName mComponentName;
+ private final RemoteAugmentedAutofillServiceCallbacks mCallbacks;
RemoteAugmentedAutofillService(Context context, ComponentName serviceName,
int userId, RemoteAugmentedAutofillServiceCallbacks callbacks,
@@ -81,6 +82,7 @@
mIdleUnbindTimeoutMs = idleUnbindTimeoutMs;
mRequestTimeoutMs = requestTimeoutMs;
mComponentName = serviceName;
+ mCallbacks = callbacks;
// Bind right away.
connect();
@@ -159,9 +161,12 @@
focusedId, focusedValue, requestTime, inlineSuggestionsRequest,
new IFillCallback.Stub() {
@Override
- public void onSuccess(@Nullable Dataset[] inlineSuggestionsData) {
- maybeHandleInlineSuggestions(sessionId, inlineSuggestionsData,
- focusedId, inlineSuggestionsCallback, client);
+ public void onSuccess(@Nullable Dataset[] inlineSuggestionsData,
+ @Nullable Bundle clientState) {
+ mCallbacks.resetLastResponse();
+ maybeRequestShowInlineSuggestions(sessionId,
+ inlineSuggestionsData, focusedId,
+ inlineSuggestionsCallback, client, clientState);
requestAutofill.complete(null);
}
@@ -223,20 +228,32 @@
});
}
- private void maybeHandleInlineSuggestions(int sessionId,
+ private void maybeRequestShowInlineSuggestions(int sessionId,
@Nullable Dataset[] inlineSuggestionsData, @NonNull AutofillId focusedId,
@Nullable IInlineSuggestionsResponseCallback inlineSuggestionsCallback,
- @NonNull IAutoFillManagerClient client) {
+ @NonNull IAutoFillManagerClient client, @Nullable Bundle clientState) {
if (ArrayUtils.isEmpty(inlineSuggestionsData) || inlineSuggestionsCallback == null) {
return;
}
+ mCallbacks.setLastResponse(sessionId);
try {
inlineSuggestionsCallback.onInlineSuggestionsResponse(
- InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(sessionId,
- inlineSuggestionsData, focusedId, mContext, client));
+ InlineSuggestionFactory.createAugmentedInlineSuggestionsResponse(
+ inlineSuggestionsData, focusedId, mContext,
+ dataset -> {
+ mCallbacks.logAugmentedAutofillSelected(sessionId,
+ dataset.getId(), clientState);
+ try {
+ client.autofill(sessionId, dataset.getFieldIds(),
+ dataset.getFieldValues());
+ } catch (RemoteException e) {
+ Slog.w(TAG, "Encounter exception autofilling the values");
+ }
+ }));
} catch (RemoteException e) {
Slog.w(TAG, "Exception sending inline suggestions response back to IME.");
}
+ mCallbacks.logAugmentedAutofillShown(sessionId, clientState);
}
@Override
@@ -254,8 +271,13 @@
public interface RemoteAugmentedAutofillServiceCallbacks
extends AbstractRemoteService.VultureCallback<RemoteAugmentedAutofillService> {
- // NOTE: so far we don't need to notify the callback implementation (an inner class on
- // AutofillManagerServiceImpl) of the request results (success, timeouts, etc..), so this
- // callback interface is empty.
+ void resetLastResponse();
+
+ void setLastResponse(int sessionId);
+
+ void logAugmentedAutofillShown(int sessionId, @Nullable Bundle clientState);
+
+ void logAugmentedAutofillSelected(int sessionId, @Nullable String suggestionId,
+ @Nullable Bundle clientState);
}
}
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ee37de5..415ecd8 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2674,7 +2674,9 @@
if (response.supportsInlineSuggestions()) {
if (requestShowInlineSuggestions(response)) {
- //TODO(b/137800469): Add logging instead of bypassing below logic.
+ //TODO(b/137800469): Fix it to log showed only when IME asks for inflation, rather
+ // than here where framework sends back the response.
+ mService.logDatasetShown(id, mClientState);
return;
}
}
diff --git a/services/core/java/android/app/usage/UsageStatsManagerInternal.java b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
index a8be669..5c2cbfa 100644
--- a/services/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/services/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -215,9 +215,14 @@
/**
* Returns the events for the user in the given time period.
+ *
+ * @param obfuscateInstantApps whether instant app package names need to be obfuscated in the
+ * result.
+ * @param hideShortcutInvocationEvents whether the {@link UsageEvents.Event#SHORTCUT_INVOCATION}
+ * events need to be excluded from the result.
*/
public abstract UsageEvents queryEventsForUser(@UserIdInt int userId, long beginTime,
- long endTime, boolean shouldObfuscateInstantApps);
+ long endTime, boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents);
/**
* Used to persist the last time a job was run for this app, in order to make decisions later
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index d933e9d..0194a21 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -557,13 +557,17 @@
.asInterface(ServiceManager.getService("dnsresolver"));
}
- /** Handler thread used for both of the handlers below. */
+ /** Handler thread used for all of the handlers below. */
@VisibleForTesting
protected final HandlerThread mHandlerThread;
/** Handler used for internal events. */
final private InternalHandler mHandler;
/** Handler used for incoming {@link NetworkStateTracker} events. */
final private NetworkStateTrackerHandler mTrackerHandler;
+ /** Handler used for processing {@link android.net.ConnectivityDiagnosticsManager} events */
+ @VisibleForTesting
+ final ConnectivityDiagnosticsHandler mConnectivityDiagnosticsHandler;
+
private final DnsManager mDnsManager;
private boolean mSystemReady;
@@ -630,6 +634,10 @@
@VisibleForTesting
final MultipathPolicyTracker mMultipathPolicyTracker;
+ @VisibleForTesting
+ final Map<IConnectivityDiagnosticsCallback, ConnectivityDiagnosticsCallbackInfo>
+ mConnectivityDiagnosticsCallbacks = new HashMap<>();
+
/**
* Implements support for the legacy "one network per network type" model.
*
@@ -962,6 +970,8 @@
mHandlerThread.start();
mHandler = new InternalHandler(mHandlerThread.getLooper());
mTrackerHandler = new NetworkStateTrackerHandler(mHandlerThread.getLooper());
+ mConnectivityDiagnosticsHandler =
+ new ConnectivityDiagnosticsHandler(mHandlerThread.getLooper());
mReleasePendingIntentDelayMs = Settings.Secure.getInt(context.getContentResolver(),
Settings.Secure.CONNECTIVITY_RELEASE_PENDING_INTENT_DELAY_MS, 5_000);
@@ -3391,18 +3401,7 @@
nri.unlinkDeathRecipient();
mNetworkRequests.remove(nri.request);
- synchronized (mUidToNetworkRequestCount) {
- int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
- if (requests < 1) {
- Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " +
- nri.mUid);
- } else if (requests == 1) {
- mUidToNetworkRequestCount.removeAt(
- mUidToNetworkRequestCount.indexOfKey(nri.mUid));
- } else {
- mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
- }
- }
+ decrementNetworkRequestPerUidCount(nri);
mNetworkRequestInfoLogs.log("RELEASE " + nri);
if (nri.request.isRequest()) {
@@ -3473,6 +3472,19 @@
}
}
+ private void decrementNetworkRequestPerUidCount(final NetworkRequestInfo nri) {
+ synchronized (mUidToNetworkRequestCount) {
+ final int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
+ if (requests < 1) {
+ Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " + nri.mUid);
+ } else if (requests == 1) {
+ mUidToNetworkRequestCount.removeAt(mUidToNetworkRequestCount.indexOfKey(nri.mUid));
+ } else {
+ mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
+ }
+ }
+ }
+
@Override
public void setAcceptUnvalidated(Network network, boolean accept, boolean always) {
enforceNetworkStackSettingsOrSetup();
@@ -5091,6 +5103,10 @@
}
}
+ NetworkRequestInfo(NetworkRequest r) {
+ this(r, null);
+ }
+
private void enforceRequestCountLimit() {
synchronized (mUidToNetworkRequestCount) {
int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
@@ -5537,20 +5553,6 @@
return nri.request.requestId == mDefaultRequest.requestId;
}
- // TODO : remove this method. It's a stopgap measure to help sheperding a number of dependent
- // changes that would conflict throughout the automerger graph. Having this method temporarily
- // helps with the process of going through with all these dependent changes across the entire
- // tree.
- /**
- * Register a new agent. {@see #registerNetworkAgent} below.
- */
- public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
- LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig) {
- return registerNetworkAgent(messenger, networkInfo, linkProperties, networkCapabilities,
- currentScore, networkAgentConfig, NetworkProvider.ID_NONE);
- }
-
/**
* Register a new agent with ConnectivityService to handle a network.
*
@@ -5569,7 +5571,7 @@
*/
public Network registerNetworkAgent(Messenger messenger, NetworkInfo networkInfo,
LinkProperties linkProperties, NetworkCapabilities networkCapabilities,
- int currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
+ NetworkScore currentScore, NetworkAgentConfig networkAgentConfig, int providerId) {
enforceNetworkFactoryPermission();
LinkProperties lp = new LinkProperties(linkProperties);
@@ -5577,12 +5579,10 @@
// TODO: Instead of passing mDefaultRequest, provide an API to determine whether a Network
// satisfies mDefaultRequest.
final NetworkCapabilities nc = new NetworkCapabilities(networkCapabilities);
- final NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, currentScore);
final NetworkAgentInfo nai = new NetworkAgentInfo(messenger, new AsyncChannel(),
new Network(mNetIdManager.reserveNetId()), new NetworkInfo(networkInfo), lp, nc,
- ns, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig), this,
- mNetd, mDnsResolver, mNMS, providerId);
+ currentScore, mContext, mTrackerHandler, new NetworkAgentConfig(networkAgentConfig),
+ this, mNetd, mDnsResolver, mNMS, providerId);
// Make sure the network capabilities reflect what the agent info says.
nai.getAndSetNetworkCapabilities(mixInCapabilities(nai, nc));
final String extraInfo = networkInfo.getExtraInfo();
@@ -6181,7 +6181,10 @@
private void callCallbackForRequest(NetworkRequestInfo nri,
NetworkAgentInfo networkAgent, int notificationType, int arg1) {
if (nri.messenger == null) {
- return; // Default request has no msgr
+ // Default request has no msgr. Also prevents callbacks from being invoked for
+ // NetworkRequestInfos registered with ConnectivityDiagnostics requests. Those callbacks
+ // are Type.LISTEN, but should not have NetworkCallbacks invoked.
+ return;
}
Bundle bundle = new Bundle();
// TODO: check if defensive copies of data is needed.
@@ -6335,12 +6338,34 @@
}
}
+ static class RequestReassignment {
+ @NonNull public final NetworkRequestInfo mRequest;
+ @Nullable public final NetworkAgentInfo mOldNetwork;
+ @Nullable public final NetworkAgentInfo mNewNetwork;
+ RequestReassignment(@NonNull final NetworkRequestInfo request,
+ @Nullable final NetworkAgentInfo oldNetwork,
+ @Nullable final NetworkAgentInfo newNetwork) {
+ mRequest = request;
+ mOldNetwork = oldNetwork;
+ mNewNetwork = newNetwork;
+ }
+ }
+
@NonNull private final Set<NetworkBgStatePair> mRematchedNetworks = new ArraySet<>();
+ @NonNull private final List<RequestReassignment> mReassignments = new ArrayList<>();
@NonNull Iterable<NetworkBgStatePair> getRematchedNetworks() {
return mRematchedNetworks;
}
+ @NonNull Iterable<RequestReassignment> getRequestReassignments() {
+ return mReassignments;
+ }
+
+ void addRequestReassignment(@NonNull final RequestReassignment reassignment) {
+ mReassignments.add(reassignment);
+ }
+
void addRematchedNetwork(@NonNull final NetworkBgStatePair network) {
mRematchedNetworks.add(network);
}
@@ -6416,20 +6441,13 @@
changes.addRematchedNetwork(new NetworkReassignment.NetworkBgStatePair(newNetwork,
newNetwork.isBackgroundNetwork()));
- final int score = newNetwork.getCurrentScore();
-
if (VDBG || DDBG) log("rematching " + newNetwork.name());
final ArrayMap<NetworkRequestInfo, NetworkAgentInfo> reassignedRequests =
computeRequestReassignmentForNetwork(newNetwork);
- NetworkCapabilities nc = newNetwork.networkCapabilities;
- if (VDBG) log(" network has: " + nc);
-
// Find and migrate to this Network any NetworkRequests for
// which this network is now the best.
- final ArrayList<NetworkAgentInfo> removedRequests = new ArrayList<>();
- final ArrayList<NetworkRequestInfo> addedRequests = new ArrayList<>();
for (final Map.Entry<NetworkRequestInfo, NetworkAgentInfo> entry :
reassignedRequests.entrySet()) {
final NetworkRequestInfo nri = entry.getKey();
@@ -6443,7 +6461,6 @@
}
previousSatisfier.removeRequest(nri.request.requestId);
previousSatisfier.lingerRequest(nri.request, now, mLingerDelayMs);
- removedRequests.add(previousSatisfier);
} else {
if (VDBG || DDBG) log(" accepting network in place of null");
}
@@ -6452,7 +6469,8 @@
if (!newSatisfier.addRequest(nri.request)) {
Slog.wtf(TAG, "BUG: " + newSatisfier.name() + " already has " + nri.request);
}
- addedRequests.add(nri);
+ changes.addRequestReassignment(new NetworkReassignment.RequestReassignment(
+ nri, previousSatisfier, newSatisfier));
// Tell NetworkProviders about the new score, so they can stop
// trying to connect if they know they cannot match it.
// TODO - this could get expensive if we have a lot of requests for this
@@ -6509,21 +6527,6 @@
// Have a new default network, release the transition wakelock in
scheduleReleaseNetworkTransitionWakelock();
}
-
- if (!newNetwork.networkCapabilities.equalRequestableCapabilities(nc)) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed requestable capabilities during rematch: %s -> %s",
- newNetwork.name(), nc, newNetwork.networkCapabilities));
- }
- if (newNetwork.getCurrentScore() != score) {
- Slog.wtf(TAG, String.format(
- "BUG: %s changed score during rematch: %d -> %d",
- newNetwork.name(), score, newNetwork.getCurrentScore()));
- }
-
- // Notify requested networks are available after the default net is switched, but
- // before LegacyTypeTracker sends legacy broadcasts
- for (NetworkRequestInfo nri : addedRequests) notifyNetworkAvailable(newNetwork, nri);
}
/**
@@ -6552,6 +6555,15 @@
final NetworkAgentInfo newDefaultNetwork = getDefaultNetwork();
+ // Notify requested networks are available after the default net is switched, but
+ // before LegacyTypeTracker sends legacy broadcasts
+ for (final NetworkReassignment.RequestReassignment event :
+ changes.getRequestReassignments()) {
+ if (null != event.mNewNetwork) {
+ notifyNetworkAvailable(event.mNewNetwork, event.mRequest);
+ }
+ }
+
for (final NetworkReassignment.NetworkBgStatePair event : changes.getRematchedNetworks()) {
// Process listen requests and update capabilities if the background state has
// changed for this network. For consistency with previous behavior, send onLost
@@ -7337,19 +7349,161 @@
}
}
+ /**
+ * Handler used for managing all Connectivity Diagnostics related functions.
+ *
+ * @see android.net.ConnectivityDiagnosticsManager
+ *
+ * TODO(b/147816404): Explore moving ConnectivityDiagnosticsHandler to a separate file
+ */
+ @VisibleForTesting
+ class ConnectivityDiagnosticsHandler extends Handler {
+ /**
+ * Used to handle ConnectivityDiagnosticsCallback registration events from {@link
+ * android.net.ConnectivityDiagnosticsManager}.
+ * obj = ConnectivityDiagnosticsCallbackInfo with IConnectivityDiagnosticsCallback and
+ * NetworkRequestInfo to be registered
+ */
+ private static final int EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 1;
+
+ /**
+ * Used to handle ConnectivityDiagnosticsCallback unregister events from {@link
+ * android.net.ConnectivityDiagnosticsManager}.
+ * obj = the IConnectivityDiagnosticsCallback to be unregistered
+ * arg1 = the uid of the caller
+ */
+ private static final int EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK = 2;
+
+ private ConnectivityDiagnosticsHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void handleMessage(Message msg) {
+ switch (msg.what) {
+ case EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
+ handleRegisterConnectivityDiagnosticsCallback(
+ (ConnectivityDiagnosticsCallbackInfo) msg.obj);
+ break;
+ }
+ case EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK: {
+ handleUnregisterConnectivityDiagnosticsCallback(
+ (IConnectivityDiagnosticsCallback) msg.obj, msg.arg1);
+ break;
+ }
+ }
+ }
+ }
+
+ /** Class used for cleaning up IConnectivityDiagnosticsCallback instances after their death. */
+ @VisibleForTesting
+ class ConnectivityDiagnosticsCallbackInfo implements Binder.DeathRecipient {
+ @NonNull private final IConnectivityDiagnosticsCallback mCb;
+ @NonNull private final NetworkRequestInfo mRequestInfo;
+
+ @VisibleForTesting
+ ConnectivityDiagnosticsCallbackInfo(
+ @NonNull IConnectivityDiagnosticsCallback cb, @NonNull NetworkRequestInfo nri) {
+ mCb = cb;
+ mRequestInfo = nri;
+ }
+
+ @Override
+ public void binderDied() {
+ log("ConnectivityDiagnosticsCallback IBinder died.");
+ unregisterConnectivityDiagnosticsCallback(mCb);
+ }
+ }
+
+ private void handleRegisterConnectivityDiagnosticsCallback(
+ @NonNull ConnectivityDiagnosticsCallbackInfo cbInfo) {
+ ensureRunningOnConnectivityServiceThread();
+
+ final IConnectivityDiagnosticsCallback cb = cbInfo.mCb;
+ final NetworkRequestInfo nri = cbInfo.mRequestInfo;
+
+ // This means that the client registered the same callback multiple times. Do
+ // not override the previous entry, and exit silently.
+ if (mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
+ if (VDBG) log("Diagnostics callback is already registered");
+
+ // Decrement the reference count for this NetworkRequestInfo. The reference count is
+ // incremented when the NetworkRequestInfo is created as part of
+ // enforceRequestCountLimit().
+ decrementNetworkRequestPerUidCount(nri);
+ return;
+ }
+
+ mConnectivityDiagnosticsCallbacks.put(cb, cbInfo);
+
+ try {
+ cb.asBinder().linkToDeath(cbInfo, 0);
+ } catch (RemoteException e) {
+ cbInfo.binderDied();
+ }
+ }
+
+ private void handleUnregisterConnectivityDiagnosticsCallback(
+ @NonNull IConnectivityDiagnosticsCallback cb, int uid) {
+ ensureRunningOnConnectivityServiceThread();
+
+ if (!mConnectivityDiagnosticsCallbacks.containsKey(cb)) {
+ if (VDBG) log("Removing diagnostics callback that is not currently registered");
+ return;
+ }
+
+ final NetworkRequestInfo nri = mConnectivityDiagnosticsCallbacks.get(cb).mRequestInfo;
+
+ if (uid != nri.mUid) {
+ if (VDBG) loge("Different uid than registrant attempting to unregister cb");
+ return;
+ }
+
+ cb.asBinder().unlinkToDeath(mConnectivityDiagnosticsCallbacks.remove(cb), 0);
+ }
+
@Override
public void registerConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback callback, @NonNull NetworkRequest request) {
- // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
- throw new UnsupportedOperationException(
- "registerConnectivityDiagnosticsCallback not yet implemented");
+ if (request.legacyType != TYPE_NONE) {
+ throw new IllegalArgumentException("ConnectivityManager.TYPE_* are deprecated."
+ + " Please use NetworkCapabilities instead.");
+ }
+
+ // This NetworkCapabilities is only used for matching to Networks. Clear out its owner uid
+ // and administrator uids to be safe.
+ final NetworkCapabilities nc = new NetworkCapabilities(request.networkCapabilities);
+ restrictRequestUidsForCaller(nc);
+
+ final NetworkRequest requestWithId =
+ new NetworkRequest(
+ nc, TYPE_NONE, nextNetworkRequestId(), NetworkRequest.Type.LISTEN);
+
+ // NetworkRequestInfos created here count towards MAX_NETWORK_REQUESTS_PER_UID limit.
+ //
+ // nri is not bound to the death of callback. Instead, callback.bindToDeath() is set in
+ // handleRegisterConnectivityDiagnosticsCallback(). nri will be cleaned up as part of the
+ // callback's binder death.
+ final NetworkRequestInfo nri = new NetworkRequestInfo(requestWithId);
+ final ConnectivityDiagnosticsCallbackInfo cbInfo =
+ new ConnectivityDiagnosticsCallbackInfo(callback, nri);
+
+ mConnectivityDiagnosticsHandler.sendMessage(
+ mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler
+ .EVENT_REGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
+ cbInfo));
}
@Override
public void unregisterConnectivityDiagnosticsCallback(
@NonNull IConnectivityDiagnosticsCallback callback) {
- // TODO(b/146444622): implement register IConnectivityDiagnosticsCallback functionality
- throw new UnsupportedOperationException(
- "unregisterConnectivityDiagnosticsCallback not yet implemented");
+ mConnectivityDiagnosticsHandler.sendMessage(
+ mConnectivityDiagnosticsHandler.obtainMessage(
+ ConnectivityDiagnosticsHandler
+ .EVENT_UNREGISTER_CONNECTIVITY_DIAGNOSTICS_CALLBACK,
+ Binder.getCallingUid(),
+ 0,
+ callback));
}
}
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index e342dd7..50843b0 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -2644,7 +2644,12 @@
if (noGPSLocation == null && lastNoGPSLocation != null) {
// New location has no no-GPS location: adopt last no-GPS location. This is set
// directly into location because we do not want to notify COARSE clients.
- location.setExtraLocation(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
+ Bundle extras = location.getExtras();
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putParcelable(Location.EXTRA_NO_GPS_LOCATION, lastNoGPSLocation);
+ location.setExtras(extras);
}
}
lastLocation.set(location);
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index 9d4c783..1bb3c3a 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -86,12 +86,12 @@
import android.util.Slog;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.IBatteryStats;
import com.android.internal.util.DumpUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.HexDump;
import com.android.internal.util.Preconditions;
@@ -412,8 +412,8 @@
getBatteryStats().noteMobileRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
- StatsLog.write_non_chained(StatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, null,
- powerState);
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.MOBILE_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
}
@@ -424,8 +424,8 @@
getBatteryStats().noteWifiRadioPowerState(powerState, tsNanos, uid);
} catch (RemoteException e) {
}
- StatsLog.write_non_chained(StatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, null,
- powerState);
+ FrameworkStatsLog.write_non_chained(
+ FrameworkStatsLog.WIFI_RADIO_POWER_STATE_CHANGED, uid, null, powerState);
}
}
diff --git a/services/core/java/com/android/server/RescueParty.java b/services/core/java/com/android/server/RescueParty.java
index bacffb6..3e5c278 100644
--- a/services/core/java/com/android/server/RescueParty.java
+++ b/services/core/java/com/android/server/RescueParty.java
@@ -393,8 +393,8 @@
@Override
public int onHealthCheckFailed(@Nullable VersionedPackage failedPackage,
@FailureReasons int failureReason) {
- if (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
- || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING) {
+ if (!isDisabled() && (failureReason == PackageWatchdog.FAILURE_REASON_APP_CRASH
+ || failureReason == PackageWatchdog.FAILURE_REASON_APP_NOT_RESPONDING)) {
return mapRescueLevelToUserImpact(getNextRescueLevel());
} else {
return PackageHealthObserverImpact.USER_IMPACT_NONE;
diff --git a/services/core/java/com/android/server/ServiceWatcher.java b/services/core/java/com/android/server/ServiceWatcher.java
index 14cd3a5..b43ae36 100644
--- a/services/core/java/com/android/server/ServiceWatcher.java
+++ b/services/core/java/com/android/server/ServiceWatcher.java
@@ -49,6 +49,8 @@
import com.android.internal.content.PackageMonitor;
import com.android.internal.util.Preconditions;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.Callable;
@@ -183,9 +185,7 @@
// write from handler thread only, read anywhere
private volatile ServiceInfo mServiceInfo;
-
- // read/write from handler thread only
- private IBinder mBinder;
+ private volatile IBinder mBinder;
public ServiceWatcher(Context context, Handler handler, String action,
@Nullable BinderRunner onBind, @Nullable Runnable onUnbind,
@@ -345,20 +345,25 @@
}
mBinder = binder;
+
+ // we always run the on bind callback even if we know that the binder is dead already so
+ // that there are always balance pairs of bind/unbind callbacks
if (mOnBind != null) {
- runOnBinder(mOnBind);
- }
- }
-
- @Override
- public void onBindingDied(ComponentName component) {
- Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
-
- if (D) {
- Log.i(TAG, getLogPrefix() + " " + component.toShortString() + " died");
+ try {
+ mOnBind.run(binder);
+ } catch (RuntimeException | RemoteException e) {
+ // binders may propagate some specific non-RemoteExceptions from the other side
+ // through the binder as well - we cannot allow those to crash the system server
+ Log.e(TAG, getLogPrefix() + " exception running on " + mServiceInfo, e);
+ }
}
- onBestServiceChanged(true);
+ try {
+ // setting the binder to null lets us skip queued transactions
+ binder.linkToDeath(() -> mBinder = null, 0);
+ } catch (RemoteException e) {
+ mBinder = null;
+ }
}
@Override
@@ -375,6 +380,17 @@
}
}
+ @Override
+ public void onBindingDied(ComponentName component) {
+ Preconditions.checkState(Looper.myLooper() == mHandler.getLooper());
+
+ if (D) {
+ Log.i(TAG, getLogPrefix() + " " + component.toShortString() + " died");
+ }
+
+ onBestServiceChanged(true);
+ }
+
private void onUserSwitched(@UserIdInt int userId) {
mCurrentUserId = userId;
onBestServiceChanged(false);
@@ -398,7 +414,7 @@
* RemoteException thrown during execution.
*/
public final void runOnBinder(BinderRunner runner) {
- runOnHandler(() -> {
+ mHandler.post(() -> {
if (mBinder == null) {
return;
}
@@ -447,14 +463,6 @@
}
}
- private void runOnHandler(Runnable r) {
- if (Looper.myLooper() == mHandler.getLooper()) {
- r.run();
- } else {
- mHandler.post(r);
- }
- }
-
private <T> T runOnHandlerBlocking(Callable<T> c)
throws InterruptedException, TimeoutException {
if (Looper.myLooper() == mHandler.getLooper()) {
@@ -489,4 +497,12 @@
public String toString() {
return mServiceInfo.toString();
}
+
+ /**
+ * Dump for debugging.
+ */
+ public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+ pw.println("service=" + mServiceInfo);
+ pw.println("connected=" + (mBinder != null));
+ }
}
diff --git a/services/core/java/com/android/server/TelephonyRegistry.java b/services/core/java/com/android/server/TelephonyRegistry.java
index 36dd017..139a871 100644
--- a/services/core/java/com/android/server/TelephonyRegistry.java
+++ b/services/core/java/com/android/server/TelephonyRegistry.java
@@ -897,6 +897,13 @@
if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH)
!= 0) {
updateReportSignalStrengthDecision(r.subId);
+ try {
+ if (mSignalStrength[phoneId] != null) {
+ r.callback.onSignalStrengthsChanged(mSignalStrength[phoneId]);
+ }
+ } catch (RemoteException ex) {
+ remove(r.binder);
+ }
}
if (validateEventsAndUserLocked(r, PhoneStateListener.LISTEN_CELL_INFO)) {
try {
@@ -1326,9 +1333,10 @@
log("notifySignalStrengthForPhoneId: r=" + r + " subId=" + subId
+ " phoneId=" + phoneId + " ss=" + signalStrength);
}
- if (r.matchPhoneStateListenerEvent(
- PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) &&
- idMatch(r.subId, subId, phoneId)) {
+ if ((r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTHS)
+ || r.matchPhoneStateListenerEvent(
+ PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH))
+ && idMatch(r.subId, subId, phoneId)) {
try {
if (DBG) {
log("notifySignalStrengthForPhoneId: callback.onSsS r=" + r
@@ -1341,7 +1349,7 @@
}
}
if (r.matchPhoneStateListenerEvent(PhoneStateListener.LISTEN_SIGNAL_STRENGTH) &&
- idMatch(r.subId, subId, phoneId)){
+ idMatch(r.subId, subId, phoneId)) {
try {
int gsmSignalStrength = signalStrength.getGsmSignalStrength();
int ss = (gsmSignalStrength == 99 ? -1 : gsmSignalStrength);
@@ -2542,6 +2550,11 @@
android.Manifest.permission.READ_ACTIVE_EMERGENCY_SESSION, null);
}
+ if ((events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
+ mContext.enforceCallingOrSelfPermission(
+ android.Manifest.permission.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH, null);
+ }
+
if ((events & READ_PRIVILEGED_PHONE_STATE_PERMISSION_MASK) != 0) {
mContext.enforceCallingOrSelfPermission(
android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE, null);
@@ -2657,7 +2670,8 @@
}
}
- if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0) {
+ if ((events & PhoneStateListener.LISTEN_SIGNAL_STRENGTHS) != 0
+ || (events & PhoneStateListener.LISTEN_ALWAYS_REPORTED_SIGNAL_STRENGTH) != 0) {
try {
if (mSignalStrength[phoneId] != null) {
SignalStrength signalStrength = mSignalStrength[phoneId];
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 8cf620d..6560777 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -355,7 +355,6 @@
import com.android.server.firewall.IntentFirewall;
import com.android.server.job.JobSchedulerInternal;
import com.android.server.pm.Installer;
-import com.android.server.pm.Installer.InstallerException;
import com.android.server.pm.permission.PermissionManagerServiceInternal;
import com.android.server.uri.GrantUri;
import com.android.server.uri.UriGrantsManagerInternal;
@@ -5270,26 +5269,6 @@
mCallFinishBooting = false;
}
- ArraySet<String> completedIsas = new ArraySet<String>();
- for (String abi : Build.SUPPORTED_ABIS) {
- ZYGOTE_PROCESS.establishZygoteConnectionForAbi(abi);
- final String instructionSet = VMRuntime.getInstructionSet(abi);
- if (!completedIsas.contains(instructionSet)) {
- try {
- mInstaller.markBootComplete(VMRuntime.getInstructionSet(abi));
- } catch (InstallerException e) {
- if (!VMRuntime.didPruneDalvikCache()) {
- // This is technically not the right filter, as different zygotes may
- // have made different pruning decisions. But the log is best effort,
- // anyways.
- Slog.w(TAG, "Unable to mark boot complete for abi: " + abi + " (" +
- e.getMessage() +")");
- }
- }
- completedIsas.add(instructionSet);
- }
- }
-
// Let the ART runtime in zygote and system_server know that the boot completed.
ZYGOTE_PROCESS.bootCompleted();
VMRuntime.bootCompleted();
@@ -6876,6 +6855,7 @@
}
}
+ ProcessRecord dyingProc = null;
if (cpr != null && cpr.proc != null) {
providerRunning = !cpr.proc.killed;
@@ -6885,14 +6865,9 @@
// (See the commit message on I2c4ba1e87c2d47f2013befff10c49b3dc337a9a7 to see
// how to test this case.)
if (cpr.proc.killed && cpr.proc.killedByAm) {
- final long iden = Binder.clearCallingIdentity();
- try {
- mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc, false,
- cpr.uid == cpr.proc.uid || cpr.proc.isolated,
- "getContentProviderImpl: %s (killedByAm)", startTime);
- } finally {
- Binder.restoreCallingIdentity(iden);
- }
+ Slog.wtf(TAG, cpr.proc.toString() + " was killed by AM but isn't really dead");
+ // Now we are going to wait for the death before starting the new process.
+ dyingProc = cpr.proc;
}
}
@@ -6993,18 +6968,18 @@
// has been killed on us. We need to wait for a new
// process to be started, and make sure its death
// doesn't kill our process.
- Slog.i(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ Slog.wtf(TAG, "Existing provider " + cpr.name.flattenToShortString()
+ " is crashing; detaching " + r);
boolean lastRef = decProviderCountLocked(conn, cpr, token, stable);
- mProcessList.killProcAndWaitIfNecessaryLocked(cpr.proc,
- false, true, "getContentProviderImpl: %s", startTime);
if (!lastRef) {
// This wasn't the last ref our process had on
- // the provider... we have now been killed, bail.
+ // the provider... we will be killed during cleaning up, bail.
return null;
}
+ // We'll just start a new process to host the content provider
providerRunning = false;
conn = null;
+ dyingProc = cpr.proc;
} else {
cpr.proc.verifiedAdj = cpr.proc.setAdj;
}
@@ -7080,7 +7055,7 @@
checkTime(startTime, "getContentProviderImpl: before getProviderByClass");
cpr = mProviderMap.getProviderByClass(comp, userId);
checkTime(startTime, "getContentProviderImpl: after getProviderByClass");
- final boolean firstClass = cpr == null;
+ boolean firstClass = cpr == null;
if (firstClass) {
final long ident = Binder.clearCallingIdentity();
@@ -7111,6 +7086,13 @@
} finally {
Binder.restoreCallingIdentity(ident);
}
+ } else if (dyingProc == cpr.proc) {
+ // The old stable connection's client should be killed during proc cleaning up,
+ // so do not re-use the old ContentProviderRecord, otherwise the new clients
+ // could get killed unexpectedly.
+ cpr = new ContentProviderRecord(cpr);
+ // This is sort of "firstClass"
+ firstClass = true;
}
checkTime(startTime, "getContentProviderImpl: now have ContentProviderRecord");
@@ -14270,10 +14252,19 @@
cpr.launchingApp = null;
cpr.notifyAll();
}
- mProviderMap.removeProviderByClass(cpr.name, UserHandle.getUserId(cpr.uid));
+ final int userId = UserHandle.getUserId(cpr.uid);
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByClass(cpr.name, userId) == cpr) {
+ mProviderMap.removeProviderByClass(cpr.name, userId);
+ }
String names[] = cpr.info.authority.split(";");
for (int j = 0; j < names.length; j++) {
- mProviderMap.removeProviderByName(names[j], UserHandle.getUserId(cpr.uid));
+ // Don't remove from provider map if it doesn't match
+ // could be a new content provider is starting
+ if (mProviderMap.getProviderByName(names[j], userId) == cpr) {
+ mProviderMap.removeProviderByName(names[j], userId);
+ }
}
}
@@ -14368,6 +14359,10 @@
// Remove published content providers.
for (int i = app.pubProviders.size() - 1; i >= 0; i--) {
ContentProviderRecord cpr = app.pubProviders.valueAt(i);
+ if (cpr.proc != app) {
+ // If the hosting process record isn't really us, bail out
+ continue;
+ }
final boolean alwaysRemove = app.bad || !allowRestart;
final boolean inLaunching = removeDyingProviderLocked(app, cpr, alwaysRemove);
if (!alwaysRemove && inLaunching && cpr.hasConnectionOrHandle()) {
@@ -14453,6 +14448,27 @@
mUiHandler.obtainMessage(DISPATCH_PROCESS_DIED_UI_MSG, app.pid, app.info.uid,
null).sendToTarget();
+ // If this is a precede instance of another process instance
+ allowRestart = true;
+ synchronized (app) {
+ if (app.mSuccessor != null) {
+ // We don't allow restart with this ProcessRecord now,
+ // because we have created a new one already.
+ allowRestart = false;
+ // If it's persistent, add the successor to mPersistentStartingProcesses
+ if (app.isPersistent() && !app.removed) {
+ if (mPersistentStartingProcesses.indexOf(app.mSuccessor) < 0) {
+ mPersistentStartingProcesses.add(app.mSuccessor);
+ }
+ }
+ // clean up the field so the successor's proc starter could proceed.
+ app.mSuccessor.mPrecedence = null;
+ app.mSuccessor = null;
+ // Notify if anyone is waiting for it.
+ app.notifyAll();
+ }
+ }
+
// If the caller is restarting this app, then leave it in its
// current lists and let the caller take care of it.
if (restarting) {
@@ -14482,7 +14498,7 @@
mAtmInternal.onCleanUpApplicationRecord(app.getWindowProcessController());
mProcessList.noteProcessDiedLocked(app);
- if (restart && !app.isolated) {
+ if (restart && allowRestart && !app.isolated) {
// We have components that still need to be running in the
// process, so re-launch it.
if (index < 0) {
diff --git a/services/core/java/com/android/server/am/AppExitInfoTracker.java b/services/core/java/com/android/server/am/AppExitInfoTracker.java
index bab133f..60aba27 100644
--- a/services/core/java/com/android/server/am/AppExitInfoTracker.java
+++ b/services/core/java/com/android/server/am/AppExitInfoTracker.java
@@ -17,6 +17,7 @@
package com.android.server.am;
import static android.app.ActivityManager.RunningAppProcessInfo.procStateToImportance;
+import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PROCESSES;
import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -52,6 +53,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.ProcessMap;
import com.android.server.IoThread;
+import com.android.server.ServiceThread;
import com.android.server.SystemServiceManager;
import java.io.File;
@@ -179,9 +181,12 @@
mRawRecordsPool = new SynchronizedPool<ApplicationExitInfo>(APP_EXIT_RAW_INFO_POOL_SIZE);
}
- void init(ActivityManagerService service, Looper looper) {
+ void init(ActivityManagerService service) {
mService = service;
- mKillHandler = new KillHandler(looper);
+ ServiceThread thread = new ServiceThread(TAG + ":killHandler",
+ THREAD_PRIORITY_BACKGROUND, true /* allowIo */);
+ thread.start();
+ mKillHandler = new KillHandler(thread.getLooper());
mProcExitInfoFile = new File(SystemServiceManager.ensureSystemDir(), APP_EXIT_INFO_FILE);
mAppExitInfoHistoryListSize = service.mContext.getResources().getInteger(
diff --git a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
index d5fc14b..39f79ca 100644
--- a/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
+++ b/services/core/java/com/android/server/am/BatteryExternalStatsWorker.java
@@ -550,7 +550,6 @@
return data;
}
}
- Slog.e(TAG, "no controller energy info supplied for " + receiver.getName());
} catch (TimeoutException e) {
Slog.w(TAG, "timeout reading " + receiver.getName() + " stats");
}
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 143424d..b107626 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -36,7 +36,9 @@
import static android.app.ActivityManager.PROCESS_STATE_SERVICE;
import static android.app.ActivityManager.PROCESS_STATE_TOP;
import static android.app.ActivityManager.PROCESS_STATE_TRANSIENT_BACKGROUND;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
import static android.os.Process.SCHED_OTHER;
import static android.os.Process.THREAD_GROUP_BACKGROUND;
import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -70,7 +72,6 @@
import android.app.ActivityManager;
import android.app.ApplicationExitInfo;
import android.app.usage.UsageEvents;
-import android.compat.Compatibility;
import android.compat.annotation.ChangeId;
import android.compat.annotation.Disabled;
import android.compat.annotation.EnabledAfter;
@@ -82,6 +83,7 @@
import android.os.PowerManagerInternal;
import android.os.Process;
import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
@@ -93,6 +95,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.procstats.ProcessStats;
+import com.android.internal.compat.IPlatformCompat;
import com.android.server.LocalServices;
import com.android.server.ServiceThread;
import com.android.server.wm.ActivityServiceConnectionsHolder;
@@ -210,6 +213,8 @@
private ActiveUids mTmpUidRecords;
private ArrayDeque<ProcessRecord> mTmpQueue;
+ private final IPlatformCompat mPlatformCompat;
+
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
this(service, processList, activeUids, createAdjusterThread());
}
@@ -256,6 +261,8 @@
mTmpQueue = new ArrayDeque<ProcessRecord>(mConstants.CUR_MAX_CACHED_PROCESSES << 1);
mNumSlots = ((ProcessList.CACHED_APP_MAX_ADJ - ProcessList.CACHED_APP_MIN_ADJ + 1) >> 1)
/ ProcessList.CACHED_APP_IMPORTANCE_LEVELS;
+ IBinder b = ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE);
+ mPlatformCompat = IPlatformCompat.Stub.asInterface(b);
}
void initSettings() {
@@ -1492,8 +1499,23 @@
!= 0 ? TEMP_PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
}
if (s.mAllowWhileInUsePermissionInFgs) {
- capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
- | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ boolean enabled = false;
+ try {
+ enabled = mPlatformCompat.isChangeEnabled(
+ CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
+ } catch (RemoteException e) {
+ }
+ if (enabled) {
+ capabilityFromFGS |=
+ (fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
+ != 0 ? PROCESS_CAPABILITY_FOREGROUND_CAMERA : 0;
+ capabilityFromFGS |=
+ (fgsType & FOREGROUND_SERVICE_TYPE_MICROPHONE)
+ != 0 ? PROCESS_CAPABILITY_FOREGROUND_MICROPHONE : 0;
+ } else {
+ capabilityFromFGS |= PROCESS_CAPABILITY_FOREGROUND_CAMERA
+ | PROCESS_CAPABILITY_FOREGROUND_MICROPHONE;
+ }
}
}
@@ -1667,7 +1689,13 @@
// Go at most to BOUND_TOP, unless requested to elevate
// to client's state.
clientProcState = PROCESS_STATE_BOUND_TOP;
- if (Compatibility.isChangeEnabled(PROCESS_CAPABILITY_CHANGE_ID)) {
+ boolean enabled = false;
+ try {
+ enabled = mPlatformCompat.isChangeEnabled(
+ PROCESS_CAPABILITY_CHANGE_ID, client.info);
+ } catch (RemoteException e) {
+ }
+ if (enabled) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
capability = PROCESS_CAPABILITY_ALL;
diff --git a/services/core/java/com/android/server/am/ProcessList.java b/services/core/java/com/android/server/am/ProcessList.java
index 7c36a7e..3c7d6b8 100644
--- a/services/core/java/com/android/server/am/ProcessList.java
+++ b/services/core/java/com/android/server/am/ProcessList.java
@@ -739,7 +739,7 @@
mSystemServerSocketForZygote.getFileDescriptor(),
EVENT_INPUT, this::handleZygoteMessages);
}
- mAppExitInfoTracker.init(mService, sKillThread.getLooper());
+ mAppExitInfoTracker.init(mService);
mImperceptibleKillRunner = new ImperceptibleKillRunner(sKillThread.getLooper());
}
}
@@ -1842,26 +1842,9 @@
if (mService.mConstants.FLAG_PROCESS_START_ASYNC) {
if (DEBUG_PROCESSES) Slog.i(TAG_PROCESSES,
"Posting procStart msg for " + app.toShortString());
- mService.mProcStartHandler.post(() -> {
- try {
- final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
- entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
- app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
- synchronized (mService) {
- handleProcessStartedLocked(app, startResult, startSeq);
- }
- } catch (RuntimeException e) {
- synchronized (mService) {
- Slog.e(ActivityManagerService.TAG, "Failure starting process "
- + app.processName, e);
- mPendingStarts.remove(startSeq);
- app.pendingStart = false;
- mService.forceStopPackageLocked(app.info.packageName,
- UserHandle.getAppId(app.uid),
- false, false, true, false, false, app.userId, "start failure");
- }
- }
- });
+ mService.mProcStartHandler.post(() -> handleProcessStart(
+ app, entryPoint, gids, runtimeFlags, mountExternal, requiredAbi,
+ instructionSet, invokeWith, startSeq));
return true;
} else {
try {
@@ -1882,6 +1865,66 @@
}
}
+ /**
+ * Main handler routine to start the given process from the ProcStartHandler.
+ *
+ * <p>Note: this function doesn't hold the global AM lock intentionally.</p>
+ */
+ private void handleProcessStart(final ProcessRecord app, final String entryPoint,
+ final int[] gids, final int runtimeFlags, final int mountExternal,
+ final String requiredAbi, final String instructionSet,
+ final String invokeWith, final long startSeq) {
+ // If there is a precede instance of the process, wait for its death with a timeout.
+ // Use local reference since we are not using locks here
+ final ProcessRecord precedence = app.mPrecedence;
+ if (precedence != null) {
+ final int pid = precedence.pid;
+ long now = System.currentTimeMillis();
+ final long end = now + PROC_KILL_TIMEOUT;
+ try {
+ Process.waitForProcessDeath(pid, PROC_KILL_TIMEOUT);
+ // It's killed successfully, but we'd make sure the cleanup work is done.
+ synchronized (precedence) {
+ if (app.mPrecedence != null) {
+ now = System.currentTimeMillis();
+ if (now < end) {
+ try {
+ precedence.wait(end - now);
+ } catch (InterruptedException e) {
+ }
+ }
+ }
+ if (app.mPrecedence != null) {
+ // The cleanup work hasn't be done yet, let's log it and continue.
+ Slog.w(TAG, precedence + " has died, but its cleanup isn't done");
+ }
+ }
+ } catch (Exception e) {
+ // It's still alive...
+ Slog.wtf(TAG, precedence.toString() + " refused to die, but we need to launch "
+ + app);
+ }
+ }
+ try {
+ final Process.ProcessStartResult startResult = startProcess(app.hostingRecord,
+ entryPoint, app, app.startUid, gids, runtimeFlags, mountExternal,
+ app.seInfo, requiredAbi, instructionSet, invokeWith, app.startTime);
+ synchronized (mService) {
+ handleProcessStartedLocked(app, startResult, startSeq);
+ }
+ } catch (RuntimeException e) {
+ synchronized (mService) {
+ Slog.e(ActivityManagerService.TAG, "Failure starting process "
+ + app.processName, e);
+ mPendingStarts.remove(startSeq);
+ app.pendingStart = false;
+ mService.forceStopPackageLocked(app.info.packageName,
+ UserHandle.getAppId(app.uid),
+ false, false, true, false, false, app.userId, "start failure");
+ }
+ }
+ }
+
@GuardedBy("mService")
public void killAppZygoteIfNeededLocked(AppZygote appZygote, boolean force) {
final ApplicationInfo appInfo = appZygote.getAppInfo();
@@ -2136,6 +2179,7 @@
+ " app=" + app + " knownToBeDead=" + knownToBeDead
+ " thread=" + (app != null ? app.thread : null)
+ " pid=" + (app != null ? app.pid : -1));
+ ProcessRecord precedence = null;
if (app != null && app.pid > 0) {
if ((!knownToBeDead && !app.killed) || app.thread == null) {
// We already have the app running, or are waiting for it to
@@ -2150,9 +2194,15 @@
// An application record is attached to a previous process,
// clean it up now.
if (DEBUG_PROCESSES) Slog.v(TAG_PROCESSES, "App died: " + app);
- // do the killing
- killProcAndWaitIfNecessaryLocked(app, true, app.uid == info.uid || app.isolated,
- "startProcess: bad proc running, killing: %s", startTime);
+ checkSlow(startTime, "startProcess: bad proc running, killing");
+ ProcessList.killProcessGroup(app.uid, app.pid);
+ checkSlow(startTime, "startProcess: done killing old proc");
+
+ Slog.wtf(TAG_PROCESSES, app.toString() + " is attached to a previous process");
+ // We are not going to re-use the ProcessRecord, as we haven't dealt with the cleanup
+ // routine of it yet, but we'd set it as the precedence of the new process.
+ precedence = app;
+ app = null;
}
if (app == null) {
@@ -2166,6 +2216,10 @@
app.crashHandler = crashHandler;
app.isolatedEntryPoint = entryPoint;
app.isolatedEntryPointArgs = entryPointArgs;
+ if (precedence != null) {
+ app.mPrecedence = precedence;
+ precedence.mSuccessor = app;
+ }
checkSlow(startTime, "startProcess: done creating new process record");
} else {
// If this is a new package in the process, add the package to the list
@@ -2193,44 +2247,6 @@
return success ? app : null;
}
- /**
- * Kill (if asked to) and wait for the given process died if necessary
- * @param app - The process record to kill
- * @param doKill - Kill the given process record
- * @param wait - Wait for the death of the given process
- * @param formatString - The log message for slow operation
- * @param startTime - The start timestamp of the operation
- */
- @GuardedBy("mService")
- void killProcAndWaitIfNecessaryLocked(final ProcessRecord app, final boolean doKill,
- final boolean wait, final String formatString, final long startTime) {
-
- checkSlow(startTime, String.format(formatString, "before appDied"));
-
- if (doKill) {
- // do the killing
- ProcessList.killProcessGroup(app.uid, app.pid);
- noteAppKill(app, ApplicationExitInfo.REASON_OTHER,
- ApplicationExitInfo.SUBREASON_UNKNOWN,
- String.format(formatString, ""));
- }
-
- // wait for the death
- if (wait) {
- try {
- Process.waitForProcessDeath(app.pid, PROC_KILL_TIMEOUT);
- } catch (Exception e) {
- // Maybe the process goes into zombie, use an expensive API to check again.
- if (mService.isProcessAliveLocked(app)) {
- Slog.w(TAG, String.format(formatString,
- "waiting for app killing timed out"));
- }
- }
- }
-
- checkSlow(startTime, String.format(formatString, "after appDied"));
- }
-
@GuardedBy("mService")
private String isProcStartValidLocked(ProcessRecord app, long expectedStartSeq) {
StringBuilder sb = null;
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index b0c0aae..fc33c25 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -320,6 +320,14 @@
// set of disabled compat changes for the process (all others are enabled)
long[] mDisabledCompatChanges;
+ // The precede instance of the process, which would exist when the previous process is killed
+ // but not fully dead yet; in this case, the new instance of the process should be held until
+ // this precede instance is fully dead.
+ volatile ProcessRecord mPrecedence;
+ // The succeeding instance of the process, which is going to be started after this process
+ // is killed successfully.
+ volatile ProcessRecord mSuccessor;
+
// Cached task info for OomAdjuster
private static final int VALUE_INVALID = -1;
private static final int VALUE_FALSE = 0;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8f6bd21..b2548af 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -1068,6 +1068,27 @@
}
}
+ // Restore capture policies
+ synchronized (mPlaybackMonitor) {
+ HashMap<Integer, Integer> allowedCapturePolicies =
+ mPlaybackMonitor.getAllAllowedCapturePolicies();
+ for (HashMap.Entry<Integer, Integer> entry : allowedCapturePolicies.entrySet()) {
+ int result = AudioSystem.setAllowedCapturePolicy(
+ entry.getKey(),
+ AudioAttributes.capturePolicyToFlags(entry.getValue(), 0x0));
+ if (result != AudioSystem.AUDIO_STATUS_OK) {
+ Log.e(TAG, "Failed to restore capture policy, uid: "
+ + entry.getKey() + ", capture policy: " + entry.getValue()
+ + ", result: " + result);
+ // When restoring capture policy failed, set the capture policy as
+ // ALLOW_CAPTURE_BY_ALL, which will result in removing the cached
+ // capture policy in PlaybackActivityMonitor.
+ mPlaybackMonitor.setAllowedCapturePolicy(
+ entry.getKey(), AudioAttributes.ALLOW_CAPTURE_BY_ALL);
+ }
+ }
+ }
+
onIndicateSystemReady();
// indicate the end of reconfiguration phase to audio HAL
AudioSystem.setParameters("restarting=false");
@@ -7298,6 +7319,43 @@
mPlaybackMonitor.releasePlayer(piid, Binder.getCallingUid());
}
+ /**
+ * Specifies whether the audio played by this app may or may not be captured by other apps or
+ * the system.
+ *
+ * @param capturePolicy one of
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+ * @return AudioSystem.AUDIO_STATUS_OK if set allowed capture policy succeed.
+ * @throws IllegalArgumentException if the argument is not a valid value.
+ */
+ public int setAllowedCapturePolicy(int capturePolicy) {
+ int callingUid = Binder.getCallingUid();
+ int flags = AudioAttributes.capturePolicyToFlags(capturePolicy, 0x0);
+ final long identity = Binder.clearCallingIdentity();
+ synchronized (mPlaybackMonitor) {
+ int result = AudioSystem.setAllowedCapturePolicy(callingUid, flags);
+ if (result == AudioSystem.AUDIO_STATUS_OK) {
+ mPlaybackMonitor.setAllowedCapturePolicy(callingUid, capturePolicy);
+ }
+ Binder.restoreCallingIdentity(identity);
+ return result;
+ }
+ }
+
+ /**
+ * Return the capture policy.
+ * @return the cached capture policy for the calling uid.
+ */
+ public int getAllowedCapturePolicy() {
+ int callingUid = Binder.getCallingUid();
+ final long identity = Binder.clearCallingIdentity();
+ int capturePolicy = mPlaybackMonitor.getAllowedCapturePolicy(callingUid);
+ Binder.restoreCallingIdentity(identity);
+ return capturePolicy;
+ }
+
//======================
// Audio device management
//======================
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index f8ba55b..98f409e 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -160,6 +160,12 @@
new AudioPlaybackConfiguration(pic, newPiid,
Binder.getCallingUid(), Binder.getCallingPid());
apc.init();
+ synchronized (mAllowedCapturePolicies) {
+ int uid = apc.getClientUid();
+ if (mAllowedCapturePolicies.containsKey(uid)) {
+ updateAllowedCapturePolicy(apc, mAllowedCapturePolicies.get(uid));
+ }
+ }
sEventLogger.log(new NewPlayerEvent(apc));
synchronized(mPlayerLock) {
mPlayers.put(newPiid, apc);
@@ -169,6 +175,13 @@
public void playerAttributes(int piid, @NonNull AudioAttributes attr, int binderUid) {
final boolean change;
+ synchronized (mAllowedCapturePolicies) {
+ if (mAllowedCapturePolicies.containsKey(binderUid)
+ && attr.getAllowedCapturePolicy() < mAllowedCapturePolicies.get(binderUid)) {
+ attr = new AudioAttributes.Builder(attr)
+ .setAllowedCapturePolicy(mAllowedCapturePolicies.get(binderUid)).build();
+ }
+ }
synchronized(mPlayerLock) {
final AudioPlaybackConfiguration apc = mPlayers.get(new Integer(piid));
if (checkConfigurationCaller(piid, apc, binderUid)) {
@@ -284,6 +297,69 @@
}
}
+ /**
+ * A map of uid to capture policy.
+ */
+ private final HashMap<Integer, Integer> mAllowedCapturePolicies =
+ new HashMap<Integer, Integer>();
+
+ /**
+ * Cache allowed capture policy, which specifies whether the audio played by the app may or may
+ * not be captured by other apps or the system.
+ *
+ * @param uid the uid of requested app
+ * @param capturePolicy one of
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_ALL},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_SYSTEM},
+ * {@link AudioAttributes#ALLOW_CAPTURE_BY_NONE}.
+ */
+ public void setAllowedCapturePolicy(int uid, int capturePolicy) {
+ synchronized (mAllowedCapturePolicies) {
+ if (capturePolicy == AudioAttributes.ALLOW_CAPTURE_BY_ALL) {
+ // When the capture policy is ALLOW_CAPTURE_BY_ALL, it is okay to
+ // remove it from cached capture policy as it is the default value.
+ mAllowedCapturePolicies.remove(uid);
+ return;
+ } else {
+ mAllowedCapturePolicies.put(uid, capturePolicy);
+ }
+ }
+ synchronized (mPlayerLock) {
+ for (AudioPlaybackConfiguration apc : mPlayers.values()) {
+ if (apc.getClientUid() == uid) {
+ updateAllowedCapturePolicy(apc, capturePolicy);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return the capture policy for given uid.
+ * @param uid the uid to query its cached capture policy.
+ * @return cached capture policy for given uid or AudioAttributes.ALLOW_CAPTURE_BY_ALL
+ * if there is not cached capture policy.
+ */
+ public int getAllowedCapturePolicy(int uid) {
+ return mAllowedCapturePolicies.getOrDefault(uid, AudioAttributes.ALLOW_CAPTURE_BY_ALL);
+ }
+
+ /**
+ * Return all cached capture policies.
+ */
+ public HashMap<Integer, Integer> getAllAllowedCapturePolicies() {
+ return mAllowedCapturePolicies;
+ }
+
+ private void updateAllowedCapturePolicy(AudioPlaybackConfiguration apc, int capturePolicy) {
+ AudioAttributes attr = apc.getAudioAttributes();
+ if (attr.getAllowedCapturePolicy() >= capturePolicy) {
+ return;
+ }
+ apc.handleAudioAttributesEvent(
+ new AudioAttributes.Builder(apc.getAudioAttributes())
+ .setAllowedCapturePolicy(capturePolicy).build());
+ }
+
// Implementation of AudioPlaybackConfiguration.PlayerDeathMonitor
@Override
public void playerDeath(int piid) {
@@ -331,6 +407,12 @@
// log
sEventLogger.dump(pw);
}
+ synchronized (mAllowedCapturePolicies) {
+ pw.println("\n allowed capture policies:");
+ for (HashMap.Entry<Integer, Integer> entry : mAllowedCapturePolicies.entrySet()) {
+ pw.println(" uid: " + entry.getKey() + " policy: " + entry.getValue());
+ }
+ }
}
/**
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
index ad20ed8..ad72166 100644
--- a/services/core/java/com/android/server/audio/RotationHelper.java
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -80,6 +80,7 @@
static void updateOrientation() {
// Even though we're responding to device orientation events,
// use display rotation so audio stays in sync with video/dialogs
+ // TODO(b/148458001): Support multi-display
int newRotation = ((WindowManager) sContext.getSystemService(
Context.WINDOW_SERVICE)).getDefaultDisplay().getRotation();
synchronized(sRotationLock) {
diff --git a/services/core/java/com/android/server/backup/SystemBackupAgent.java b/services/core/java/com/android/server/backup/SystemBackupAgent.java
index 1f4563b..0a30b76 100644
--- a/services/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/services/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -113,6 +113,7 @@
throws IOException {
// Slot in a restore helper for the older wallpaper backup schema to support restore
// from devices still generating data in that format.
+ //TODO(b/147732386): Add multi-display support for wallpaper backup.
addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this,
new String[] { WALLPAPER_IMAGE_KEY}));
diff --git a/services/core/java/com/android/server/biometrics/face/FaceService.java b/services/core/java/com/android/server/biometrics/face/FaceService.java
index a0573db..b512475 100644
--- a/services/core/java/com/android/server/biometrics/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/face/FaceService.java
@@ -962,9 +962,10 @@
@Override
public void onLockoutChanged(long duration) {
Slog.d(TAG, "onLockoutChanged: " + duration);
+
if (duration == 0) {
mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_NONE;
- } else if (duration == Long.MAX_VALUE) {
+ } else if (duration == -1 || duration == Long.MAX_VALUE) {
mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_PERMANENT;
} else {
mCurrentUserLockoutMode = AuthenticationClient.LOCKOUT_TIMED;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 8d26176..7f7c9c4 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -35,6 +35,7 @@
import com.android.internal.compat.OverrideAllowedState;
import com.android.server.compat.config.Change;
import com.android.server.compat.config.XmlParser;
+import com.android.server.pm.ApexManager;
import org.xmlpull.v1.XmlPullParserException;
@@ -45,6 +46,7 @@
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import javax.xml.datatype.DatatypeConfigurationException;
@@ -369,12 +371,18 @@
Environment.getRootDirectory(), "etc", "compatconfig"));
config.initConfigFromLib(Environment.buildPath(
Environment.getRootDirectory(), "system_ext", "etc", "compatconfig"));
+
+ List<ApexManager.ActiveApexInfo> apexes = ApexManager.getInstance().getActiveApexInfos();
+ for (ApexManager.ActiveApexInfo apex : apexes) {
+ config.initConfigFromLib(Environment.buildPath(
+ apex.apexDirectory, "etc", "compatconfig"));
+ }
return config;
}
void initConfigFromLib(File libraryDir) {
if (!libraryDir.exists() || !libraryDir.isDirectory()) {
- Slog.e(TAG, "No directory " + libraryDir + ", skipping");
+ Slog.d(TAG, "No directory " + libraryDir + ", skipping");
return;
}
for (File f : libraryDir.listFiles()) {
diff --git a/services/core/java/com/android/server/compat/PlatformCompat.java b/services/core/java/com/android/server/compat/PlatformCompat.java
index 4d5af9a..2fc9d04 100644
--- a/services/core/java/com/android/server/compat/PlatformCompat.java
+++ b/services/core/java/com/android/server/compat/PlatformCompat.java
@@ -16,11 +16,6 @@
package com.android.server.compat;
-import static android.Manifest.permission.LOG_COMPAT_CHANGE;
-import static android.Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG;
-import static android.Manifest.permission.READ_COMPAT_CHANGE_CONFIG;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-
import android.app.ActivityManager;
import android.app.IActivityManager;
import android.content.Context;
@@ -30,7 +25,6 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.util.Slog;
-import android.util.StatsLog;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.compat.AndroidBuildClassifier;
@@ -59,7 +53,7 @@
public PlatformCompat(Context context) {
mContext = context;
mChangeReporter = new ChangeReporter(
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = CompatConfig.create(new AndroidBuildClassifier(), mContext);
}
@@ -67,20 +61,18 @@
PlatformCompat(Context context, CompatConfig compatConfig) {
mContext = context;
mChangeReporter = new ChangeReporter(
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__SOURCE__SYSTEM_SERVER);
+ ChangeReporter.SOURCE_SYSTEM_SERVER);
mCompatConfig = compatConfig;
}
@Override
public void reportChange(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeLogPermission();
reportChange(changeId, appInfo.uid,
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
+ ChangeReporter.STATE_LOGGED);
}
@Override
public void reportChangeByPackageName(long changeId, String packageName, int userId) {
- checkCompatChangeLogPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return;
@@ -90,26 +82,23 @@
@Override
public void reportChangeByUid(long changeId, int uid) {
- checkCompatChangeLogPermission();
- reportChange(changeId, uid, StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__LOGGED);
+ reportChange(changeId, uid, ChangeReporter.STATE_LOGGED);
}
@Override
public boolean isChangeEnabled(long changeId, ApplicationInfo appInfo) {
- checkCompatChangeReadPermission();
if (mCompatConfig.isChangeEnabled(changeId, appInfo)) {
reportChange(changeId, appInfo.uid,
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__ENABLED);
+ ChangeReporter.STATE_ENABLED);
return true;
}
reportChange(changeId, appInfo.uid,
- StatsLog.APP_COMPATIBILITY_CHANGE_REPORTED__STATE__DISABLED);
+ ChangeReporter.STATE_DISABLED);
return false;
}
@Override
public boolean isChangeEnabledByPackageName(long changeId, String packageName, int userId) {
- checkCompatChangeReadPermission();
ApplicationInfo appInfo = getApplicationInfo(packageName, userId);
if (appInfo == null) {
return true;
@@ -119,7 +108,6 @@
@Override
public boolean isChangeEnabledByUid(long changeId, int uid) {
- checkCompatChangeReadPermission();
String[] packages = mContext.getPackageManager().getPackagesForUid(uid);
if (packages == null || packages.length == 0) {
return true;
@@ -152,7 +140,6 @@
@Override
public void setOverrides(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
killPackage(packageName);
}
@@ -160,13 +147,11 @@
@Override
public void setOverridesForTest(CompatibilityChangeConfig overrides, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.addOverrides(overrides, packageName);
}
@Override
public void clearOverrides(String packageName) throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
killPackage(packageName);
}
@@ -174,14 +159,12 @@
@Override
public void clearOverridesForTest(String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
mCompatConfig.removePackageOverrides(packageName);
}
@Override
public boolean clearOverride(long changeId, String packageName)
throws RemoteException, SecurityException {
- checkCompatChangeOverridePermission();
boolean existed = mCompatConfig.removeOverride(changeId, packageName);
killPackage(packageName);
return existed;
@@ -189,13 +172,11 @@
@Override
public CompatibilityChangeConfig getAppConfig(ApplicationInfo appInfo) {
- checkCompatChangeReadPermission();
return mCompatConfig.getAppConfig(appInfo);
}
@Override
public CompatibilityChangeInfo[] listAllChanges() {
- checkCompatChangeReadPermission();
return mCompatConfig.dumpChanges();
}
@@ -234,7 +215,6 @@
@Override
protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- checkCompatChangeReadPermission();
if (!DumpUtils.checkDumpAndUsageStatsPermission(mContext, "platform_compat", pw)) return;
mCompatConfig.dumpConfig(pw);
}
@@ -292,25 +272,4 @@
Binder.restoreCallingIdentity(identity);
}
}
-
- private void checkCompatChangeLogPermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(LOG_COMPAT_CHANGE)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot log compat change usage");
- }
- }
-
- private void checkCompatChangeReadPermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(READ_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot read compat change");
- }
- }
-
- private void checkCompatChangeOverridePermission() throws SecurityException {
- if (mContext.checkCallingOrSelfPermission(OVERRIDE_COMPAT_CHANGE_CONFIG)
- != PERMISSION_GRANTED) {
- throw new SecurityException("Cannot override compat change");
- }
- }
}
diff --git a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
index 17e2f69..f3d2012 100644
--- a/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
+++ b/services/core/java/com/android/server/connectivity/NetdEventListenerService.java
@@ -35,11 +35,11 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.SparseArray;
-import android.util.StatsLog;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.BitUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.RingBuffer;
import com.android.internal.util.TokenBucket;
import com.android.server.connectivity.metrics.nano.IpConnectivityLogClass.IpConnectivityEvent;
@@ -278,7 +278,7 @@
addWakeupEvent(event);
String dstMac = event.dstHwAddr.toString();
- StatsLog.write(StatsLog.PACKET_WAKEUP_OCCURRED,
+ FrameworkStatsLog.write(FrameworkStatsLog.PACKET_WAKEUP_OCCURRED,
uid, iface, ethertype, dstMac, srcIp, dstIp, ipNextHeader, srcPort, dstPort);
}
diff --git a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
index d66aec5..3cfe916 100644
--- a/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
+++ b/services/core/java/com/android/server/connectivity/NetworkAgentInfo.java
@@ -483,7 +483,7 @@
return ConnectivityConstants.EXPLICITLY_SELECTED_NETWORK_SCORE;
}
- int score = mNetworkScore.getIntExtension(NetworkScore.LEGACY_SCORE);
+ int score = mNetworkScore.getLegacyScore();
if (!lastValidated && !pretendValidated && !ignoreWifiUnvalidationPenalty() && !isVPN()) {
score -= ConnectivityConstants.UNVALIDATED_SCORE_PENALTY;
}
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index decb1f9..96532f4 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -1050,6 +1050,7 @@
public void dumpLocked(PrintWriter pw) {
pw.println(" BrightnessObserver");
+ pw.println(" mAmbientLux: " + mAmbientLux);
pw.println(" mRefreshRateInZone: " + mRefreshRateInZone);
for (int d: mDisplayBrightnessThresholds) {
@@ -1059,6 +1060,8 @@
for (int d: mAmbientBrightnessThresholds) {
pw.println(" mAmbientBrightnessThreshold: " + d);
}
+
+ mLightSensorListener.dumpLocked(pw);
}
public void onDisplayChanged(int displayId) {
@@ -1222,6 +1225,10 @@
final private static int INJECT_EVENTS_INTERVAL_MS = LIGHT_SENSOR_RATE_MS;
private float mLastSensorData;
+ public void dumpLocked(PrintWriter pw) {
+ pw.println(" mLastSensorData: " + mLastSensorData);
+ }
+
@Override
public void onSensorChanged(SensorEvent event) {
mLastSensorData = event.values[0];
diff --git a/services/core/java/com/android/server/display/OverlayDisplayWindow.java b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
index 0fdf2da..49f0d35 100644
--- a/services/core/java/com/android/server/display/OverlayDisplayWindow.java
+++ b/services/core/java/com/android/server/display/OverlayDisplayWindow.java
@@ -109,7 +109,8 @@
mWindowManager = (WindowManager)context.getSystemService(
Context.WINDOW_SERVICE);
- mDefaultDisplay = mWindowManager.getDefaultDisplay();
+ // TODO(b/148458868): Support multi-display
+ mDefaultDisplay = mContext.getDisplay();
updateDefaultDisplayInfo();
resize(width, height, densityDpi, false /* doLayout */);
diff --git a/services/core/java/com/android/server/location/LocationFudger.java b/services/core/java/com/android/server/location/LocationFudger.java
index ae71fe3..04c7714 100644
--- a/services/core/java/com/android/server/location/LocationFudger.java
+++ b/services/core/java/com/android/server/location/LocationFudger.java
@@ -16,17 +16,19 @@
package com.android.server.location;
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.security.SecureRandom;
import android.content.Context;
import android.database.ContentObserver;
import android.location.Location;
+import android.os.Bundle;
import android.os.Handler;
import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+import java.security.SecureRandom;
+
/**
* Contains the logic to obfuscate (fudge) locations for coarse applications.
@@ -177,7 +179,12 @@
private Location addCoarseLocationExtraLocked(Location location) {
Location coarse = createCoarseLocked(location);
- location.setExtraLocation(Location.EXTRA_COARSE_LOCATION, coarse);
+ Bundle extras = location.getExtras();
+ if (extras == null) {
+ extras = new Bundle();
+ }
+ extras.putParcelable(Location.EXTRA_COARSE_LOCATION, coarse);
+ location.setExtras(extras);
return coarse;
}
diff --git a/services/core/java/com/android/server/location/LocationProviderProxy.java b/services/core/java/com/android/server/location/LocationProviderProxy.java
index 19fb669..96ffaa6 100644
--- a/services/core/java/com/android/server/location/LocationProviderProxy.java
+++ b/services/core/java/com/android/server/location/LocationProviderProxy.java
@@ -139,13 +139,13 @@
@GuardedBy("mLock")
private boolean mBound;
- @GuardedBy("mLock")
- private ProviderRequest mRequest;
+
+ private volatile ProviderRequest mRequest;
private LocationProviderProxy(Context context, String action, int enableOverlayResId,
int nonOverlayPackageResId) {
- // safe to use direct executor even though this class has internal locks - all of our
- // callbacks go to oneway binder transactions which cannot possibly be re-entrant
+ // safe to use direct executor since our locks are not acquired in a code path invoked by
+ // our owning provider
super(DIRECT_EXECUTOR, Collections.emptySet());
mContext = context;
@@ -167,8 +167,10 @@
mBound = true;
provider.setLocationProviderManager(mManager);
- if (!mRequest.equals(ProviderRequest.EMPTY_REQUEST)) {
- provider.setRequest(mRequest, mRequest.workSource);
+
+ ProviderRequest request = mRequest;
+ if (!request.equals(ProviderRequest.EMPTY_REQUEST)) {
+ provider.setRequest(request, request.workSource);
}
ComponentName service = mServiceWatcher.getBoundService().component;
@@ -187,10 +189,7 @@
@Override
public void onSetRequest(ProviderRequest request) {
- synchronized (mLock) {
- mRequest = request;
- }
-
+ mRequest = request;
mServiceWatcher.runOnBinder(binder -> {
ILocationProvider service = ILocationProvider.Stub.asInterface(binder);
service.setRequest(request, request.workSource);
@@ -215,9 +214,6 @@
@Override
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
- pw.println("service=" + mServiceWatcher);
- synchronized (mLock) {
- pw.println("bound=" + mBound);
- }
+ mServiceWatcher.dump(fd, pw, args);
}
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index baae4ea..1f4048f 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -139,6 +139,7 @@
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintWriter;
+import java.security.GeneralSecurityException;
import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.KeyStoreException;
@@ -224,6 +225,7 @@
private final KeyStore mKeyStore;
private final RecoverableKeyStoreManager mRecoverableKeyStoreManager;
+ private ManagedProfilePasswordCache mManagedProfilePasswordCache;
private final RebootEscrowManager mRebootEscrowManager;
@@ -387,6 +389,7 @@
setLockCredentialInternal(unifiedProfilePassword, managedUserPassword, managedUserId,
/* isLockTiedToParent= */ true);
tieProfileLockToParent(managedUserId, unifiedProfilePassword);
+ mManagedProfilePasswordCache.storePassword(managedUserId, unifiedProfilePassword);
}
}
@@ -527,6 +530,16 @@
int defaultValue) {
return Settings.Global.getInt(contentResolver, keyName, defaultValue);
}
+
+ public @NonNull ManagedProfilePasswordCache getManagedProfilePasswordCache() {
+ try {
+ java.security.KeyStore ks = java.security.KeyStore.getInstance("AndroidKeyStore");
+ ks.load(null);
+ return new ManagedProfilePasswordCache(ks, getUserManager());
+ } catch (Exception e) {
+ throw new IllegalStateException("Cannot load keystore", e);
+ }
+ }
}
public LockSettingsService(Context context) {
@@ -560,6 +573,7 @@
mStrongAuthTracker.register(mStrongAuth);
mSpManager = injector.getSyntheticPasswordManager(mStorage);
+ mManagedProfilePasswordCache = injector.getManagedProfilePasswordCache();
mRebootEscrowManager = injector.getRebootEscrowManager(new RebootEscrowCallbacks(),
mStorage);
@@ -706,7 +720,8 @@
private void ensureProfileKeystoreUnlocked(int userId) {
final KeyStore ks = KeyStore.getInstance();
if (ks.state(userId) == KeyStore.State.LOCKED
- && tiedManagedProfileReadyToUnlock(mUserManager.getUserInfo(userId))) {
+ && mUserManager.getUserInfo(userId).isManagedProfile()
+ && hasUnifiedChallenge(userId)) {
Slog.i(TAG, "Managed profile got unlocked, will unlock its keystore");
// If boot took too long and the password in vold got expired, parent keystore will
// be still locked, we ignore this case since the user will be prompted to unlock
@@ -1302,6 +1317,7 @@
LockscreenCredential credential = LockscreenCredential.createManagedPassword(
decryptionResult);
Arrays.fill(decryptionResult, (byte) 0);
+ mManagedProfilePasswordCache.storePassword(userId, credential);
return credential;
}
@@ -1381,12 +1397,25 @@
}
for (UserInfo profile : mUserManager.getProfiles(userId)) {
- // Unlock managed profile with unified lock
- if (tiedManagedProfileReadyToUnlock(profile)) {
- // Must pass the challenge on for resetLockout, so it's not over-written, which
- // causes LockSettingsService to revokeChallenge inappropriately.
- unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
- challengeType, challenge, resetLockouts);
+ if (profile.id == userId) continue;
+ if (!profile.isManagedProfile()) continue;
+
+ if (hasUnifiedChallenge(profile.id)) {
+ if (mUserManager.isUserRunning(profile.id)) {
+ // Unlock managed profile with unified lock
+ // Must pass the challenge on for resetLockout, so it's not over-written, which
+ // causes LockSettingsService to revokeChallenge inappropriately.
+ unlockChildProfile(profile.id, false /* ignoreUserNotAuthenticated */,
+ challengeType, challenge, resetLockouts);
+ } else {
+ try {
+ // Profile not ready for unlock yet, but decrypt the unified challenge now
+ // so it goes into the cache
+ getDecryptedPasswordForTiedProfile(profile.id);
+ } catch (GeneralSecurityException | IOException e) {
+ Slog.d(TAG, "Cache work profile password failed", e);
+ }
+ }
}
// Now we have unlocked the parent user and attempted to unlock the profile we should
// show notifications if the profile is still locked.
@@ -1417,11 +1446,9 @@
}
}
- private boolean tiedManagedProfileReadyToUnlock(UserInfo userInfo) {
- return userInfo.isManagedProfile()
- && !getSeparateProfileChallengeEnabledInternal(userInfo.id)
- && mStorage.hasChildProfileLock(userInfo.id)
- && mUserManager.isUserRunning(userInfo.id);
+ private boolean hasUnifiedChallenge(int userId) {
+ return !getSeparateProfileChallengeEnabledInternal(userId)
+ && mStorage.hasChildProfileLock(userId);
}
private Map<Integer, LockscreenCredential> getDecryptedPasswordsForAllTiedProfiles(int userId) {
@@ -2233,6 +2260,7 @@
final KeyStore ks = KeyStore.getInstance();
ks.onUserRemoved(userId);
+ mManagedProfilePasswordCache.removePassword(userId);
gateKeeperClearSecureUserId(userId);
if (unknownUser || mUserManager.getUserInfo(userId).isManagedProfile()) {
@@ -2783,6 +2811,7 @@
synchronizeUnifiedWorkChallengeForProfiles(userId, profilePasswords);
setUserPasswordMetrics(credential, userId);
+ mManagedProfilePasswordCache.removePassword(userId);
if (profilePasswords != null) {
for (Map.Entry<Integer, LockscreenCredential> entry : profilePasswords.entrySet()) {
@@ -3097,6 +3126,22 @@
return true;
}
+ @Override
+ public boolean tryUnlockWithCachedUnifiedChallenge(int userId) {
+ try (LockscreenCredential cred = mManagedProfilePasswordCache.retrievePassword(userId)) {
+ if (cred == null) {
+ return false;
+ }
+ return doVerifyCredential(cred, CHALLENGE_NONE, 0, userId, null /* progressCallback */)
+ .getResponseCode() == VerifyCredentialResponse.RESPONSE_OK;
+ }
+ }
+
+ @Override
+ public void removeCachedUnifiedChallenge(int userId) {
+ mManagedProfilePasswordCache.removePassword(userId);
+ }
+
static String timestampToString(long timestamp) {
return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date(timestamp));
}
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
index 4943c25..7b767b8 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsShellCommand.java
@@ -44,6 +44,7 @@
private static final String COMMAND_SET_DISABLED = "set-disabled";
private static final String COMMAND_VERIFY = "verify";
private static final String COMMAND_GET_DISABLED = "get-disabled";
+ private static final String COMMAND_REMOVE_CACHE = "remove-cache";
private static final String COMMAND_HELP = "help";
private int mCurrentUserId;
@@ -76,6 +77,15 @@
return -1;
}
}
+ switch (cmd) {
+ // Commands that do not require authentication go here.
+ case COMMAND_REMOVE_CACHE:
+ runRemoveCache();
+ return 0;
+ case COMMAND_HELP:
+ onHelp();
+ return 0;
+ }
if (!checkCredential()) {
return -1;
}
@@ -105,9 +115,6 @@
case COMMAND_GET_DISABLED:
runGetDisabled();
break;
- case COMMAND_HELP:
- onHelp();
- break;
default:
getErrPrintWriter().println("Unknown command: " + cmd);
break;
@@ -163,6 +170,9 @@
pw.println(" verify [--old <CREDENTIAL>] [--user USER_ID]");
pw.println(" Verifies the lock credentials.");
pw.println("");
+ pw.println(" remove-cache [--user USER_ID]");
+ pw.println(" Removes cached unified challenge for the managed profile.");
+ pw.println("");
}
}
@@ -322,4 +332,9 @@
return true;
}
}
+
+ private void runRemoveCache() {
+ mLockPatternUtils.removeCachedUnifiedChallenge(mCurrentUserId);
+ getOutPrintWriter().println("Password cached removed for user " + mCurrentUserId);
+ }
}
diff --git a/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
new file mode 100644
index 0000000..d38ee67
--- /dev/null
+++ b/services/core/java/com/android/server/locksettings/ManagedProfilePasswordCache.java
@@ -0,0 +1,191 @@
+/*
+ * 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.locksettings;
+
+import android.annotation.Nullable;
+import android.content.pm.UserInfo;
+import android.os.UserHandle;
+import android.os.UserManager;
+import android.security.keystore.AndroidKeyStoreSpi;
+import android.security.keystore.KeyGenParameterSpec;
+import android.security.keystore.KeyProperties;
+import android.security.keystore.UserNotAuthenticatedException;
+import android.util.Slog;
+import android.util.SparseArray;
+
+import com.android.internal.widget.LockscreenCredential;
+
+import java.security.GeneralSecurityException;
+import java.security.Key;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.util.Arrays;
+import java.util.concurrent.TimeUnit;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.GCMParameterSpec;
+
+/**
+ * Caches *unified* work challenge for user 0's managed profiles. Only user 0's profile is supported
+ * at the moment because the cached credential is encrypted using a keystore key auth-bound to
+ * user 0: this is to match how unified work challenge is similarly auth-bound to its parent user's
+ * lockscreen credential normally. It's possible to extend this class to support managed profiles
+ * for secondary users, that will require generating auth-bound keys to their corresponding parent
+ * user though (which {@link KeyGenParameterSpec} does not support right now).
+ *
+ * <p> The cache is filled whenever the managed profile's unified challenge is created or derived
+ * (as part of the parent user's credential verification flow). It's removed when the profile is
+ * deleted or a (separate) lockscreen credential is explicitly set on the profile. There is also
+ * an ADB command to evict the cache "cmd lock_settings remove-cache --user X", to assist
+ * development and testing.
+
+ * <p> The encrypted credential is stored in-memory only so the cache does not persist across
+ * reboots.
+ */
+public class ManagedProfilePasswordCache {
+
+ private static final String TAG = "ManagedProfilePasswordCache";
+ private static final int KEY_LENGTH = 256;
+ private static final int CACHE_TIMEOUT_SECONDS = (int) TimeUnit.DAYS.toSeconds(7);
+
+ private final SparseArray<byte[]> mEncryptedPasswords = new SparseArray<>();
+ private final KeyStore mKeyStore;
+ private final UserManager mUserManager;
+
+ public ManagedProfilePasswordCache(KeyStore keyStore, UserManager userManager) {
+ mKeyStore = keyStore;
+ mUserManager = userManager;
+ }
+
+ /**
+ * Encrypt and store the password in the cache. Does NOT overwrite existing password cache
+ * if one for the given user already exists.
+ */
+ public void storePassword(int userId, LockscreenCredential password) {
+ synchronized (mEncryptedPasswords) {
+ if (mEncryptedPasswords.contains(userId)) {
+ return;
+ }
+ UserInfo parent = mUserManager.getProfileParent(userId);
+ if (parent == null || parent.id != UserHandle.USER_SYSTEM) {
+ // Since the cached password is encrypted using a keystore key auth-bound to user 0,
+ // only support caching password for user 0's profile.
+ return;
+ }
+ String keyName = getEncryptionKeyName(userId);
+ KeyGenerator generator;
+ SecretKey key;
+ try {
+ generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,
+ AndroidKeyStoreSpi.NAME);
+ generator.init(new KeyGenParameterSpec.Builder(
+ keyName, KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)
+ .setKeySize(KEY_LENGTH)
+ .setBlockModes(KeyProperties.BLOCK_MODE_GCM)
+ .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)
+ // Generate auth-bound key to user 0 (since we the caller is user 0)
+ .setUserAuthenticationRequired(true)
+ .setUserAuthenticationValidityDurationSeconds(CACHE_TIMEOUT_SECONDS)
+ // Only accessible after user 0's keyguard is unlocked
+ .setUnlockedDeviceRequired(true)
+ .build());
+ key = generator.generateKey();
+ } catch (GeneralSecurityException e) {
+ Slog.e(TAG, "Cannot generate key", e);
+ return;
+ }
+
+ Cipher cipher;
+ try {
+ cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.ENCRYPT_MODE, key);
+ byte[] ciphertext = cipher.doFinal(password.getCredential());
+ byte[] iv = cipher.getIV();
+ byte[] block = Arrays.copyOf(iv, ciphertext.length + iv.length);
+ System.arraycopy(ciphertext, 0, block, iv.length, ciphertext.length);
+ mEncryptedPasswords.put(userId, block);
+ } catch (GeneralSecurityException e) {
+ Slog.d(TAG, "Cannot encrypt", e);
+ }
+ }
+ }
+
+ /** Attempt to retrieve the password for the given user. Returns {@code null} if it's not in the
+ * cache or if decryption fails.
+ */
+ public @Nullable LockscreenCredential retrievePassword(int userId) {
+ synchronized (mEncryptedPasswords) {
+ byte[] block = mEncryptedPasswords.get(userId);
+ if (block == null) {
+ return null;
+ }
+ Key key;
+ try {
+ key = mKeyStore.getKey(getEncryptionKeyName(userId), null);
+ } catch (UnrecoverableKeyException | KeyStoreException | NoSuchAlgorithmException e) {
+ Slog.d(TAG, "Cannot get key", e);
+ return null;
+ }
+ if (key == null) {
+ return null;
+ }
+ byte[] iv = Arrays.copyOf(block, 12);
+ byte[] ciphertext = Arrays.copyOfRange(block, 12, block.length);
+ byte[] credential;
+ try {
+ Cipher cipher = Cipher.getInstance("AES/GCM/NoPadding");
+ cipher.init(Cipher.DECRYPT_MODE, key, new GCMParameterSpec(128, iv));
+ credential = cipher.doFinal(ciphertext);
+ } catch (UserNotAuthenticatedException e) {
+ Slog.i(TAG, "Device not unlocked for more than 7 days");
+ return null;
+ } catch (GeneralSecurityException e) {
+ Slog.d(TAG, "Cannot decrypt", e);
+ return null;
+ }
+ LockscreenCredential result = LockscreenCredential.createManagedPassword(credential);
+ Arrays.fill(credential, (byte) 0);
+ return result;
+ }
+ }
+
+ /** Remove the given user's password from cache, if one exists. */
+ public void removePassword(int userId) {
+ synchronized (mEncryptedPasswords) {
+ String keyName = getEncryptionKeyName(userId);
+ try {
+ if (mKeyStore.containsAlias(keyName)) {
+ mKeyStore.deleteEntry(keyName);
+ }
+ } catch (KeyStoreException e) {
+ Slog.d(TAG, "Cannot delete key", e);
+ }
+ if (mEncryptedPasswords.contains(userId)) {
+ Arrays.fill(mEncryptedPasswords.get(userId), (byte) 0);
+ mEncryptedPasswords.remove(userId);
+ }
+ }
+ }
+
+ private static String getEncryptionKeyName(int userId) {
+ return "com.android.server.locksettings.unified_profile_cache_" + userId;
+ }
+}
diff --git a/services/core/java/com/android/server/media/BluetoothRouteProvider.java b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
index 8179c32..669f1ac 100644
--- a/services/core/java/com/android/server/media/BluetoothRouteProvider.java
+++ b/services/core/java/com/android/server/media/BluetoothRouteProvider.java
@@ -186,6 +186,7 @@
.setConnectionState(MediaRoute2Info.CONNECTION_STATE_DISCONNECTED)
.setDescription(mContext.getResources().getText(
R.string.bluetooth_a2dp_audio_route_name).toString())
+ .setDeviceType(MediaRoute2Info.DEVICE_TYPE_BLUETOOTH)
.build();
newBtRoute.connectedProfiles = new SparseBooleanArray();
return newBtRoute;
diff --git a/services/core/java/com/android/server/media/MediaRoute2Provider.java b/services/core/java/com/android/server/media/MediaRoute2Provider.java
index 1cd8aad..5123362 100644
--- a/services/core/java/com/android/server/media/MediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/MediaRoute2Provider.java
@@ -36,6 +36,7 @@
final Object mLock = new Object();
Callback mCallback;
+ boolean mIsSystemRouteProvider;
private volatile MediaRoute2ProviderInfo mProviderInfo;
@GuardedBy("mLock")
@@ -85,6 +86,7 @@
} else {
mProviderInfo = new MediaRoute2ProviderInfo.Builder(providerInfo)
.setUniqueId(mUniqueId)
+ .setSystemRouteProvider(mIsSystemRouteProvider)
.build();
}
}
diff --git a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
index 558eb8d..924a9b7 100644
--- a/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
+++ b/services/core/java/com/android/server/media/SystemMediaRoute2Provider.java
@@ -83,6 +83,8 @@
super(sComponentName);
setCallback(callback);
+ mIsSystemRouteProvider = true;
+
mContext = context;
mHandler = new Handler(Looper.getMainLooper());
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 7104790..68cc014 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2735,7 +2735,7 @@
// TODO(b/144152069): Remove informative toast
mUiHandler.post(() -> Toast.makeText(getContext(),
"Background custom toast blocked for package " + pkg + ".\n"
- + "See go/r-toast-block.",
+ + "See g.co/dev/toast.",
Toast.LENGTH_SHORT).show());
Slog.w(TAG, "Blocking custom toast from package " + pkg
+ " due to package not in the foreground");
diff --git a/services/core/java/com/android/server/pm/ApexManager.java b/services/core/java/com/android/server/pm/ApexManager.java
index 90afeff..42bc464 100644
--- a/services/core/java/com/android/server/pm/ApexManager.java
+++ b/services/core/java/com/android/server/pm/ApexManager.java
@@ -95,6 +95,7 @@
* Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
* depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
* evaluates to {@code true}.
+ * @hide
*/
public static ApexManager getInstance() {
return sApexManagerSingleton.get();
@@ -102,8 +103,9 @@
/**
* Minimal information about APEX mount points and the original APEX package they refer to.
+ * @hide
*/
- static class ActiveApexInfo {
+ public static class ActiveApexInfo {
@Nullable public final String apexModuleName;
public final File apexDirectory;
public final File preInstalledApexPath;
@@ -130,8 +132,10 @@
/**
* Returns {@link ActiveApexInfo} records relative to all active APEX packages.
+ *
+ * @hide
*/
- abstract List<ActiveApexInfo> getActiveApexInfos();
+ public abstract List<ActiveApexInfo> getActiveApexInfos();
abstract void systemReady(Context context);
@@ -287,6 +291,14 @@
public abstract boolean restoreCeData(int userId, int rollbackId, String apexPackageName);
/**
+ * Deletes snapshots of the device encrypted apex data directories for the given
+ * {@code rollbackId}.
+ *
+ * @return boolean true if the delete was successful
+ */
+ public abstract boolean destroyDeSnapshots(int rollbackId);
+
+ /**
* Dumps various state information to the provided {@link PrintWriter} object.
*
* @param pw the {@link PrintWriter} object to send information to.
@@ -362,7 +374,7 @@
}
@Override
- List<ActiveApexInfo> getActiveApexInfos() {
+ public List<ActiveApexInfo> getActiveApexInfos() {
synchronized (mLock) {
if (mActiveApexInfosCache == null) {
try {
@@ -716,6 +728,17 @@
}
}
+ @Override
+ public boolean destroyDeSnapshots(int rollbackId) {
+ try {
+ mApexService.destroyDeSnapshots(rollbackId);
+ return true;
+ } catch (Exception e) {
+ Slog.e(TAG, e.getMessage(), e);
+ return false;
+ }
+ }
+
/**
* Dump information about the packages contained in a particular cache
* @param packagesCache the cache to print information about.
@@ -798,7 +821,7 @@
*/
private static final class ApexManagerFlattenedApex extends ApexManager {
@Override
- List<ActiveApexInfo> getActiveApexInfos() {
+ public List<ActiveApexInfo> getActiveApexInfos() {
// There is no apexd running in case of flattened apex
// We look up the /apex directory and identify the active APEX modules from there.
// As "preinstalled" path, we just report /system since in the case of flattened APEX
@@ -929,6 +952,11 @@
}
@Override
+ public boolean destroyDeSnapshots(int rollbackId) {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
void dump(PrintWriter pw, String packageName) {
// No-op
}
diff --git a/services/core/java/com/android/server/pm/BackgroundDexOptService.java b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
index c712431..ba7583f 100644
--- a/services/core/java/com/android/server/pm/BackgroundDexOptService.java
+++ b/services/core/java/com/android/server/pm/BackgroundDexOptService.java
@@ -36,9 +36,9 @@
import android.os.storage.StorageManager;
import android.util.ArraySet;
import android.util.Log;
-import android.util.StatsLog;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.server.LocalServices;
import com.android.server.PinnerService;
import com.android.server.pm.dex.DexManager;
@@ -444,7 +444,7 @@
}
if (dex_opt_performed) {
- StatsLog.write(StatsLog.APP_DOWNGRADED, pkg, package_size_before,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_DOWNGRADED, pkg, package_size_before,
getPackageSize(pm, pkg), /*aggressive=*/ false);
}
return dex_opt_performed;
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index f962eed..40ea6cf 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -450,16 +450,6 @@
}
}
- public void markBootComplete(String instructionSet) throws InstallerException {
- assertValidInstructionSet(instructionSet);
- if (!checkBeforeRemote()) return;
- try {
- mInstalld.markBootComplete(instructionSet);
- } catch (Exception e) {
- throw InstallerException.from(e);
- }
- }
-
public void freeCache(String uuid, long targetFreeBytes, long cacheReservedBytes, int flags)
throws InstallerException {
if (!checkBeforeRemote()) return;
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 02ec472..148c5ad 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -288,7 +288,6 @@
import android.util.SparseArray;
import android.util.SparseBooleanArray;
import android.util.SparseIntArray;
-import android.util.StatsLog;
import android.util.TimingsTraceLog;
import android.util.Xml;
import android.util.apk.ApkSignatureVerifier;
@@ -310,6 +309,7 @@
import com.android.internal.util.ConcurrentUtils;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.AttributeCache;
@@ -2163,7 +2163,8 @@
getPackageExternalStorageType(volume, isExternal(res.pkg));
// If the package was installed externally, log it.
if (packageExternalStorageType != StorageEnums.UNKNOWN) {
- StatsLog.write(StatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
+ FrameworkStatsLog.write(
+ FrameworkStatsLog.APP_INSTALL_ON_EXTERNAL_STORAGE_REPORTED,
packageExternalStorageType, res.pkg.getPackageName());
}
}
@@ -2727,7 +2728,7 @@
t.traceBegin("get system config");
SystemConfig systemConfig = SystemConfig.getInstance();
mAvailableFeatures = systemConfig.getAvailableFeatures();
- ApplicationPackageManager.invalidateSysFeatureCache();
+ ApplicationPackageManager.invalidateHasSystemFeatureCache();
t.traceEnd();
mProtectedPackages = new ProtectedPackages(mContext);
@@ -19706,9 +19707,7 @@
if (packageName == null) {
return null;
}
- if (getPackageInfo(packageName, MATCH_SYSTEM_ONLY | MATCH_DIRECT_BOOT_AWARE
- | MATCH_DIRECT_BOOT_UNAWARE | MATCH_DISABLED_COMPONENTS,
- UserHandle.getCallingUserId()) == null) {
+ if (getPackageInfo(packageName, MATCH_FACTORY_ONLY, UserHandle.USER_SYSTEM) == null) {
return null;
}
return packageName;
@@ -22179,13 +22178,15 @@
if (!isPreviousLocationExternal && isExternal(pkg)) {
// Move from internal to external storage.
- StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
- StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+ packageExternalStorageType,
+ FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_EXTERNAL,
packageName);
} else if (isPreviousLocationExternal && !isExternal(pkg)) {
// Move from external to internal storage.
- StatsLog.write(StatsLog.APP_MOVED_STORAGE_REPORTED, packageExternalStorageType,
- StatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
+ FrameworkStatsLog.write(FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED,
+ packageExternalStorageType,
+ FrameworkStatsLog.APP_MOVED_STORAGE_REPORTED__MOVE_TYPE__TO_INTERNAL,
packageName);
}
}
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 5511a54..0cb8f495 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -932,6 +932,7 @@
userId, true /* enableQuietMode */, target, callingPackage);
return true;
}
+ mLockPatternUtils.tryUnlockWithCachedUnifiedChallenge(userId);
boolean needToShowConfirmCredential =
mLockPatternUtils.isSecure(userId)
&& !StorageManager.isUserKeyUnlocked(userId);
@@ -942,8 +943,7 @@
showConfirmCredentialToDisableQuietMode(userId, target);
return false;
}
- setQuietModeEnabled(
- userId, false /* enableQuietMode */, target, callingPackage);
+ setQuietModeEnabled(userId, false /* enableQuietMode */, target, callingPackage);
return true;
} finally {
Binder.restoreCallingIdentity(identity);
diff --git a/services/core/java/com/android/server/rollback/Rollback.java b/services/core/java/com/android/server/rollback/Rollback.java
index cb583cd..e0143ae 100644
--- a/services/core/java/com/android/server/rollback/Rollback.java
+++ b/services/core/java/com/android/server/rollback/Rollback.java
@@ -44,6 +44,7 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.IndentingPrintWriter;
+import com.android.server.pm.ApexManager;
import java.io.File;
import java.io.IOException;
@@ -651,15 +652,23 @@
*/
void delete(AppDataRollbackHelper dataHelper) {
synchronized (mLock) {
+ boolean containsApex = false;
for (PackageRollbackInfo pkgInfo : info.getPackages()) {
- IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers();
- for (int i = 0; i < snapshottedUsers.size(); i++) {
- // Destroy app data snapshot.
- int userId = snapshottedUsers.get(i);
+ if (pkgInfo.isApex()) {
+ containsApex = true;
+ } else {
+ IntArray snapshottedUsers = pkgInfo.getSnapshottedUsers();
+ for (int i = 0; i < snapshottedUsers.size(); i++) {
+ // Destroy app data snapshot.
+ int userId = snapshottedUsers.get(i);
- dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId);
+ dataHelper.destroyAppDataSnapshot(info.getRollbackId(), pkgInfo, userId);
+ }
}
}
+ if (containsApex) {
+ ApexManager.getInstance().destroyDeSnapshots(info.getRollbackId());
+ }
RollbackStore.deleteRollback(this);
mState = ROLLBACK_STATE_DELETED;
diff --git a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
index 4bab224..4425c0a 100644
--- a/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
+++ b/services/core/java/com/android/server/rollback/RollbackManagerServiceImpl.java
@@ -52,6 +52,7 @@
import android.provider.DeviceConfig;
import android.util.ArraySet;
import android.util.IntArray;
+import android.util.Log;
import android.util.LongArrayQueue;
import android.util.Slog;
import android.util.SparseBooleanArray;
@@ -94,7 +95,7 @@
class RollbackManagerServiceImpl extends IRollbackManager.Stub {
private static final String TAG = "RollbackManager";
- private static final boolean LOCAL_LOGV = false;
+ private static final boolean LOCAL_LOGV = Log.isLoggable(TAG, Log.VERBOSE);
// Rollbacks expire after 14 days.
private static final long DEFAULT_ROLLBACK_LIFETIME_DURATION_MILLIS =
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 4f8a86d..96f1219 100644
--- a/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
+++ b/services/core/java/com/android/server/stats/pull/StatsPullAtomService.java
@@ -256,6 +256,8 @@
mContext = context;
}
+ private native void nativeInit();
+
/**
* Use of this StatsPullAtomCallbackImpl means we avoid one class per tagId, which we would
* get if we used lambdas.
@@ -399,6 +401,7 @@
super.onBootPhase(phase);
if (phase == PHASE_SYSTEM_SERVICES_READY) {
BackgroundThread.getHandler().post(() -> {
+ nativeInit();
initializePullersState();
registerAllPullers();
registerEventListeners();
@@ -896,7 +899,6 @@
return data;
}
}
- Slog.e(TAG, "no controller energy info supplied for " + receiver.getName());
} catch (TimeoutException e) {
Slog.w(TAG, "timeout reading " + receiver.getName() + " stats");
}
diff --git a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
index e95fc4a..a1e643f 100644
--- a/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
+++ b/services/core/java/com/android/server/timedetector/TimeDetectorStrategyImpl.java
@@ -101,11 +101,12 @@
private TimestampedValue<Long> mLastAutoSystemClockTimeSet;
/**
- * A mapping from phoneId to a time suggestion. We typically expect one or two mappings: devices
- * will have a small number of telephony devices and phoneIds are assumed to be stable.
+ * A mapping from slotIndex to a time suggestion. We typically expect one or two mappings:
+ * devices will have a small number of telephony devices and slotIndexs are assumed to be
+ * stable.
*/
@GuardedBy("this")
- private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionByPhoneId =
+ private final ArrayMapWithHistory<Integer, PhoneTimeSuggestion> mSuggestionBySlotIndex =
new ArrayMapWithHistory<>(KEEP_SUGGESTION_HISTORY_SIZE);
@GuardedBy("this")
@@ -155,7 +156,7 @@
}
// Perform validation / input filtering and record the validated suggestion against the
- // phoneId.
+ // slotIndex.
if (!validateAndStorePhoneSuggestion(timeSuggestion)) {
return;
}
@@ -202,7 +203,7 @@
ipw.println("Phone suggestion history:");
ipw.increaseIndent(); // level 2
- mSuggestionByPhoneId.dump(ipw);
+ mSuggestionBySlotIndex.dump(ipw);
ipw.decreaseIndent(); // level 2
ipw.println("Network suggestion history:");
@@ -223,8 +224,8 @@
return false;
}
- int phoneId = suggestion.getPhoneId();
- PhoneTimeSuggestion previousSuggestion = mSuggestionByPhoneId.get(phoneId);
+ int slotIndex = suggestion.getSlotIndex();
+ PhoneTimeSuggestion previousSuggestion = mSuggestionBySlotIndex.get(slotIndex);
if (previousSuggestion != null) {
// We can log / discard suggestions with obvious issues with the reference time clock.
if (previousSuggestion.getUtcTime() == null
@@ -249,7 +250,7 @@
}
// Store the latest suggestion.
- mSuggestionByPhoneId.put(phoneId, suggestion);
+ mSuggestionBySlotIndex.put(slotIndex, suggestion);
return true;
}
@@ -323,15 +324,15 @@
//
// [1] https://en.wikipedia.org/wiki/NITZ
//
- // Generally, when there are suggestions from multiple phoneIds they should usually
+ // Generally, when there are suggestions from multiple slotIndexs they should usually
// approximately agree. In cases where signals *are* inaccurate we don't want to vacillate
- // between signals from two phoneIds. However, it is known for NITZ signals to be incorrect
- // occasionally, which means we also don't want to stick forever with one phoneId. Without
- // cross-referencing across sources (e.g. the current device time, NTP), or doing some kind
- // of statistical analysis of consistency within and across phoneIds, we can't know which
- // suggestions are more correct.
+ // between signals from two slotIndexs. However, it is known for NITZ signals to be
+ // incorrect occasionally, which means we also don't want to stick forever with one
+ // slotIndex. Without cross-referencing across sources (e.g. the current device time, NTP),
+ // or doing some kind of statistical analysis of consistency within and across slotIndexs,
+ // we can't know which suggestions are more correct.
//
- // For simplicity, we try to value recency, then consistency of phoneId.
+ // For simplicity, we try to value recency, then consistency of slotIndex.
//
// The heuristic works as follows:
// Recency: The most recent suggestion from each phone is scored. The score is based on a
@@ -339,20 +340,20 @@
// bucket, thus applying a loose reference time ordering. The suggestion with the highest
// score is used.
// Consistency: If there a multiple suggestions with the same score, the suggestion with the
- // lowest phoneId is always taken.
+ // lowest slotIndex is always taken.
//
// In the trivial case with a single ID this will just mean that the latest received
// suggestion is used.
PhoneTimeSuggestion bestSuggestion = null;
int bestScore = PHONE_INVALID_SCORE;
- for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
- Integer phoneId = mSuggestionByPhoneId.keyAt(i);
- PhoneTimeSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i);
+ for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) {
+ Integer slotIndex = mSuggestionBySlotIndex.keyAt(i);
+ PhoneTimeSuggestion candidateSuggestion = mSuggestionBySlotIndex.valueAt(i);
if (candidateSuggestion == null) {
// Unexpected - null suggestions should never be stored.
- Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for phoneId."
- + " phoneId=" + phoneId);
+ Slog.w(LOG_TAG, "Latest suggestion unexpectedly null for slotIndex."
+ + " slotIndex=" + slotIndex);
continue;
} else if (candidateSuggestion.getUtcTime() == null) {
// Unexpected - we do not store empty suggestions.
@@ -372,10 +373,10 @@
bestSuggestion = candidateSuggestion;
bestScore = candidateScore;
} else if (bestScore == candidateScore) {
- // Tie! Use the suggestion with the lowest phoneId.
- int candidatePhoneId = candidateSuggestion.getPhoneId();
- int bestPhoneId = bestSuggestion.getPhoneId();
- if (candidatePhoneId < bestPhoneId) {
+ // Tie! Use the suggestion with the lowest slotIndex.
+ int candidateSlotIndex = candidateSuggestion.getSlotIndex();
+ int bestSlotIndex = bestSuggestion.getSlotIndex();
+ if (candidateSlotIndex < bestSlotIndex) {
bestSuggestion = candidateSuggestion;
}
}
@@ -396,7 +397,7 @@
}
// The score is based on the age since receipt. Suggestions are bucketed so two
- // suggestions in the same bucket from different phoneIds are scored the same.
+ // suggestions in the same bucket from different slotIndexs are scored the same.
long ageMillis = elapsedRealtimeMillis - utcTime.getReferenceTimeMillis();
// Turn the age into a discrete value: 0 <= bucketIndex < PHONE_BUCKET_COUNT.
@@ -560,8 +561,8 @@
*/
@VisibleForTesting
@Nullable
- public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int phoneId) {
- return mSuggestionByPhoneId.get(phoneId);
+ public synchronized PhoneTimeSuggestion getLatestPhoneSuggestion(int slotIndex) {
+ return mSuggestionBySlotIndex.get(slotIndex);
}
/**
diff --git a/services/core/java/com/android/server/timezone/RulesManagerService.java b/services/core/java/com/android/server/timezone/RulesManagerService.java
index cdf8ea3..bbd1ae6 100644
--- a/services/core/java/com/android/server/timezone/RulesManagerService.java
+++ b/services/core/java/com/android/server/timezone/RulesManagerService.java
@@ -198,7 +198,7 @@
Slog.w(TAG, "Failed to read staged distro.", e);
}
}
- return new RulesState(baseVersion.rulesVersion, DISTRO_FORMAT_VERSION_SUPPORTED,
+ return new RulesState(baseVersion.getRulesVersion(), DISTRO_FORMAT_VERSION_SUPPORTED,
operationInProgress, stagedOperationStatus, stagedDistroRulesVersion,
distroStatus, installedDistroRulesVersion);
}
diff --git a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
index b4a4399..b0e0069 100644
--- a/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
+++ b/services/core/java/com/android/server/timezonedetector/TimeZoneDetectorStrategy.java
@@ -172,12 +172,12 @@
private final LocalLog mTimeZoneChangesLog = new LocalLog(30, false /* useLocalTimestamps */);
/**
- * A mapping from phoneId to a phone time zone suggestion. We typically expect one or two
- * mappings: devices will have a small number of telephony devices and phoneIds are assumed to
+ * A mapping from slotIndex to a phone time zone suggestion. We typically expect one or two
+ * mappings: devices will have a small number of telephony devices and slotIndexs are assumed to
* be stable.
*/
@GuardedBy("this")
- private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionByPhoneId =
+ private ArrayMapWithHistory<Integer, QualifiedPhoneTimeZoneSuggestion> mSuggestionBySlotIndex =
new ArrayMapWithHistory<>(KEEP_PHONE_SUGGESTION_HISTORY_SIZE);
/**
@@ -205,7 +205,7 @@
/**
* Suggests a time zone for the device, or withdraws a previous suggestion if
* {@link PhoneTimeZoneSuggestion#getZoneId()} is {@code null}. The suggestion is scoped to a
- * specific {@link PhoneTimeZoneSuggestion#getPhoneId() phone}.
+ * specific {@link PhoneTimeZoneSuggestion#getSlotIndex() phone}.
* See {@link PhoneTimeZoneSuggestion} for an explanation of the metadata associated with a
* suggestion. The strategy uses suggestions to decide whether to modify the device's time zone
* setting and what to set it to.
@@ -221,8 +221,8 @@
QualifiedPhoneTimeZoneSuggestion scoredSuggestion =
new QualifiedPhoneTimeZoneSuggestion(suggestion, score);
- // Store the suggestion against the correct phoneId.
- mSuggestionByPhoneId.put(suggestion.getPhoneId(), scoredSuggestion);
+ // Store the suggestion against the correct slotIndex.
+ mSuggestionBySlotIndex.put(suggestion.getSlotIndex(), scoredSuggestion);
// Now perform auto time zone detection. The new suggestion may be used to modify the time
// zone setting.
@@ -384,8 +384,9 @@
// and find the best. Note that we deliberately do not look at age: the caller can
// rate-limit so age is not a strong indicator of confidence. Instead, the callers are
// expected to withdraw suggestions they no longer have confidence in.
- for (int i = 0; i < mSuggestionByPhoneId.size(); i++) {
- QualifiedPhoneTimeZoneSuggestion candidateSuggestion = mSuggestionByPhoneId.valueAt(i);
+ for (int i = 0; i < mSuggestionBySlotIndex.size(); i++) {
+ QualifiedPhoneTimeZoneSuggestion candidateSuggestion =
+ mSuggestionBySlotIndex.valueAt(i);
if (candidateSuggestion == null) {
// Unexpected
continue;
@@ -396,10 +397,10 @@
} else if (candidateSuggestion.score > bestSuggestion.score) {
bestSuggestion = candidateSuggestion;
} else if (candidateSuggestion.score == bestSuggestion.score) {
- // Tie! Use the suggestion with the lowest phoneId.
- int candidatePhoneId = candidateSuggestion.suggestion.getPhoneId();
- int bestPhoneId = bestSuggestion.suggestion.getPhoneId();
- if (candidatePhoneId < bestPhoneId) {
+ // Tie! Use the suggestion with the lowest slotIndex.
+ int candidateSlotIndex = candidateSuggestion.suggestion.getSlotIndex();
+ int bestSlotIndex = bestSuggestion.suggestion.getSlotIndex();
+ if (candidateSlotIndex < bestSlotIndex) {
bestSuggestion = candidateSuggestion;
}
}
@@ -455,7 +456,7 @@
ipw.println("Phone suggestion history:");
ipw.increaseIndent(); // level 2
- mSuggestionByPhoneId.dump(ipw);
+ mSuggestionBySlotIndex.dump(ipw);
ipw.decreaseIndent(); // level 2
ipw.decreaseIndent(); // level 1
ipw.flush();
@@ -465,8 +466,8 @@
* A method used to inspect strategy state during tests. Not intended for general use.
*/
@VisibleForTesting
- public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int phoneId) {
- return mSuggestionByPhoneId.get(phoneId);
+ public synchronized QualifiedPhoneTimeZoneSuggestion getLatestPhoneSuggestion(int slotIndex) {
+ return mSuggestionBySlotIndex.get(slotIndex);
}
/**
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index d746691..61a33b4 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -361,7 +361,7 @@
private final Region mTempRegion3 = new Region();
private final Region mTempRegion4 = new Region();
- private final Context mContext;
+ private final Context mDisplayContext;
private final WindowManagerService mService;
private final MagnifiedViewport mMagnifedViewport;
private final Handler mHandler;
@@ -378,14 +378,14 @@
DisplayContent displayContent,
Display display,
MagnificationCallbacks callbacks) {
- mContext = windowManagerService.mContext;
+ mDisplayContext = windowManagerService.mContext.createDisplayContext(display);
mService = windowManagerService;
mCallbacks = callbacks;
mDisplayContent = displayContent;
mDisplay = display;
mHandler = new MyHandler(mService.mH.getLooper());
mMagnifedViewport = new MagnifiedViewport();
- mLongAnimationDuration = mContext.getResources().getInteger(
+ mLongAnimationDuration = mDisplayContext.getResources().getInteger(
com.android.internal.R.integer.config_longAnimTime);
}
@@ -568,8 +568,6 @@
private final MagnificationSpec mMagnificationSpec = MagnificationSpec.obtain();
- private final WindowManager mWindowManager;
-
private final float mBorderWidth;
private final int mHalfBorderWidth;
private final int mDrawBorderInset;
@@ -580,14 +578,13 @@
private int mTempLayer = 0;
public MagnifiedViewport() {
- mWindowManager = (WindowManager) mContext.getSystemService(Service.WINDOW_SERVICE);
- mBorderWidth = mContext.getResources().getDimension(
+ mBorderWidth = mDisplayContext.getResources().getDimension(
com.android.internal.R.dimen.accessibility_magnification_indicator_width);
mHalfBorderWidth = (int) Math.ceil(mBorderWidth / 2);
mDrawBorderInset = (int) mBorderWidth / 2;
- mWindow = new ViewportWindow(mContext);
+ mWindow = new ViewportWindow(mDisplayContext);
- if (mContext.getResources().getConfiguration().isScreenRound()) {
+ if (mDisplayContext.getResources().getConfiguration().isScreenRound()) {
mCircularPath = new Path();
mDisplay.getRealSize(mTempPoint);
final int centerXY = mTempPoint.x / 2;
@@ -916,7 +913,7 @@
public void updateSize(SurfaceControl.Transaction t) {
synchronized (mService.mGlobalLock) {
- mWindowManager.getDefaultDisplay().getRealSize(mTempPoint);
+ mDisplay.getRealSize(mTempPoint);
t.setBufferSize(mSurfaceControl, mTempPoint.x, mTempPoint.y);
invalidate(mDirtyRect);
}
diff --git a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
index 2ef0015..0502d0b 100644
--- a/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/wm/ActivityMetricsLogger.java
@@ -1212,7 +1212,7 @@
final ProtoOutputStream protoOutputStream =
new ProtoOutputStream(LAUNCH_OBSERVER_ACTIVITY_RECORD_PROTO_CHUNK_SIZE);
// Write this data out as the top-most ActivityRecordProto (i.e. it is not a sub-object).
- record.dumpDebug(protoOutputStream);
+ record.dumpDebug(protoOutputStream, WindowTraceLogLevel.ALL);
final byte[] bytes = protoOutputStream.getBytes();
Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index dda11f9..df6dfc4 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -196,6 +196,7 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.TaskPersister.DEBUG;
import static com.android.server.wm.TaskPersister.IMAGE_EXTENSION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
@@ -311,6 +312,8 @@
import com.android.server.uri.UriPermissionOwner;
import com.android.server.wm.ActivityMetricsLogger.TransitionInfoSnapshot;
import com.android.server.wm.ActivityStack.ActivityState;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.WindowManagerService.H;
import com.android.server.wm.utils.InsetUtils;
@@ -3074,7 +3077,11 @@
mStackSupervisor.getActivityMetricsLogger().notifyActivityRemoved(this);
waitingToShow = false;
- boolean delayed = isAnimating(TRANSITION | CHILDREN);
+ // Defer removal of this activity when either a child is animating, or app transition is on
+ // going. App transition animation might be applied on the parent stack not on the activity,
+ // but the actual frame buffer is associated with the activity, so we have to keep the
+ // activity while a parent is animating.
+ boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
if (getDisplayContent().mClosingApps.contains(this)) {
delayed = true;
} else if (getDisplayContent().mAppTransition.isTransitionSet()) {
@@ -4076,7 +4083,8 @@
@Override
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- boolean isVoiceInteraction, @Nullable Runnable animationFinishedCallback) {
+ boolean isVoiceInteraction,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
if (mUseTransferredAnimation) {
return false;
}
@@ -4154,7 +4162,7 @@
// We aren't delayed anything, but exiting windows rely on the animation finished
// callback being called in case the ActivityRecord was pretending to be delayed,
// which we might have done because we were in closing/opening apps list.
- onAnimationFinished();
+ onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, null /* AnimationAdapter */);
if (visible) {
// The token was made immediately visible, there will be no entrance animation.
// We need to inform the client the enter animation was finished.
@@ -6050,8 +6058,8 @@
}
@Override
- protected void onAnimationFinished() {
- super.onAnimationFinished();
+ protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
+ super.onAnimationFinished(type, anim);
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "AR#onAnimationFinished");
mTransit = TRANSIT_UNSET;
@@ -7498,17 +7506,19 @@
* Write all fields to an {@code ActivityRecordProto}. This assumes the
* {@code ActivityRecordProto} is the outer-most proto data.
*/
- void dumpDebug(ProtoOutputStream proto) {
+ void dumpDebug(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
writeNameToProto(proto, NAME);
- super.dumpDebug(proto, WINDOW_TOKEN, WindowTraceLogLevel.ALL);
+ super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
- proto.write(IS_ANIMATING, isAnimating());
- if (mThumbnail != null) {
+ proto.write(IS_ANIMATING, isAnimating(PARENTS));
+ if (mThumbnail != null){
mThumbnail.dumpDebug(proto, THUMBNAIL);
}
proto.write(FILLS_PARENT, mOccludesParent);
proto.write(APP_STOPPED, mAppStopped);
+ proto.write(TRANSLUCENT, !occludesParent());
+ proto.write(VISIBLE, mVisible);
proto.write(VISIBLE_REQUESTED, mVisibleRequested);
proto.write(CLIENT_VISIBLE, mClientVisible);
proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
@@ -7531,24 +7541,12 @@
writeIdentifierToProto(proto, IDENTIFIER);
proto.write(STATE, mState.toString());
- proto.write(VISIBLE_REQUESTED, mVisibleRequested);
proto.write(FRONT_OF_TASK, isRootOfTask());
if (hasProcess()) {
proto.write(PROC_ID, app.getPid());
}
- proto.write(TRANSLUCENT, !occludesParent());
- proto.write(VISIBLE, mVisible);
}
- public void dumpDebug(ProtoOutputStream proto, long fieldId) {
- final long token = proto.start(fieldId);
- dumpDebug(proto);
- proto.end(token);
- }
-
- /**
- * Copied from old AppWindowToken.
- */
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
@@ -7558,36 +7556,7 @@
}
final long token = proto.start(fieldId);
- writeNameToProto(proto, NAME);
- super.dumpDebug(proto, WINDOW_TOKEN, logLevel);
- proto.write(LAST_SURFACE_SHOWING, mLastSurfaceShowing);
- proto.write(IS_WAITING_FOR_TRANSITION_START, isWaitingForTransitionStart());
- proto.write(IS_ANIMATING, isAnimating(PARENTS));
- if (mThumbnail != null){
- mThumbnail.dumpDebug(proto, THUMBNAIL);
- }
- proto.write(FILLS_PARENT, mOccludesParent);
- proto.write(APP_STOPPED, mAppStopped);
- proto.write(VISIBLE_REQUESTED, mVisibleRequested);
- proto.write(CLIENT_VISIBLE, mClientVisible);
- proto.write(DEFER_HIDING_CLIENT, mDeferHidingClient);
- proto.write(REPORTED_DRAWN, reportedDrawn);
- proto.write(REPORTED_VISIBLE, reportedVisible);
- proto.write(NUM_INTERESTING_WINDOWS, mNumInterestingWindows);
- proto.write(NUM_DRAWN_WINDOWS, mNumDrawnWindows);
- proto.write(ALL_DRAWN, allDrawn);
- proto.write(LAST_ALL_DRAWN, mLastAllDrawn);
- if (startingWindow != null) {
- startingWindow.writeIdentifierToProto(proto, STARTING_WINDOW);
- }
- proto.write(STARTING_DISPLAYED, startingDisplayed);
- proto.write(STARTING_MOVED, startingMoved);
- proto.write(VISIBLE_SET_FROM_TRANSFERRED_STARTING_WINDOW,
- mVisibleSetFromTransferredStartingWindow);
- for (Rect bounds : mFrozenBounds) {
- bounds.dumpDebug(proto, FROZEN_BOUNDS);
- }
- proto.write(VISIBLE, mVisible);
+ dumpDebug(proto, logLevel);
proto.end(token);
}
diff --git a/services/core/java/com/android/server/wm/ActivityStack.java b/services/core/java/com/android/server/wm/ActivityStack.java
index ddf0117..d5961a8 100644
--- a/services/core/java/com/android/server/wm/ActivityStack.java
+++ b/services/core/java/com/android/server/wm/ActivityStack.java
@@ -60,10 +60,18 @@
import static android.view.WindowManager.TRANSIT_TASK_TO_BACK;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-import static com.android.server.am.ActivityStackProto.DISPLAY_ID;
-import static com.android.server.am.ActivityStackProto.FULLSCREEN;
-import static com.android.server.am.ActivityStackProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityStackProto.STACK;
+import static com.android.server.wm.TaskProto.ACTIVITIES;
+import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
+import static com.android.server.wm.TaskProto.BOUNDS;
+import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
+import static com.android.server.wm.TaskProto.DISPLAY_ID;
+import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
+import static com.android.server.wm.TaskProto.MIN_HEIGHT;
+import static com.android.server.wm.TaskProto.MIN_WIDTH;
+import static com.android.server.wm.TaskProto.ORIG_ACTIVITY;
+import static com.android.server.wm.TaskProto.REAL_ACTIVITY;
+import static com.android.server.wm.TaskProto.RESIZE_MODE;
+import static com.android.server.wm.TaskProto.RESUMED_ACTIVITY;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSING;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
@@ -107,15 +115,19 @@
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_END;
import static com.android.server.wm.BoundsAnimationController.SCHEDULE_PIP_MODE_CHANGED_ON_START;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
-import static com.android.server.wm.StackProto.ADJUSTED_BOUNDS;
-import static com.android.server.wm.StackProto.ADJUSTED_FOR_IME;
-import static com.android.server.wm.StackProto.ADJUST_DIVIDER_AMOUNT;
-import static com.android.server.wm.StackProto.ADJUST_IME_AMOUNT;
-import static com.android.server.wm.StackProto.ANIMATING_BOUNDS;
-import static com.android.server.wm.StackProto.DEFER_REMOVAL;
-import static com.android.server.wm.StackProto.FILLS_PARENT;
-import static com.android.server.wm.StackProto.MINIMIZE_AMOUNT;
-import static com.android.server.wm.StackProto.WINDOW_CONTAINER;
+import static com.android.server.wm.TaskProto.ADJUSTED_BOUNDS;
+import static com.android.server.wm.TaskProto.ADJUSTED_FOR_IME;
+import static com.android.server.wm.TaskProto.ADJUST_DIVIDER_AMOUNT;
+import static com.android.server.wm.TaskProto.ADJUST_IME_AMOUNT;
+import static com.android.server.wm.TaskProto.ANIMATING_BOUNDS;
+import static com.android.server.wm.TaskProto.DEFER_REMOVAL;
+import static com.android.server.wm.TaskProto.FILLS_PARENT;
+import static com.android.server.wm.TaskProto.MINIMIZE_AMOUNT;
+import static com.android.server.wm.TaskProto.ROOT_TASK_ID;
+import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
+import static com.android.server.wm.TaskProto.SURFACE_WIDTH;
+import static com.android.server.wm.TaskProto.TASKS;
+import static com.android.server.wm.TaskProto.WINDOW_CONTAINER;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
@@ -341,6 +353,9 @@
private static final int TRANSLUCENT_TIMEOUT_MSG = FIRST_ACTIVITY_STACK_MSG + 1;
+ // TODO(task-hierarchy): remove when tiles can be actual parents
+ TaskTile mTile = null;
+
private final Handler mHandler;
private class ActivityStackHandler extends Handler {
@@ -638,11 +653,20 @@
}
@Override
+ public void resolveOverrideConfiguration(Configuration newParentConfig) {
+ super.resolveOverrideConfiguration(newParentConfig);
+ if (mTile != null) {
+ // If this is a virtual child of a tile, simulate the parent-child relationship
+ mTile.updateResolvedConfig(getResolvedOverrideConfiguration());
+ }
+ }
+
+ @Override
public void onConfigurationChanged(Configuration newParentConfig) {
// Calling Task#onConfigurationChanged() for leaf task since the ops in this method are
// particularly for ActivityStack, like preventing bounds changes when inheriting certain
// windowing mode.
- if (!isRootTask()) {
+ if (!isRootTask() || this instanceof TaskTile) {
super.onConfigurationChanged(newParentConfig);
return;
}
@@ -3944,7 +3968,6 @@
? ((WindowContainer) newParent).getDisplayContent() : null;
final DisplayContent oldDisplay = oldParent != null
? ((WindowContainer) oldParent).getDisplayContent() : null;
-
super.onParentChanged(newParent, oldParent);
if (display != null && inSplitScreenPrimaryWindowingMode()
@@ -3963,6 +3986,11 @@
if (oldDisplay != null && oldDisplay.isRemoving()) {
postReparent();
}
+ if (mTile != null && getSurfaceControl() != null) {
+ // by now, the TaskStack should already have been reparented, so we can reparent its
+ // surface here
+ reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ }
}
void reparent(DisplayContent newParent, boolean onTop) {
@@ -4000,7 +4028,16 @@
@Override
void getRelativeDisplayedPosition(Point outPos) {
- super.getRelativeDisplayedPosition(outPos);
+ // check for tile which is "virtually" a parent.
+ if (mTile != null) {
+ final Rect dispBounds = getDisplayedBounds();
+ outPos.set(dispBounds.left, dispBounds.top);
+ final Rect parentBounds = mTile.getBounds();
+ outPos.offset(-parentBounds.left, -parentBounds.top);
+ } else {
+ super.getRelativeDisplayedPosition(outPos);
+ }
+
final int outset = getStackOutset();
outPos.x -= outset;
outPos.y -= outset;
@@ -4010,6 +4047,16 @@
if (mSurfaceControl == null) {
return;
}
+ if (mTile != null) {
+ // Tile controls crop, so the app needs to be able to draw its background outside of
+ // the stack bounds for when the tile crop gets bigger than the stack.
+ if (mLastSurfaceSize.equals(0, 0)) {
+ return;
+ }
+ transaction.setWindowCrop(mSurfaceControl, null);
+ mLastSurfaceSize.set(0, 0);
+ return;
+ }
final Rect stackBounds = getDisplayedBounds();
int width = stackBounds.width();
@@ -4033,6 +4080,9 @@
@Override
void onDisplayChanged(DisplayContent dc) {
+ if (mTile != null && dc != mTile.getDisplay()) {
+ mTile.removeChild(this);
+ }
super.onDisplayChanged(dc);
if (isRootTask()) {
updateSurfaceBounds();
@@ -4848,32 +4898,44 @@
return shouldSleepActivities() || mAtmService.mShuttingDown;
}
- @Override
- public void dumpDebug(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- final long token = proto.start(fieldId);
- dumpDebugInnerStackOnly(proto, STACK, logLevel);
- proto.write(com.android.server.am.ActivityStackProto.ID, getRootTaskId());
-
- forAllTasks((t) -> {
- t.dumpDebugInner(proto, com.android.server.am.ActivityStackProto.TASKS, logLevel);
- }, true /* traverseTopToBottom */, this);
- if (mResumedActivity != null) {
- mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
- }
- proto.write(DISPLAY_ID, getDisplayId());
- if (!matchParentBounds()) {
- final Rect bounds = getRequestedOverrideBounds();
- bounds.dumpDebug(proto, com.android.server.am.ActivityStackProto.BOUNDS);
- }
-
- // TODO: Remove, no longer needed with windowingMode.
- proto.write(FULLSCREEN, matchParentBounds());
- proto.end(token);
+ TaskTile getTile() {
+ return mTile;
}
- // TODO(proto-merge): Remove once protos for ActivityStack and TaskStack are merged.
- void dumpDebugInnerStackOnly(ProtoOutputStream proto, long fieldId,
+ /**
+ * Don't call this directly. instead use {@link TaskTile#addChild} or
+ * {@link TaskTile#removeChild}.
+ */
+ void setTile(TaskTile tile) {
+ TaskTile origTile = mTile;
+ mTile = tile;
+ final ConfigurationContainer parent = getParent();
+ if (parent != null) {
+ onConfigurationChanged(parent.getConfiguration());
+ }
+
+ // Reparent to tile surface or back to original parent
+ if (getSurfaceControl() == null) {
+ return;
+ }
+ if (mTile != null) {
+ reparentSurfaceControl(getPendingTransaction(), mTile.getSurfaceControl());
+ } else if (mTile == null && origTile != null) {
+ reparentSurfaceControl(getPendingTransaction(), getParentSurfaceControl());
+ }
+ }
+
+ @Override
+ void removeImmediately() {
+ // TODO(task-hierarchy): remove this override when tiles are in hierarchy
+ if (mTile != null) {
+ mTile.removeChild(this);
+ }
+ super.removeImmediately();
+ }
+
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
return;
@@ -4881,19 +4943,60 @@
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
- proto.write(StackProto.ID, getRootTaskId());
- forAllTasks((t) -> {
- t.dumpDebugInnerTaskOnly(proto, StackProto.TASKS, logLevel);
- }, true /* traverseTopToBottom */, this);
+
+ proto.write(TaskProto.ID, mTaskId);
+ proto.write(DISPLAY_ID, getDisplayId());
+ proto.write(ROOT_TASK_ID, getRootTaskId());
+
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child instanceof Task) {
+ child.dumpDebug(proto, TASKS, logLevel);
+ } else if (child instanceof ActivityRecord) {
+ child.dumpDebug(proto, ACTIVITIES, logLevel);
+ } else {
+ throw new IllegalStateException("Unknown child type: " + child);
+ }
+ }
+
+ if (mResumedActivity != null) {
+ mResumedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+ }
+ if (realActivity != null) {
+ proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
+ }
+ if (origActivity != null) {
+ proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
+ }
+ proto.write(ACTIVITY_TYPE, getActivityType());
+ proto.write(RESIZE_MODE, mResizeMode);
+ proto.write(MIN_WIDTH, mMinWidth);
+ proto.write(MIN_HEIGHT, mMinHeight);
+
proto.write(FILLS_PARENT, matchParentBounds());
- getRawBounds().dumpDebug(proto, StackProto.BOUNDS);
+
+ if (!matchParentBounds()) {
+ final Rect bounds = getRequestedOverrideBounds();
+ bounds.dumpDebug(proto, BOUNDS);
+ }
+ getOverrideDisplayedBounds().dumpDebug(proto, DISPLAYED_BOUNDS);
+ mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS);
+ if (mLastNonFullscreenBounds != null) {
+ mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
+ }
+
proto.write(DEFER_REMOVAL, mDeferRemoval);
proto.write(MINIMIZE_AMOUNT, mMinimizeAmount);
proto.write(ADJUSTED_FOR_IME, mAdjustedForIme);
proto.write(ADJUST_IME_AMOUNT, mAdjustImeAmount);
proto.write(ADJUST_DIVIDER_AMOUNT, mAdjustDividerAmount);
- mAdjustedBounds.dumpDebug(proto, ADJUSTED_BOUNDS);
proto.write(ANIMATING_BOUNDS, mBoundsAnimating);
+
+ if (mSurfaceControl != null) {
+ proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
+ proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
+ }
+
proto.end(token);
}
}
diff --git a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
index 362e781..a513ef8 100644
--- a/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityStackSupervisor.java
@@ -1711,6 +1711,7 @@
* invisible as well and added to the stopping list. After which we process the
* stopping list by handling the idle.
*/
+ stack.cancelAnimation();
stack.mForceHidden = true;
stack.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
stack.mForceHidden = false;
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index f019013..5a5976b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -69,6 +69,7 @@
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.am.ActivityManagerService.STOCK_PM_FLAGS;
import static com.android.server.am.ActivityManagerService.dumpStackTraces;
+import static com.android.server.am.ActivityManagerServiceDumpActivitiesProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONFIG_WILL_CHANGE;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CONTROLLER;
import static com.android.server.am.ActivityManagerServiceDumpProcessesProto.CURRENT_TRACKER;
@@ -144,6 +145,7 @@
import android.app.IAssistDataReceiver;
import android.app.INotificationManager;
import android.app.IRequestFinishCallback;
+import android.app.ITaskOrganizerController;
import android.app.ITaskStackListener;
import android.app.Notification;
import android.app.NotificationManager;
@@ -225,10 +227,8 @@
import android.util.TimeUtils;
import android.util.proto.ProtoOutputStream;
import android.view.IRecentsAnimationRunner;
-import android.view.ITaskOrganizer;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationDefinition;
-import android.view.WindowContainerTransaction;
import android.view.WindowManager;
import com.android.internal.R;
@@ -258,7 +258,6 @@
import com.android.server.UiThread;
import com.android.server.Watchdog;
import com.android.server.am.ActivityManagerService;
-import com.android.server.am.ActivityManagerServiceDumpActivitiesProto;
import com.android.server.am.ActivityManagerServiceDumpProcessesProto;
import com.android.server.am.AppTimeTracker;
import com.android.server.am.BaseErrorDialog;
@@ -292,7 +291,6 @@
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
@@ -344,10 +342,6 @@
/** This activity is being relaunched due to a free-resize operation. */
public static final int RELAUNCH_REASON_FREE_RESIZE = 2;
- /** Flag indicating that an applied transaction may have effected lifecycle */
- private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
- private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
-
Context mContext;
/**
@@ -669,8 +663,7 @@
/**
* Stores the registration and state of TaskOrganizers in use.
*/
- TaskOrganizerController mTaskOrganizerController =
- new TaskOrganizerController(this, mGlobalLock);
+ TaskOrganizerController mTaskOrganizerController = new TaskOrganizerController(this);
private int mDeviceOwnerUid = Process.INVALID_UID;
@@ -1286,15 +1279,6 @@
}
@Override
- public final void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- enforceCallerIsRecentsOrHasPermission(
- MANAGE_ACTIVITY_STACKS, "registerTaskOrganizer()");
- synchronized (mGlobalLock) {
- mTaskOrganizerController.registerTaskOrganizer(organizer, windowingMode);
- }
- }
-
- @Override
public IBinder requestStartActivityPermissionToken(IBinder delegatorToken) {
int callingUid = Binder.getCallingUid();
if (UserHandle.getAppId(callingUid) != SYSTEM_UID) {
@@ -3304,116 +3288,6 @@
}
}
- private int sanitizeAndApplyChange(WindowContainer container,
- WindowContainerTransaction.Change change) {
- if (!(container instanceof Task || container instanceof ActivityStack)) {
- throw new RuntimeException("Invalid token in task transaction");
- }
- // The "client"-facing API should prevent bad changes; however, just in case, sanitize
- // masks here.
- int configMask = change.getConfigSetMask();
- int windowMask = change.getWindowSetMask();
- configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
- | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
- windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
- int effects = 0;
- if (configMask != 0) {
- Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
- c.setTo(change.getConfiguration(), configMask, windowMask);
- container.onRequestedOverrideConfigurationChanged(c);
- // TODO(b/145675353): remove the following once we could apply new bounds to the
- // pinned stack together with its children.
- resizePinnedStackIfNeeded(container, configMask, windowMask, c);
- effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
- }
- if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
- if (container.setFocusable(change.getFocusable())) {
- effects |= TRANSACT_EFFECTS_LIFECYCLE;
- }
- }
- return effects;
- }
-
- private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
- int windowMask, Configuration config) {
- if ((container instanceof ActivityStack)
- && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
- && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
- final ActivityStack stack = (ActivityStack) container;
- if (stack.inPinnedWindowingMode()) {
- stack.resize(config.windowConfiguration.getBounds(),
- null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
- PRESERVE_WINDOWS, true /* deferResume */);
- }
- }
- }
-
- private int applyWindowContainerChange(WindowContainer wc,
- WindowContainerTransaction.Change c) {
- int effects = sanitizeAndApplyChange(wc, c);
-
- Rect enterPipBounds = c.getEnterPipBounds();
- if (enterPipBounds != null) {
- Task tr = (Task) wc;
- mStackSupervisor.updatePictureInPictureMode(tr,
- enterPipBounds, true);
- }
- return effects;
- }
-
- @Override
- public void applyContainerTransaction(WindowContainerTransaction t) {
- mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "applyContainerTransaction()");
- if (t == null) {
- return;
- }
- long ident = Binder.clearCallingIdentity();
- try {
- synchronized (mGlobalLock) {
- int effects = 0;
- deferWindowLayout();
- try {
- ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
- Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
- t.getChanges().entrySet().iterator();
- while (entries.hasNext()) {
- final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
- entries.next();
- final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
- entry.getKey()).getContainer();
- int containerEffect = applyWindowContainerChange(wc, entry.getValue());
- effects |= containerEffect;
- // Lifecycle changes will trigger ensureConfig for everything.
- if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
- && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
- haveConfigChanges.add(wc);
- }
- }
- if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
- // Already calls ensureActivityConfig
- mRootWindowContainer.ensureActivitiesVisible(null, 0, PRESERVE_WINDOWS);
- } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
- final PooledConsumer f = PooledLambda.obtainConsumer(
- ActivityRecord::ensureActivityConfiguration,
- PooledLambda.__(ActivityRecord.class), 0,
- false /* preserveWindow */);
- try {
- for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
- haveConfigChanges.valueAt(i).forAllActivities(f);
- }
- } finally {
- f.recycle();
- }
- }
- } finally {
- continueWindowLayout();
- }
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
- }
- }
-
@Override
public boolean releaseActivityInstance(IBinder token) {
synchronized (mGlobalLock) {
@@ -4442,6 +4316,13 @@
}
}
+ @Override
+ public ITaskOrganizerController getTaskOrganizerController() {
+ mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS,
+ "getTaskOrganizerController()");
+ return mTaskOrganizerController;
+ }
+
/**
* Check that we have the features required for VR-related API calls, and throw an exception if
* not.
@@ -7082,10 +6963,8 @@
public void writeActivitiesToProto(ProtoOutputStream proto) {
synchronized (mGlobalLock) {
// The output proto of "activity --proto activities"
- // is ActivityManagerServiceDumpActivitiesProto
- mRootWindowContainer.dumpDebug(proto,
- ActivityManagerServiceDumpActivitiesProto.ACTIVITY_STACK_SUPERVISOR,
- WindowTraceLogLevel.ALL);
+ mRootWindowContainer.dumpDebug(
+ proto, ROOT_WINDOW_CONTAINER, WindowTraceLogLevel.ALL);
}
}
diff --git a/services/core/java/com/android/server/wm/AnimationAdapter.java b/services/core/java/com/android/server/wm/AnimationAdapter.java
index 1be3d61..0519b80 100644
--- a/services/core/java/com/android/server/wm/AnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/AnimationAdapter.java
@@ -21,6 +21,7 @@
import android.view.SurfaceControl.Transaction;
import android.view.animation.Animation;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -47,9 +48,10 @@
* component running the animation after {@code finishCallback} has been
* invoked, or after the animation was cancelled.
* @param t The Transaction to apply the initial frame of the animation.
+ * @param type The type of the animation.
* @param finishCallback The callback to be invoked when the animation has finished.
*/
- void startAnimation(SurfaceControl animationLeash, Transaction t,
+ void startAnimation(SurfaceControl animationLeash, Transaction t, @AnimationType int type,
OnAnimationFinishedCallback finishCallback);
/**
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 3927d5f..f72020e 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -377,9 +377,9 @@
transitioningDecendants.add(app);
}
}
- wc.applyAnimation(animLp, transit, visible, voiceInteraction, () -> {
+ wc.applyAnimation(animLp, transit, visible, voiceInteraction, (type, anim) -> {
for (int j = 0; j < transitioningDecendants.size(); ++j) {
- transitioningDecendants.get(j).onAnimationFinished();
+ transitioningDecendants.get(j).onAnimationFinished(type, anim);
}
});
}
@@ -431,6 +431,8 @@
while (!candidates.isEmpty()) {
final WindowContainer current = candidates.removeFirst();
final WindowContainer parent = current.getParent();
+ siblings.clear();
+ siblings.add(current);
boolean canPromote = true;
if (parent == null) {
@@ -468,12 +470,11 @@
//
// [Task] +- [ActivityRecord1] (visible, in opening apps)
// +- [ActivityRecord2] (visible, not in opening apps)
- siblings.clear();
for (int j = 0; j < parent.getChildCount(); ++j) {
final WindowContainer sibling = parent.getChildAt(j);
- if (sibling == current || candidates.remove(sibling)) {
+ if (candidates.remove(sibling)) {
siblings.add(sibling);
- } else if (sibling.isVisible()) {
+ } else if (sibling != current && sibling.isVisible()) {
canPromote = false;
}
}
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index 16aff9c..537ca08 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -20,6 +20,7 @@
import static com.android.server.wm.AlphaAnimationSpecProto.FROM;
import static com.android.server.wm.AlphaAnimationSpecProto.TO;
import static com.android.server.wm.AnimationSpecProto.ALPHA;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
import android.annotation.Nullable;
import android.graphics.Rect;
@@ -29,6 +30,8 @@
import android.view.SurfaceControl;
import com.android.internal.annotations.VisibleForTesting;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -135,7 +138,7 @@
mDimLayer = dimLayer;
mDimming = true;
final DimAnimatable dimAnimatable = new DimAnimatable(dimLayer);
- mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, () -> {
+ mSurfaceAnimator = new SurfaceAnimator(dimAnimatable, (type, anim) -> {
if (!mDimming) {
dimAnimatable.removeSurface();
}
@@ -157,8 +160,8 @@
@VisibleForTesting
interface SurfaceAnimatorStarter {
void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
- AnimationAdapter anim, boolean hidden,
- @Nullable Runnable animationFinishedCallback);
+ AnimationAdapter anim, boolean hidden, @AnimationType int type,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback);
}
Dimmer(WindowContainer host) {
@@ -345,7 +348,7 @@
mSurfaceAnimatorStarter.startAnimation(animator, t, new LocalAnimationAdapter(
new AlphaAnimationSpec(startAlpha, endAlpha, getDimDuration(container)),
mHost.mWmService.mSurfaceAnimationRunner), false /* hidden */,
- null /* animationFinishedCallback */);
+ ANIMATION_TYPE_DIMMER, null /* animationFinishedCallback */);
}
private long getDimDuration(WindowContainer container) {
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
new file mode 100644
index 0000000..b3edc91
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSET;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
+import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+
+import static com.android.internal.util.Preconditions.checkState;
+import static com.android.server.wm.DisplayAreaChildProto.DISPLAY_AREA;
+import static com.android.server.wm.DisplayAreaChildProto.UNKNOWN;
+import static com.android.server.wm.DisplayAreaChildProto.WINDOW;
+import static com.android.server.wm.DisplayAreaProto.CHILDREN;
+import static com.android.server.wm.DisplayAreaProto.NAME;
+import static com.android.server.wm.DisplayAreaProto.WINDOW_CONTAINER;
+import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+
+import android.graphics.Rect;
+import android.util.proto.ProtoOutputStream;
+
+import com.android.server.policy.WindowManagerPolicy;
+import com.android.server.protolog.common.ProtoLog;
+
+import java.util.Comparator;
+import java.util.function.Predicate;
+
+/**
+ * Container for grouping WindowContainer below DisplayContent.
+ *
+ * DisplayAreas are managed by a {@link DisplayAreaPolicy}, and can override configurations and
+ * can be leashed.
+ *
+ * DisplayAreas can contain nested DisplayAreas.
+ *
+ * DisplayAreas come in three flavors, to ensure that windows have the right Z-Order:
+ * - BELOW_TASKS: Can only contain BELOW_TASK DisplayAreas and WindowTokens that go below tasks.
+ * - ABOVE_TASKS: Can only contain ABOVE_TASK DisplayAreas and WindowTokens that go above tasks.
+ * - ANY: Can contain any kind of DisplayArea, and any kind of WindowToken or the Task container.
+ * Cannot have a sibling that is of type ANY.
+ *
+ * @param <T> type of the children of the DisplayArea.
+ */
+public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
+
+ protected final Type mType;
+ private final String mName;
+
+ DisplayArea(WindowManagerService wms, Type type, String name) {
+ super(wms);
+ // TODO(display-area): move this up to ConfigurationContainer
+ mOrientation = SCREEN_ORIENTATION_UNSET;
+ mType = type;
+ mName = name;
+ }
+
+ @Override
+ void onChildPositionChanged(WindowContainer child) {
+ super.onChildPositionChanged(child);
+
+ // Verify that we have proper ordering
+ Type.checkChild(mType, Type.typeOf(child));
+
+ if (child instanceof ActivityStack) {
+ // TODO(display-area): ActivityStacks are type ANY, but are allowed to have siblings.
+ // They might need a separate type.
+ return;
+ }
+
+ for (int i = 1; i < getChildCount(); i++) {
+ final WindowContainer top = getChildAt(i - 1);
+ final WindowContainer bottom = getChildAt(i);
+ if (child == top || child == bottom) {
+ Type.checkSiblings(Type.typeOf(top), Type.typeOf(bottom));
+ }
+ }
+ }
+
+ @Override
+ boolean fillsParent() {
+ return true;
+ }
+
+ @Override
+ String getName() {
+ return mName;
+ }
+
+ @Override
+ public final void dumpDebug(ProtoOutputStream proto, long fieldId, int logLevel) {
+ final long token = proto.start(fieldId);
+ super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
+ proto.write(NAME, mName);
+ for (int i = 0; i < getChildCount(); i++) {
+ final long childToken = proto.start(CHILDREN);
+ final T child = getChildAt(i);
+ if (child instanceof ActivityStack) {
+ // TODO(display-area): Dump stacks & tasks here, instead of in DisplayContent's
+ // dumpDebug. For now, skip them here to avoid dumping them as UNKNOWN.
+ } else if (child instanceof WindowToken) {
+ ((WindowToken) child).dumpDebug(proto, WINDOW, logLevel);
+ } else if (child instanceof DisplayArea) {
+ child.dumpDebug(proto, DISPLAY_AREA, logLevel);
+ } else {
+ proto.write(UNKNOWN, child.getClass().getSimpleName());
+ }
+ proto.end(childToken);
+ }
+ proto.end(token);
+ }
+
+ /**
+ * DisplayArea that contains WindowTokens, and orders them according to their type.
+ */
+ public static class Tokens extends DisplayArea<WindowToken> {
+ int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
+
+ private final Comparator<WindowToken> mWindowComparator =
+ Comparator.comparingInt(WindowToken::getWindowLayerFromType);
+
+ private final Predicate<WindowState> mGetOrientingWindow = w -> {
+ final WindowManagerPolicy policy = mWmService.mPolicy;
+ if (policy.isKeyguardHostWindow(w.mAttrs)) {
+ if (mWmService.mKeyguardGoingAway) {
+ return false;
+ }
+ // Consider unoccluding only when all unknown visibilities have been
+ // resolved, as otherwise we just may be starting another occluding activity.
+ final boolean isUnoccluding =
+ mDisplayContent.mAppTransition.getAppTransition()
+ == TRANSIT_KEYGUARD_UNOCCLUDE
+ && mDisplayContent.mUnknownAppVisibilityController.allResolved();
+ // If keyguard is showing, or we're unoccluding, force the keyguard's orientation,
+ // even if SystemUI hasn't updated the attrs yet.
+ if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) {
+ return true;
+ }
+ }
+ final int req = w.mAttrs.screenOrientation;
+ if (req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND
+ || req == SCREEN_ORIENTATION_UNSET) {
+ return false;
+ }
+ return true;
+ };
+
+ Tokens(WindowManagerService wms, Type type, String name) {
+ super(wms, type, name);
+ }
+
+ void addChild(WindowToken token) {
+ addChild(token, mWindowComparator);
+ }
+
+ @Override
+ int getOrientation(int candidate) {
+ // Find a window requesting orientation.
+ final WindowState win = getWindow(mGetOrientingWindow);
+
+ if (win == null) {
+ return candidate;
+ }
+ int req = win.mAttrs.screenOrientation;
+ ProtoLog.v(WM_DEBUG_ORIENTATION, "%s forcing orientation to %d for display id=%d",
+ win, req, mDisplayContent.getDisplayId());
+ if (mWmService.mPolicy.isKeyguardHostWindow(win.mAttrs)) {
+ // SystemUI controls the Keyguard orientation asynchronously, and mAttrs may be
+ // stale. We record / use the last known override.
+ if (req != SCREEN_ORIENTATION_UNSET && req != SCREEN_ORIENTATION_UNSPECIFIED) {
+ mLastKeyguardForcedOrientation = req;
+ } else {
+ req = mLastKeyguardForcedOrientation;
+ }
+ }
+ return req;
+ }
+ }
+
+ /**
+ * Top-most DisplayArea under DisplayContent.
+ */
+ public static class Root extends DisplayArea<DisplayArea> {
+ private final Dimmer mDimmer = new Dimmer(this);
+ private final Rect mTmpDimBoundsRect = new Rect();
+
+ Root(WindowManagerService wms) {
+ super(wms, Type.ANY, "DisplayArea.Root");
+ }
+
+ @Override
+ Dimmer getDimmer() {
+ return mDimmer;
+ }
+
+ @Override
+ void prepareSurfaces() {
+ mDimmer.resetDimStates();
+ super.prepareSurfaces();
+ getBounds(mTmpDimBoundsRect);
+
+ if (mDimmer.updateDims(getPendingTransaction(), mTmpDimBoundsRect)) {
+ scheduleAnimation();
+ }
+ }
+ }
+
+ enum Type {
+ /** Can only contain WindowTokens above the APPLICATION_LAYER. */
+ ABOVE_TASKS,
+ /** Can only contain WindowTokens below the APPLICATION_LAYER. */
+ BELOW_TASKS,
+ /** Can contain anything. */
+ ANY;
+
+ static void checkSiblings(Type bottom, Type top) {
+ checkState(!(bottom == ANY && top == ANY), "ANY cannot be a sibling of ANY");
+ checkState(!(bottom != BELOW_TASKS && top == BELOW_TASKS),
+ bottom + " must be above BELOW_TASKS");
+ checkState(!(bottom == ABOVE_TASKS && top != ABOVE_TASKS),
+ top + " must be below ABOVE_TASKS");
+ }
+
+ static void checkChild(Type parent, Type child) {
+ switch (parent) {
+ case ABOVE_TASKS:
+ checkState(child == ABOVE_TASKS, "ABOVE_TASKS can only contain ABOVE_TASKS");
+ break;
+ case BELOW_TASKS:
+ checkState(child == BELOW_TASKS, "BELOW_TASKS can only contain BELOW_TASKS");
+ break;
+ }
+ }
+
+ static Type typeOf(WindowContainer c) {
+ if (c instanceof DisplayArea) {
+ return ((DisplayArea) c).mType;
+ } else if (c instanceof WindowToken && !(c instanceof ActivityRecord)) {
+ return typeOf((WindowToken) c);
+ } else if (c instanceof ActivityStack) {
+ return ANY;
+ } else {
+ throw new IllegalArgumentException("Unknown container: " + c);
+ }
+ }
+
+ private static Type typeOf(WindowToken c) {
+ return c.getWindowLayerFromType() < APPLICATION_LAYER ? BELOW_TASKS : ABOVE_TASKS;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicy.java b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
new file mode 100644
index 0000000..06e7b48
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicy.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+
+import com.android.server.wm.DisplayContent.TaskContainers;
+
+/**
+ * Policy that manages DisplayAreas.
+ */
+public abstract class DisplayAreaPolicy {
+ protected final WindowManagerService mWmService;
+ protected final DisplayContent mContent;
+
+ /**
+ * The root DisplayArea. Attach all DisplayAreas to this area (directly or indirectly).
+ */
+ protected final DisplayArea.Root mRoot;
+
+ /**
+ * The IME container. The IME's windows are automatically added to this container.
+ */
+ protected final DisplayArea<? extends WindowContainer> mImeContainer;
+
+ /**
+ * The Tasks container. Tasks etc. are automatically added to this container.
+ */
+ protected final TaskContainers mTaskContainers;
+
+ DisplayAreaPolicy(WindowManagerService wmService,
+ DisplayContent content, DisplayArea.Root root,
+ DisplayArea<? extends WindowContainer> imeContainer, TaskContainers taskContainers) {
+ mWmService = wmService;
+ mContent = content;
+ mRoot = root;
+ mImeContainer = imeContainer;
+ mTaskContainers = taskContainers;
+ }
+
+ /**
+ * Called to ask the policy to set up the DisplayArea hierarchy. At a minimum this must:
+ *
+ * - attach mImeContainer to mRoot (or one of its descendants)
+ * - attach mTaskStacks to mRoot (or one of its descendants)
+ *
+ * Additionally, this is the right place to set up any other DisplayAreas as desired.
+ */
+ public abstract void attachDisplayAreas();
+
+ /**
+ * Called to ask the policy to attach the given WindowToken to the DisplayArea hierarchy.
+ *
+ * This must attach the token to mRoot (or one of its descendants).
+ */
+ public abstract void addWindow(WindowToken token);
+
+ /**
+ * Default policy that has no special features.
+ */
+ public static class Default extends DisplayAreaPolicy {
+
+ public Default(WindowManagerService wmService, DisplayContent content,
+ DisplayArea.Root root,
+ DisplayArea<? extends WindowContainer> imeContainer,
+ TaskContainers taskContainers) {
+ super(wmService, content, root, imeContainer, taskContainers);
+ }
+
+ private final DisplayArea.Tokens mBelow = new DisplayArea.Tokens(mWmService,
+ DisplayArea.Type.BELOW_TASKS, "BelowTasks");
+ private final DisplayArea<DisplayArea> mAbove = new DisplayArea<>(mWmService,
+ DisplayArea.Type.ABOVE_TASKS, "AboveTasks");
+ private final DisplayArea.Tokens mAboveBelowIme = new DisplayArea.Tokens(mWmService,
+ DisplayArea.Type.ABOVE_TASKS, "AboveTasksBelowIme");
+ private final DisplayArea.Tokens mAboveAboveIme = new DisplayArea.Tokens(mWmService,
+ DisplayArea.Type.ABOVE_TASKS, "AboveTasksAboveIme");
+
+ @Override
+ public void attachDisplayAreas() {
+ mRoot.addChild(mBelow, 0);
+ mRoot.addChild(mTaskContainers, 1);
+ mRoot.addChild(mAbove, 2);
+
+ mAbove.addChild(mAboveBelowIme, 0);
+ mAbove.addChild(mImeContainer, 1);
+ mAbove.addChild(mAboveAboveIme, 2);
+ }
+
+ @Override
+ public void addWindow(WindowToken token) {
+ switch (DisplayArea.Type.typeOf(token)) {
+ case ABOVE_TASKS:
+ if (token.getWindowLayerFromType()
+ < mWmService.mPolicy.getWindowLayerFromTypeLw(TYPE_INPUT_METHOD)) {
+ mAboveBelowIme.addChild(token);
+ } else {
+ mAboveAboveIme.addChild(token);
+ }
+ break;
+ case BELOW_TASKS:
+ mBelow.addChild(token);
+ break;
+ default:
+ throw new IllegalArgumentException("don't know how to sort " + token);
+ }
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 6e479b2..16ac9fb 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -17,6 +17,7 @@
package com.android.server.wm;
import static android.app.ActivityTaskManager.INVALID_STACK_ID;
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.ActivityTaskManager.SPLIT_SCREEN_CREATE_MODE_TOP_OR_LEFT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_RECENTS;
@@ -80,14 +81,12 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
-import static com.android.server.am.ActivityDisplayProto.DISPLAY;
-import static com.android.server.am.ActivityDisplayProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityDisplayProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityDisplayProto.SINGLE_TASK_INSTANCE;
+import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
+import static com.android.server.wm.DisplayContentProto.RESUMED_ACTIVITY;
+import static com.android.server.wm.DisplayContentProto.SINGLE_TASK_INSTANCE;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -98,9 +97,7 @@
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_STATES;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_TASKS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.wm.DisplayContentProto.ABOVE_APP_WINDOWS;
import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.BELOW_APP_WINDOWS;
import static com.android.server.wm.DisplayContentProto.CHANGING_APPS;
import static com.android.server.wm.DisplayContentProto.CLOSING_APPS;
import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
@@ -109,12 +106,12 @@
import static com.android.server.wm.DisplayContentProto.DPI;
import static com.android.server.wm.DisplayContentProto.FOCUSED_APP;
import static com.android.server.wm.DisplayContentProto.ID;
-import static com.android.server.wm.DisplayContentProto.IME_WINDOWS;
import static com.android.server.wm.DisplayContentProto.OPENING_APPS;
import static com.android.server.wm.DisplayContentProto.OVERLAY_WINDOWS;
+import static com.android.server.wm.DisplayContentProto.ROOT_DISPLAY_AREA;
import static com.android.server.wm.DisplayContentProto.ROTATION;
import static com.android.server.wm.DisplayContentProto.SCREEN_ROTATION_ANIMATION;
-import static com.android.server.wm.DisplayContentProto.STACKS;
+import static com.android.server.wm.DisplayContentProto.TASKS;
import static com.android.server.wm.DisplayContentProto.WINDOW_CONTAINER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
@@ -207,6 +204,7 @@
import android.view.Gravity;
import android.view.IDisplayWindowInsetsController;
import android.view.ISystemGestureExclusionListener;
+import android.view.ITaskOrganizer;
import android.view.IWindow;
import android.view.InputChannel;
import android.view.InputDevice;
@@ -295,14 +293,7 @@
/** The containers below are the only child containers {@link #mWindowContainers} can have. */
// Contains all window containers that are related to apps (Activities)
private final TaskContainers mTaskContainers = new TaskContainers(mWmService);
- // Contains all non-app window containers that should be displayed above the app containers
- // (e.g. Status bar)
- private final AboveAppWindowContainers mAboveAppWindowsContainers =
- new AboveAppWindowContainers("mAboveAppWindowsContainers", mWmService);
- // Contains all non-app window containers that should be displayed below the app containers
- // (e.g. Wallpaper).
- private final NonAppWindowContainers mBelowAppWindowsContainers =
- new NonAppWindowContainers("mBelowAppWindowsContainers", mWmService);
+
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
@@ -310,6 +301,11 @@
// TODO(display-area): is "no magnification" in the comment still true?
private final ImeContainer mImeWindowsContainers = new ImeContainer(mWmService);
+ private final DisplayArea.Root mRootDisplayArea = new DisplayArea.Root(mWmService);
+
+ private final DisplayAreaPolicy mDisplayAreaPolicy = new DisplayAreaPolicy.Default(
+ mWmService, this, mRootDisplayArea, mImeWindowsContainers, mTaskContainers);
+
private WindowState mTmpWindow;
private WindowState mTmpWindow2;
private boolean mUpdateImeTarget;
@@ -401,14 +397,6 @@
private int mCurrentOverrideConfigurationChanges;
/**
- * Last orientation forced by the keyguard. It is applied when keyguard is shown and is not
- * occluded.
- *
- * @see NonAppWindowContainers#getOrientation()
- */
- private int mLastKeyguardForcedOrientation = SCREEN_ORIENTATION_UNSPECIFIED;
-
- /**
* The maximum aspect ratio (longerSide/shorterSide) that is treated as close-to-square. The
* orientation requests from apps would be ignored if the display is close-to-square.
*/
@@ -664,6 +652,9 @@
private final RootWindowContainer.FindTaskResult
mTmpFindTaskResult = new RootWindowContainer.FindTaskResult();
+ // When non-null, new stacks get put into this tile.
+ TaskTile mLaunchTile = null;
+
private final Consumer<WindowState> mUpdateWindowsForAnimator = w -> {
WindowStateAnimator winAnimator = w.mWinAnimator;
final ActivityRecord activity = w.mActivityRecord;
@@ -1104,18 +1095,16 @@
// Add non-app token to container hierarchy on the display. App tokens are added through
// the parent container managing them (e.g. Tasks).
switch (token.windowType) {
- case TYPE_WALLPAPER:
- mBelowAppWindowsContainers.addChild(token);
- break;
case TYPE_INPUT_METHOD:
case TYPE_INPUT_METHOD_DIALOG:
mImeWindowsContainers.addChild(token);
break;
case TYPE_ACCESSIBILITY_MAGNIFICATION_OVERLAY:
+ // TODO(display-area): Migrate to DisplayArea
mOverlayContainers.addChild(token);
break;
default:
- mAboveAppWindowsContainers.addChild(token);
+ mDisplayAreaPolicy.addWindow(token);
break;
}
}
@@ -2129,13 +2118,7 @@
return getLastOrientation();
}
}
- final int orientation = mAboveAppWindowsContainers.getOrientation();
- if (orientation != SCREEN_ORIENTATION_UNSET) {
- return orientation;
- }
-
- // Top system windows are not requesting an orientation. Start searching from apps.
- return mTaskContainers.getOrientation();
+ return mRootDisplayArea.getOrientation();
}
void updateDisplayInfo() {
@@ -2750,30 +2733,6 @@
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
- final long token = proto.start(fieldId);
- dumpDebugInner(proto, DISPLAY, logLevel);
- proto.write(com.android.server.am.ActivityDisplayProto.ID, mDisplayId);
- proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
- final ActivityStack focusedStack = getFocusedStack();
- if (focusedStack != null) {
- proto.write(FOCUSED_STACK_ID, focusedStack.getRootTaskId());
- final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
- if (focusedActivity != null) {
- focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
- }
- } else {
- proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
- }
- for (int stackNdx = getStackCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = getStackAt(stackNdx);
- stack.dumpDebug(proto, com.android.server.am.ActivityDisplayProto.STACKS, logLevel);
- }
- proto.end(token);
- }
-
- // TODO(proto-merge): Remove once protos for ActivityDisplay and DisplayContent are merged.
- public void dumpDebugInner(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
// Critical log level logs only visible elements to mitigate performance overheard
if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
return;
@@ -2781,24 +2740,14 @@
final long token = proto.start(fieldId);
super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
+
proto.write(ID, mDisplayId);
- for (int stackNdx = mTaskContainers.getChildCount() - 1; stackNdx >= 0; --stackNdx) {
- final ActivityStack stack = mTaskContainers.getChildAt(stackNdx);
- stack.dumpDebugInnerStackOnly(proto, STACKS, logLevel);
+ mRootDisplayArea.dumpDebug(proto, ROOT_DISPLAY_AREA, logLevel);
+ for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack stack = mTaskContainers.getChildAt(i);
+ stack.dumpDebug(proto, TASKS, logLevel);
}
mDividerControllerLocked.dumpDebug(proto, DOCKED_STACK_DIVIDER_CONTROLLER);
- for (int i = mAboveAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
- final WindowToken windowToken = mAboveAppWindowsContainers.getChildAt(i);
- windowToken.dumpDebug(proto, ABOVE_APP_WINDOWS, logLevel);
- }
- for (int i = mBelowAppWindowsContainers.getChildCount() - 1; i >= 0; --i) {
- final WindowToken windowToken = mBelowAppWindowsContainers.getChildAt(i);
- windowToken.dumpDebug(proto, BELOW_APP_WINDOWS, logLevel);
- }
- for (int i = mImeWindowsContainers.getChildCount() - 1; i >= 0; --i) {
- final WindowToken windowToken = mImeWindowsContainers.getChildAt(i);
- windowToken.dumpDebug(proto, IME_WINDOWS, logLevel);
- }
for (int i = mOverlayContainers.getChildCount() - 1; i >= 0; --i) {
final WindowToken windowToken = mOverlayContainers.getChildAt(i);
windowToken.dumpDebug(proto, OVERLAY_WINDOWS, logLevel);
@@ -2824,6 +2773,19 @@
for (int i = mChangingApps.size() - 1; i >= 0; i--) {
mChangingApps.valueAt(i).writeIdentifierToProto(proto, CHANGING_APPS);
}
+
+ proto.write(SINGLE_TASK_INSTANCE, mSingleTaskInstance);
+ final ActivityStack focusedStack = getFocusedStack();
+ if (focusedStack != null) {
+ proto.write(FOCUSED_ROOT_TASK_ID, focusedStack.getRootTaskId());
+ final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
+ if (focusedActivity != null) {
+ focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
+ }
+ } else {
+ proto.write(FOCUSED_ROOT_TASK_ID, INVALID_TASK_ID);
+ }
+
proto.end(token);
}
@@ -4212,7 +4174,7 @@
* Window container class that contains all containers on this display relating to Apps.
* I.e Activities.
*/
- private final class TaskContainers extends DisplayChildWindowContainer<ActivityStack> {
+ final class TaskContainers extends DisplayArea<ActivityStack> {
/**
* A control placed at the appropriate level for transitions to occur.
*/
@@ -4222,16 +4184,15 @@
/**
* Given that the split-screen divider does not have an AppWindowToken, it
- * will have to live inside of a "NonAppWindowContainer", in particular
- * {@link DisplayContent#mAboveAppWindowsContainers}. However, in visual Z order
+ * will have to live inside of a "NonAppWindowContainer". However, in visual Z order
* it will need to be interleaved with some of our children, appearing on top of
* both docked stacks but underneath any assistant stacks.
*
* To solve this problem we have this anchor control, which will always exist so
* we can always assign it the correct value in our {@link #assignChildLayers}.
- * Likewise since it always exists, {@link AboveAppWindowContainers} can always
+ * Likewise since it always exists, we can always
* assign the divider a layer relative to it. This way we prevent linking lifecycle
- * events between the two containers.
+ * events between tasks and the divider window.
*/
SurfaceControl mSplitScreenDividerAnchor = null;
@@ -4242,7 +4203,7 @@
private ActivityStack mRootSplitScreenPrimaryTask = null;
TaskContainers(WindowManagerService service) {
- super(service);
+ super(service, Type.ANY, "TaskContainers");
}
/**
@@ -4275,8 +4236,15 @@
@VisibleForTesting
ActivityStack getTopStack() {
- return mTaskContainers.getChildCount() > 0
- ? mTaskContainers.getChildAt(mTaskContainers.getChildCount() - 1) : null;
+ // TODO(task-hierarchy): Just grab index -1 once tiles are in hierarchy.
+ for (int i = mTaskContainers.getChildCount() - 1; i >= 0; --i) {
+ final ActivityStack child = mTaskContainers.getChildAt(i);
+ if (child instanceof TaskTile) {
+ continue;
+ }
+ return child;
+ }
+ return null;
}
int getIndexOf(ActivityStack stack) {
@@ -4318,6 +4286,10 @@
}
private void addStackReferenceIfNeeded(ActivityStack stack) {
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ if (stack instanceof TaskTile) {
+ return;
+ }
if (stack.isActivityTypeHome()) {
if (mRootHomeTask != null) {
if (!stack.isDescendantOf(mRootHomeTask)) {
@@ -4735,31 +4707,16 @@
mSplitScreenDividerAnchor = null;
}
}
- }
-
- private final class AboveAppWindowContainers extends NonAppWindowContainers {
- AboveAppWindowContainers(String name, WindowManagerService service) {
- super(name, service);
- }
@Override
- void assignChildLayers(SurfaceControl.Transaction t) {
- boolean needAssignIme = mImeWindowsContainers.getSurfaceControl() != null;
- for (int j = 0; j < mChildren.size(); ++j) {
- final WindowToken wt = mChildren.get(j);
-
- wt.assignLayer(t, j);
- wt.assignChildLayers(t);
-
- int layer = mWmService.mPolicy.getWindowLayerFromTypeLw(
- wt.windowType, wt.mOwnerCanManageAppTokens);
-
- if (needAssignIme && layer >= mWmService.mPolicy.getWindowLayerFromTypeLw(
- TYPE_INPUT_METHOD_DIALOG, true)) {
- mImeWindowsContainers.assignRelativeLayer(t, wt.getSurfaceControl(), -1);
- needAssignIme = false;
- }
+ void onChildPositionChanged(WindowContainer child) {
+ // TODO(task-hierarchy): Move functionality to TaskTile when it's a proper parent.
+ TaskTile tile = ((ActivityStack) child).getTile();
+ if (tile == null) {
+ return;
}
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ tile, false /* force */);
}
}
@@ -4774,13 +4731,10 @@
@Override
void assignChildLayers(SurfaceControl.Transaction t) {
mImeWindowsContainers.setNeedsLayer();
- mBelowAppWindowsContainers.assignLayer(t, 0);
- mTaskContainers.assignLayer(t, 1);
- mAboveAppWindowsContainers.assignLayer(t, 2);
+
+ mRootDisplayArea.assignLayer(t, 0);
final WindowState imeTarget = mInputMethodTarget;
- boolean needAssignIme = true;
-
// In the case where we have an IME target that is not in split-screen mode IME
// assignment is easy. We just need the IME to go directly above the target. This way
// children of the target will naturally go above the IME and everyone is happy.
@@ -4813,11 +4767,7 @@
// Above we have assigned layers to our children, now we ask them to assign
// layers to their children.
- mBelowAppWindowsContainers.assignChildLayers(t);
- mTaskContainers.assignChildLayers(t);
- mAboveAppWindowsContainers.assignChildLayers(t);
- mImeWindowsContainers.assignRelativeLayer(t, getSurfaceControl(), Integer.MAX_VALUE);
- mImeWindowsContainers.assignChildLayers(t);
+ mRootDisplayArea.assignChildLayers(t);
}
@Override
@@ -4826,10 +4776,8 @@
}
void addChildren() {
- addChild(mBelowAppWindowsContainers, null);
- addChild(mTaskContainers, null);
- addChild(mAboveAppWindowsContainers, null);
- addChild(mImeWindowsContainers, null);
+ addChild(mRootDisplayArea, 0);
+ mDisplayAreaPolicy.attachDisplayAreas();
}
@Override
@@ -4856,32 +4804,6 @@
< mWmService.mPolicy.getWindowLayerFromTypeLw(token2.windowType,
token2.mOwnerCanManageAppTokens) ? -1 : 1;
- private final Predicate<WindowState> mGetOrientingWindow = w -> {
- final WindowManagerPolicy policy = mWmService.mPolicy;
- if (policy.isKeyguardHostWindow(w.mAttrs)) {
- if (mWmService.mKeyguardGoingAway) {
- return false;
- }
- // Consider unoccluding only when all unknown visibilities have been
- // resolved, as otherwise we just may be starting another occluding activity.
- final boolean isUnoccluding =
- mDisplayContent.mAppTransition.getAppTransition()
- == TRANSIT_KEYGUARD_UNOCCLUDE
- && mDisplayContent.mUnknownAppVisibilityController.allResolved();
- // If keyguard is showing, or we're unoccluding, force the keyguard's orientation,
- // even if SystemUI hasn't updated the attrs yet.
- if (policy.isKeyguardShowingAndNotOccluded() || isUnoccluding) {
- return true;
- }
- }
- final int req = w.mAttrs.screenOrientation;
- if (req == SCREEN_ORIENTATION_UNSPECIFIED || req == SCREEN_ORIENTATION_BEHIND
- || req == SCREEN_ORIENTATION_UNSET) {
- return false;
- }
- return true;
- };
-
private final String mName;
private final Dimmer mDimmer = new Dimmer(this);
private final Rect mTmpDimBoundsRect = new Rect();
@@ -4903,26 +4825,9 @@
@Override
int getOrientation(int candidate) {
- // Find a window requesting orientation.
- final WindowState win = getWindow(mGetOrientingWindow);
-
- if (win != null) {
- int req = win.mAttrs.screenOrientation;
- ProtoLog.v(WM_DEBUG_ORIENTATION,
- "%s forcing orientation to %d for display id=%d", win, req,
- mDisplayId);
- if (mWmService.mPolicy.isKeyguardHostWindow(win.mAttrs)) {
- // SystemUI controls the Keyguard orientation asynchronously, and mAttrs may be
- // stale. We record / use the last known override.
- if (req != SCREEN_ORIENTATION_UNSET && req != SCREEN_ORIENTATION_UNSPECIFIED) {
- mDisplayContent.mLastKeyguardForcedOrientation = req;
- } else {
- req = mDisplayContent.mLastKeyguardForcedOrientation;
- }
- }
- return req;
- }
- return candidate;
+ ProtoLog.w(WM_DEBUG_ORIENTATION, "NonAppWindowContainer cannot set orientation: %s",
+ this);
+ return SCREEN_ORIENTATION_UNSET;
}
@Override
@@ -4957,11 +4862,11 @@
* - the container doesn't always participate in window traversal, according to
* {@link #skipImeWindowsDuringTraversal()}
*/
- private class ImeContainer extends NonAppWindowContainers {
+ private static class ImeContainer extends DisplayArea.Tokens {
boolean mNeedsLayer = false;
ImeContainer(WindowManagerService wms) {
- super("ImeContainer", wms);
+ super(wms, Type.ABOVE_TASKS, "ImeContainer");
}
public void setNeedsLayer() {
@@ -6271,6 +6176,10 @@
}
boolean isTopNotPinnedStack(ActivityStack stack) {
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ if (stack instanceof TaskTile) {
+ return false;
+ }
for (int i = getStackCount() - 1; i >= 0; --i) {
final ActivityStack current = getStackAt(i);
if (!current.inPinnedWindowingMode()) {
@@ -6685,6 +6594,19 @@
return getHomeActivityForUser(mRootWindowContainer.mCurrentUser);
}
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ void addTile(TaskTile tile) {
+ mTaskContainers.addChild(tile, POSITION_BOTTOM);
+ ITaskOrganizer organizer = mAtmService.mTaskOrganizerController.getTaskOrganizer(
+ tile.getWindowingMode());
+ tile.setTaskOrganizer(organizer);
+ }
+
+ // TODO(task-hierarchy): Remove when tiles are in hierarchy.
+ void removeTile(TaskTile tile) {
+ mTaskContainers.removeChild(tile);
+ }
+
@Nullable
ActivityRecord getHomeActivityForUser(int userId) {
final ActivityStack homeStack = getRootHomeTask();
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 40c335b..c78707a 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -335,6 +335,13 @@
IApplicationToken mFocusedApp;
+ // The states of decor windows from the last layout. These are used to generate another display
+ // layout in different bounds but with the same states.
+ private boolean mLastNavVisible;
+ private boolean mLastNavTranslucent;
+ private boolean mLastNavAllowedHidden;
+ private boolean mLastNotificationShadeForcesShowingNavigation;
+
int mLastSystemUiFlags;
// Bits that we are in the process of clearing, so we want to prevent
// them from being set by applications until everything has been updated
@@ -1425,6 +1432,46 @@
}
}
+ private void simulateLayoutDecorWindow(WindowState win, DisplayFrames displayFrames, int uiMode,
+ InsetsState insetsState, WindowFrames simulatedWindowFrames, Runnable layout) {
+ win.setSimulatedWindowFrames(simulatedWindowFrames);
+ try {
+ layout.run();
+ } finally {
+ win.setSimulatedWindowFrames(null);
+ }
+ mDisplayContent.getInsetsStateController().computeSimulatedState(insetsState, win,
+ displayFrames, simulatedWindowFrames);
+ }
+
+ /**
+ * Computes the frames of display (its logical size, rotation and cutout should already be set)
+ * used to layout window. The result of display frames and insets state should be the same as
+ * using {@link #beginLayoutLw}, but this method only changes the given display frames, insets
+ * state and some temporal states. In other words, it doesn't change the window frames used to
+ * show on screen.
+ */
+ void simulateLayoutDisplay(DisplayFrames displayFrames, InsetsState insetsState, int uiMode) {
+ displayFrames.onBeginLayout();
+ final WindowFrames simulatedWindowFrames = new WindowFrames();
+ if (mNavigationBar != null) {
+ simulateLayoutDecorWindow(
+ mNavigationBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
+ () -> layoutNavigationBar(displayFrames, uiMode, mLastNavVisible,
+ mLastNavTranslucent, mLastNavAllowedHidden,
+ mLastNotificationShadeForcesShowingNavigation,
+ false /* isRealLayout */));
+ }
+ if (mStatusBar != null) {
+ simulateLayoutDecorWindow(
+ mStatusBar, displayFrames, uiMode, insetsState, simulatedWindowFrames,
+ () -> layoutStatusBar(displayFrames, mLastSystemUiFlags,
+ false /* isRealLayout */));
+ }
+ layoutScreenDecorWindows(displayFrames, simulatedWindowFrames);
+ postAdjustDisplayFrames(displayFrames);
+ }
+
/**
* Called when layout of the windows is about to start.
*
@@ -1483,14 +1530,23 @@
navVisible |= !canHideNavigationBar();
boolean updateSysUiVisibility = layoutNavigationBar(displayFrames, uiMode, navVisible,
- navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation);
+ navTranslucent, navAllowedHidden, notificationShadeForcesShowingNavigation,
+ true /* isRealLayout */);
if (DEBUG_LAYOUT) Slog.i(TAG, "mDock rect:" + displayFrames.mDock);
- updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, isKeyguardShowing);
+ updateSysUiVisibility |= layoutStatusBar(displayFrames, sysui, true /* isRealLayout */);
if (updateSysUiVisibility) {
updateSystemUiVisibilityLw();
}
- layoutScreenDecorWindows(displayFrames);
+ layoutScreenDecorWindows(displayFrames, null /* transientFrames */);
+ postAdjustDisplayFrames(displayFrames);
+ mLastNavVisible = navVisible;
+ mLastNavTranslucent = navTranslucent;
+ mLastNavAllowedHidden = navAllowedHidden;
+ mLastNotificationShadeForcesShowingNavigation = notificationShadeForcesShowingNavigation;
+ }
+ /** Enforces the last layout policy for display frames. */
+ private void postAdjustDisplayFrames(DisplayFrames displayFrames) {
if (displayFrames.mDisplayCutoutSafe.top > displayFrames.mUnrestricted.top) {
// Make sure that the zone we're avoiding for the cutout is at least as tall as the
// status bar; otherwise fullscreen apps will end up cutting halfway into the status
@@ -1509,7 +1565,15 @@
displayFrames.mContent.inset(mForwardedInsets);
}
- private void layoutScreenDecorWindows(DisplayFrames displayFrames) {
+ /**
+ * Layout the decor windows with {@link #PRIVATE_FLAG_IS_SCREEN_DECOR}.
+ *
+ * @param displayFrames The display frames to be layouted.
+ * @param simulatedFrames Non-null if the caller only needs the result of display frames (see
+ * {@link WindowState#mSimulatedWindowFrames}).
+ */
+ private void layoutScreenDecorWindows(DisplayFrames displayFrames,
+ WindowFrames simulatedFrames) {
if (mScreenDecorWindows.isEmpty()) {
return;
}
@@ -1527,17 +1591,24 @@
continue;
}
- w.getWindowFrames().setFrames(displayFrames.mUnrestricted /* parentFrame */,
+ final boolean isSimulatedLayout = simulatedFrames != null;
+ if (isSimulatedLayout) {
+ w.setSimulatedWindowFrames(simulatedFrames);
+ }
+ final WindowFrames windowFrames = w.getLayoutingWindowFrames();
+ windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
displayFrames.mUnrestricted /* contentFrame */,
displayFrames.mUnrestricted /* visibleFrame */, sTmpRect /* decorFrame */,
displayFrames.mUnrestricted /* stableFrame */);
- w.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- w.computeFrameLw();
- if (w.getControllableInsetProvider() != null) {
- w.getControllableInsetProvider().updateSourceFrame();
+ try {
+ w.computeFrame(displayFrames);
+ } finally {
+ if (isSimulatedLayout) {
+ w.setSimulatedWindowFrames(null);
+ }
}
- final Rect frame = w.getFrameLw();
+ final Rect frame = windowFrames.mFrame;
if (frame.left <= 0 && frame.top <= 0) {
// Docked at left or top.
@@ -1580,29 +1651,21 @@
displayFrames.mContent.set(dockFrame);
}
- private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui,
- boolean isKeyguardShowing) {
+ private boolean layoutStatusBar(DisplayFrames displayFrames, int sysui, boolean isRealLayout) {
// decide where the status bar goes ahead of time
if (mStatusBar == null) {
return false;
}
// apply any navigation bar insets
sTmpRect.setEmpty();
- final WindowFrames windowFrames = mStatusBar.getWindowFrames();
+ final WindowFrames windowFrames = mStatusBar.getLayoutingWindowFrames();
windowFrames.setFrames(displayFrames.mUnrestricted /* parentFrame */,
displayFrames.mUnrestricted /* displayFrame */,
displayFrames.mStable /* contentFrame */,
displayFrames.mStable /* visibleFrame */, sTmpRect /* decorFrame */,
displayFrames.mStable /* stableFrame */);
- windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
-
// Let the status bar determine its size.
- mStatusBar.computeFrameLw();
-
- // Update the source frame to provide insets to other windows during layout.
- if (mStatusBar.getControllableInsetProvider() != null) {
- mStatusBar.getControllableInsetProvider().updateSourceFrame();
- }
+ mStatusBar.computeFrame(displayFrames);
// For layout, the status bar is always at the top with our fixed height.
displayFrames.mStable.top = displayFrames.mUnrestricted.top
@@ -1611,12 +1674,14 @@
displayFrames.mStable.top = Math.max(displayFrames.mStable.top,
displayFrames.mDisplayCutoutSafe.top);
- // Tell the bar controller where the collapsed status bar content is
- sTmpRect.set(mStatusBar.getContentFrameLw());
- sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
- sTmpRect.top = mStatusBar.getContentFrameLw().top; // Ignore top display cutout inset
- sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
- mStatusBarController.setContentFrame(sTmpRect);
+ if (isRealLayout) {
+ // Tell the bar controller where the collapsed status bar content is.
+ sTmpRect.set(windowFrames.mContentFrame);
+ sTmpRect.intersect(displayFrames.mDisplayCutoutSafe);
+ sTmpRect.top = windowFrames.mContentFrame.top; // Ignore top display cutout inset
+ sTmpRect.bottom = displayFrames.mStable.top; // Use collapsed status bar size
+ mStatusBarController.setContentFrame(sTmpRect);
+ }
boolean statusBarTransient = (sysui & View.STATUS_BAR_TRANSIENT) != 0
|| mDisplayContent.getInsetsPolicy().isTransient(ITYPE_STATUS_BAR);
@@ -1651,7 +1716,7 @@
private boolean layoutNavigationBar(DisplayFrames displayFrames, int uiMode, boolean navVisible,
boolean navTranslucent, boolean navAllowedHidden,
- boolean statusBarForcesShowingNavigation) {
+ boolean statusBarForcesShowingNavigation, boolean isRealLayout) {
if (mNavigationBar == null) {
return false;
}
@@ -1665,13 +1730,13 @@
final int displayHeight = displayFrames.mDisplayHeight;
final int displayWidth = displayFrames.mDisplayWidth;
final Rect dockFrame = displayFrames.mDock;
- mNavigationBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
+ final int navBarPosition = navigationBarPosition(displayWidth, displayHeight, rotation);
final Rect cutoutSafeUnrestricted = sTmpRect;
cutoutSafeUnrestricted.set(displayFrames.mUnrestricted);
cutoutSafeUnrestricted.intersectUnchecked(displayFrames.mDisplayCutoutSafe);
- if (mNavigationBarPosition == NAV_BAR_BOTTOM) {
+ if (navBarPosition == NAV_BAR_BOTTOM) {
// It's a system nav bar or a portrait screen; nav bar goes on bottom.
final int top = cutoutSafeUnrestricted.bottom
- getNavigationBarHeight(rotation, uiMode);
@@ -1695,7 +1760,7 @@
// of animating on or off, then we can tell the app that it is covered by it.
displayFrames.mSystem.bottom = top;
}
- } else if (mNavigationBarPosition == NAV_BAR_RIGHT) {
+ } else if (navBarPosition == NAV_BAR_RIGHT) {
// Landscape screen; nav bar goes to the right.
final int left = cutoutSafeUnrestricted.right
- getNavigationBarWidth(rotation, uiMode);
@@ -1717,7 +1782,7 @@
// animating on or off, then we can tell the app that it is covered by it.
displayFrames.mSystem.right = left;
}
- } else if (mNavigationBarPosition == NAV_BAR_LEFT) {
+ } else if (navBarPosition == NAV_BAR_LEFT) {
// Seascape screen; nav bar goes to the left.
final int right = cutoutSafeUnrestricted.left
+ getNavigationBarWidth(rotation, uiMode);
@@ -1748,17 +1813,17 @@
displayFrames.mContent.set(dockFrame);
// And compute the final frame.
sTmpRect.setEmpty();
- mNavigationBar.getWindowFrames().setFrames(navigationFrame /* parentFrame */,
+ final WindowFrames windowFrames = mNavigationBar.getLayoutingWindowFrames();
+ windowFrames.setFrames(navigationFrame /* parentFrame */,
navigationFrame /* displayFrame */,
displayFrames.mDisplayCutoutSafe /* contentFrame */,
navigationFrame /* visibleFrame */, sTmpRect /* decorFrame */,
navigationFrame /* stableFrame */);
- mNavigationBar.getWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
- mNavigationBar.computeFrameLw();
- if (mNavigationBar.getControllableInsetProvider() != null) {
- mNavigationBar.getControllableInsetProvider().updateSourceFrame();
+ mNavigationBar.computeFrame(displayFrames);
+ if (isRealLayout) {
+ mNavigationBarPosition = navBarPosition;
+ mNavigationBarController.setContentFrame(windowFrames.mContentFrame);
}
- mNavigationBarController.setContentFrame(mNavigationBar.getContentFrameLw());
if (DEBUG_LAYOUT) Slog.i(TAG, "mNavigationBar frame: " + navigationFrame);
return mNavigationBarController.checkHiddenLw();
@@ -1886,7 +1951,6 @@
final Rect sf = windowFrames.mStableFrame;
dcf.setEmpty();
windowFrames.setParentFrameWasClippedByDisplayCutout(false);
- windowFrames.setDisplayCutout(displayFrames.mDisplayCutout);
final boolean hasNavBar = hasNavigationBar() && mNavigationBar != null
&& mNavigationBar.isVisibleLw();
@@ -2311,10 +2375,7 @@
windowFrames.setContentChanged(true);
}
- win.computeFrameLw();
- if (win.getControllableInsetProvider() != null) {
- win.getControllableInsetProvider().updateSourceFrame();
- }
+ win.computeFrame(displayFrames);
// Dock windows carve out the bottom of the screen, so normal windows
// can't appear underneath them.
if (type == TYPE_INPUT_METHOD && win.isVisibleLw()
diff --git a/services/core/java/com/android/server/wm/DisplayRotation.java b/services/core/java/com/android/server/wm/DisplayRotation.java
index da77314..efe79b3 100644
--- a/services/core/java/com/android/server/wm/DisplayRotation.java
+++ b/services/core/java/com/android/server/wm/DisplayRotation.java
@@ -526,7 +526,7 @@
mService.mH.removeCallbacks(mDisplayRotationHandlerTimeout);
mIsWaitingForRemoteRotation = false;
mDisplayContent.sendNewConfiguration();
- mService.mAtmService.applyContainerTransaction(t);
+ mService.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
}
}
diff --git a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
index ef6f847..2f02ffb 100644
--- a/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/wm/ImmersiveModeConfirmation.java
@@ -275,7 +275,7 @@
super.onAttachedToWindow();
DisplayMetrics metrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(metrics);
+ mContext.getDisplay().getMetrics(metrics);
float density = metrics.density;
getViewTreeObserver().addOnComputeInternalInsetsListener(mInsetsListener);
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 2d4211a..d0179ad 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -20,17 +20,31 @@
import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.SyncRtSurfaceTransactionApplier.applyParams;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_SHOW_STATUS_BAR;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_STATUS_FORCE_SHOW_NAVIGATION;
import android.annotation.Nullable;
import android.app.StatusBarManager;
import android.util.IntArray;
+import android.util.SparseArray;
+import android.view.InsetsAnimationControlCallbacks;
+import android.view.InsetsAnimationControlImpl;
+import android.view.InsetsController;
+import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.SurfaceControl;
+import android.view.SyncRtSurfaceTransactionApplier;
import android.view.ViewRootImpl;
+import android.view.WindowInsetsAnimationCallback;
+import android.view.WindowInsetsAnimationControlListener;
+
+import com.android.server.DisplayThread;
/**
* Policy that implements who gets control over the windows generating insets.
@@ -46,6 +60,8 @@
private WindowState mFocusedWin;
private BarWindow mStatusBar = new BarWindow(StatusBarManager.WINDOW_STATUS_BAR);
private BarWindow mNavBar = new BarWindow(StatusBarManager.WINDOW_NAVIGATION_BAR);
+ private boolean mAnimatingShown;
+ private final float[] mTmpFloat9 = new float[9];
InsetsPolicy(InsetsStateController stateController, DisplayContent displayContent) {
mStateController = stateController;
@@ -91,11 +107,14 @@
changed = true;
}
if (changed) {
- updateBarControlTarget(mFocusedWin);
- mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
- mShowingTransientTypes.toArray());
- mStateController.notifyInsetsChanged();
- // TODO(b/118118435): Animation
+ startAnimation(mShowingTransientTypes, true, () -> {
+ synchronized (mDisplayContent.mWmService.mGlobalLock) {
+ mPolicy.getStatusBarManagerInternal().showTransient(
+ mDisplayContent.getDisplayId(),
+ mShowingTransientTypes.toArray());
+ mStateController.notifyInsetsChanged();
+ }
+ });
}
}
@@ -103,11 +122,13 @@
if (mShowingTransientTypes.size() == 0) {
return;
}
-
- // TODO(b/118118435): Animation
- mShowingTransientTypes.clear();
- updateBarControlTarget(mFocusedWin);
- mStateController.notifyInsetsChanged();
+ startAnimation(mShowingTransientTypes, false, () -> {
+ synchronized (mDisplayContent.mWmService.mGlobalLock) {
+ mShowingTransientTypes.clear();
+ mStateController.notifyInsetsChanged();
+ updateBarControlTarget(mFocusedWin);
+ }
+ });
}
boolean isTransient(@InternalInsetsType int type) {
@@ -247,6 +268,29 @@
return isDockedStackVisible || isFreeformStackVisible || isResizing;
}
+ private void startAnimation(IntArray internalTypes, boolean show, Runnable callback) {
+ int typesReady = 0;
+ final SparseArray<InsetsSourceControl> controls = new SparseArray<>();
+ updateBarControlTarget(mFocusedWin);
+ for (int i = internalTypes.size() - 1; i >= 0; i--) {
+ InsetsSourceProvider provider =
+ mStateController.getSourceProvider(internalTypes.get(i));
+ if (provider == null) continue;
+ InsetsSourceControl control = provider.getControl(provider.getControlTarget());
+ if (control == null || control.getLeash() == null) continue;
+ typesReady |= InsetsState.toPublicType(internalTypes.get(i));
+ controls.put(control.getType(), control);
+ }
+ controlAnimationUnchecked(typesReady, controls, show, callback);
+ }
+
+ private void controlAnimationUnchecked(int typesReady,
+ SparseArray<InsetsSourceControl> controls, boolean show, Runnable callback) {
+ InsetsPolicyAnimationControlListener listener =
+ new InsetsPolicyAnimationControlListener(show, callback);
+ listener.mControlCallbacks.controlAnimationUnchecked(typesReady, controls, show);
+ }
+
private class BarWindow {
private final int mId;
@@ -267,7 +311,103 @@
}
}
- // TODO(b/118118435): Implement animations for it (with SurfaceAnimator)
+ private class InsetsPolicyAnimationControlListener extends
+ InsetsController.InternalAnimationControlListener {
+ Runnable mFinishCallback;
+ InsetsPolicyAnimationControlCallbacks mControlCallbacks;
+
+ InsetsPolicyAnimationControlListener(boolean show, Runnable finishCallback) {
+ super(show);
+ mFinishCallback = finishCallback;
+ mControlCallbacks = new InsetsPolicyAnimationControlCallbacks(this);
+ }
+
+ @Override
+ protected void onAnimationFinish() {
+ super.onAnimationFinish();
+ mControlCallbacks.mAnimationControl.finish(mAnimatingShown);
+ DisplayThread.getHandler().post(mFinishCallback);
+ }
+
+ private class InsetsPolicyAnimationControlCallbacks implements
+ InsetsAnimationControlCallbacks {
+ private InsetsAnimationControlImpl mAnimationControl = null;
+ private InsetsPolicyAnimationControlListener mListener;
+
+ InsetsPolicyAnimationControlCallbacks(InsetsPolicyAnimationControlListener listener) {
+ super();
+ mListener = listener;
+ }
+
+ private void controlAnimationUnchecked(int typesReady,
+ SparseArray<InsetsSourceControl> controls, boolean show) {
+ if (typesReady == 0) {
+ // nothing to animate.
+ return;
+ }
+ mAnimatingShown = show;
+
+ mAnimationControl = new InsetsAnimationControlImpl(controls,
+ mFocusedWin.getDisplayContent().getBounds(), getState(),
+ mListener, typesReady, this, mListener.getDurationMs(),
+ InsetsController.INTERPOLATOR, true,
+ show ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+ : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN);
+ }
+
+ /** Called on SurfaceAnimationThread lock without global WM lock held. */
+ @Override
+ public void scheduleApplyChangeInsets() {
+ InsetsState state = getState();
+ if (mAnimationControl.applyChangeInsets(state)) {
+ mAnimationControl.finish(mAnimatingShown);
+ }
+ }
+
+ @Override
+ public void notifyFinished(InsetsAnimationControlImpl controller, boolean shown) {
+ // Nothing's needed here. Finish steps is handled in the listener
+ // onAnimationFinished callback.
+ }
+
+ /**
+ * This method will return a state with fullscreen frame override. No need to make copy
+ * after getting state from this method.
+ * @return The client insets state with full display frame override.
+ */
+ private InsetsState getState() {
+ // To animate the transient animation correctly, we need to let the state hold
+ // the full display frame.
+ InsetsState overrideState = new InsetsState(mFocusedWin.getRequestedInsetsState(),
+ true);
+ overrideState.setDisplayFrame(mFocusedWin.getDisplayContent().getBounds());
+ return overrideState;
+ }
+
+ /** Called on SurfaceAnimationThread lock without global WM lock held. */
+ @Override
+ public void applySurfaceParams(
+ final SyncRtSurfaceTransactionApplier.SurfaceParams... params) {
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (int i = params.length - 1; i >= 0; i--) {
+ SyncRtSurfaceTransactionApplier.SurfaceParams surfaceParams = params[i];
+ applyParams(t, surfaceParams, mTmpFloat9);
+ }
+ t.apply();
+ }
+
+ /** Called on SurfaceAnimationThread lock without global WM lock held. */
+ @Override
+ public void startAnimation(InsetsAnimationControlImpl controller,
+ WindowInsetsAnimationControlListener listener, int types,
+ WindowInsetsAnimationCallback.InsetsAnimation animation,
+ WindowInsetsAnimationCallback.AnimationBounds bounds,
+ int layoutDuringAnimation) {
+ SurfaceAnimationThread.getHandler().post(() -> listener.onReady(controller, types));
+ }
+ }
+ }
+
private class TransientControlTarget implements InsetsControlTarget {
@Override
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index db43480..0418afaf 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -24,6 +24,7 @@
import static android.view.ViewRootImpl.NEW_INSETS_MODE_NONE;
import static android.view.ViewRootImpl.sNewInsetsMode;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL;
import static com.android.server.wm.WindowManagerService.H.LAYOUT_AND_ASSIGN_WINDOW_LAYERS_IF_NEEDED;
import android.annotation.NonNull;
@@ -34,11 +35,11 @@
import android.view.InsetsSource;
import android.view.InsetsSourceControl;
import android.view.InsetsState;
-import android.view.InsetsState.InternalInsetsType;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import com.android.internal.util.function.TriConsumer;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -185,6 +186,17 @@
}
}
+ /** @return A new source computed by the specified window frame in the given display frames. */
+ InsetsSource createSimulatedSource(DisplayFrames displayFrames, WindowFrames windowFrames) {
+ final InsetsSource source = new InsetsSource(mSource);
+ mTmpRect.set(windowFrames.mFrame);
+ if (mFrameProvider != null) {
+ mFrameProvider.accept(displayFrames, mWin, mTmpRect);
+ }
+ source.setFrame(mTmpRect);
+ return source;
+ }
+
/**
* Called when a layout pass has occurred.
*/
@@ -243,7 +255,8 @@
mAdapter = new ControlAdapter();
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
final Transaction t = mDisplayContent.getPendingTransaction();
- mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */);
+ mWin.startAnimation(t, mAdapter, !mClientVisible /* hidden */,
+ ANIMATION_TYPE_INSETS_CONTROL, null /* animationFinishedCallback */);
final SurfaceControl leash = mAdapter.mCapturedLeash;
final long frameNumber = mFinishSeamlessRotateFrameNumber;
mFinishSeamlessRotateFrameNumber = -1;
@@ -348,7 +361,7 @@
@Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
- OnAnimationFinishedCallback finishCallback) {
+ @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
// TODO(b/118118435): We can remove the type check when implementing the transient bar
// animation.
if (mSource.getType() == ITYPE_IME) {
diff --git a/services/core/java/com/android/server/wm/InsetsStateController.java b/services/core/java/com/android/server/wm/InsetsStateController.java
index 568966a..caaa430 100644
--- a/services/core/java/com/android/server/wm/InsetsStateController.java
+++ b/services/core/java/com/android/server/wm/InsetsStateController.java
@@ -60,6 +60,8 @@
w.notifyInsetsChanged();
}
};
+ private final InsetsControlTarget mEmptyImeControlTarget = () -> {
+ };
InsetsStateController(DisplayContent displayContent) {
mDisplayContent = displayContent;
@@ -177,12 +179,33 @@
}
}
+ /**
+ * Computes insets state of the insets provider window in the display frames.
+ *
+ * @param state The output state.
+ * @param win The owner window of insets provider.
+ * @param displayFrames The display frames to create insets source.
+ * @param windowFrames The specified frames to represent the owner window.
+ */
+ void computeSimulatedState(InsetsState state, WindowState win, DisplayFrames displayFrames,
+ WindowFrames windowFrames) {
+ for (int i = mProviders.size() - 1; i >= 0; i--) {
+ final InsetsSourceProvider provider = mProviders.valueAt(i);
+ if (provider.mWin == win) {
+ state.addSource(provider.createSimulatedSource(displayFrames, windowFrames));
+ }
+ }
+ }
+
boolean isFakeTarget(@InternalInsetsType int type, InsetsControlTarget target) {
return mTypeFakeControlTargetMap.get(type) == target;
}
void onImeControlTargetChanged(@Nullable InsetsControlTarget imeTarget) {
- onControlChanged(ITYPE_IME, imeTarget);
+
+ // Make sure that we always have a control target for the IME, even if the IME target is
+ // null. Otherwise there is no leash that will hide it and IME becomes "randomly" visible.
+ onControlChanged(ITYPE_IME, imeTarget != null ? imeTarget : mEmptyImeControlTarget);
notifyPendingInsetsControlChanged();
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index ad65e10..00947d7 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -31,11 +31,11 @@
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_TO_SHADE;
import static android.view.WindowManagerPolicyConstants.KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
-import static com.android.server.am.KeyguardControllerProto.AOD_SHOWING;
-import static com.android.server.am.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
-import static com.android.server.am.KeyguardControllerProto.KEYGUARD_SHOWING;
-import static com.android.server.am.KeyguardOccludedProto.DISPLAY_ID;
-import static com.android.server.am.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
+import static com.android.server.wm.KeyguardControllerProto.AOD_SHOWING;
+import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_OCCLUDED_STATES;
+import static com.android.server.wm.KeyguardControllerProto.KEYGUARD_SHOWING;
+import static com.android.server.wm.KeyguardOccludedProto.DISPLAY_ID;
+import static com.android.server.wm.KeyguardOccludedProto.KEYGUARD_OCCLUDED;
import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
diff --git a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
index 5892239..7c1a616 100644
--- a/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/LocalAnimationAdapter.java
@@ -24,6 +24,7 @@
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -50,9 +51,9 @@
@Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
- OnAnimationFinishedCallback finishCallback) {
+ @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
mAnimator.startAnimation(mSpec, animationLeash, t,
- () -> finishCallback.onAnimationFinished(this));
+ () -> finishCallback.onAnimationFinished(type, this));
}
@Override
diff --git a/services/core/java/com/android/server/wm/RecentsAnimation.java b/services/core/java/com/android/server/wm/RecentsAnimation.java
index 647be0f..9770947 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimation.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimation.java
@@ -388,11 +388,12 @@
// surfaces needs to be done immediately.
mWindowManager.executeAppTransition();
- // After reordering the stacks, reset the minimized state. At this point, either
- // the target activity is now top-most and we will stay minimized (if in
- // split-screen), or we will have returned to the app, and the minimized state
- // should be reset
- mWindowManager.checkSplitScreenMinimizedChanged(true /* animate */);
+ if (targetStack.getTile() != null) {
+ // Client state may have changed during the recents animation, so force
+ // send task info so the client can synchronize its state.
+ mService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ targetStack.mTile, true /* force */);
+ }
} catch (Exception e) {
Slog.e(TAG, "Failed to clean up recents activity", e);
throw e;
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index da9d074..944e0ae 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -30,6 +30,7 @@
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RECENTS_ANIMATIONS;
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
import android.annotation.IntDef;
@@ -61,6 +62,7 @@
import com.android.server.inputmethod.InputMethodManagerInternal;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.statusbar.StatusBarManagerInternal;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.InsetUtils;
@@ -432,7 +434,8 @@
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "addAnimation(%s)", task.getName());
final TaskAnimationAdapter taskAdapter = new TaskAnimationAdapter(task,
isRecentTaskInvisible);
- task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */);
+ task.startAnimation(task.getPendingTransaction(), taskAdapter, false /* hidden */,
+ ANIMATION_TYPE_RECENTS);
task.commitPendingTransaction();
mPendingAnimations.add(taskAdapter);
return taskAdapter;
@@ -443,14 +446,16 @@
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS,
"removeAnimation(%d)", taskAdapter.mTask.mTaskId);
taskAdapter.mTask.setCanAffectSystemUiFlags(true);
- taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter);
+ taskAdapter.mCapturedFinishCallback.onAnimationFinished(taskAdapter.mLastAnimationType,
+ taskAdapter);
mPendingAnimations.remove(taskAdapter);
}
@VisibleForTesting
void removeWallpaperAnimation(WallpaperAnimationAdapter wallpaperAdapter) {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "removeWallpaperAnimation()");
- wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(wallpaperAdapter);
+ wallpaperAdapter.getLeashFinishedCallback().onAnimationFinished(
+ wallpaperAdapter.getLastAnimationType(), wallpaperAdapter);
mPendingWallpaperAnimations.remove(wallpaperAdapter);
}
@@ -638,7 +643,7 @@
taskSnapshot.getColorSpace(), false /* containsSecureLayers */));
mRecentScreenshotAnimator = new SurfaceAnimator(
animatable,
- () -> {
+ (type, anim) -> {
ProtoLog.d(WM_DEBUG_RECENTS_ANIMATIONS, "mRecentScreenshotAnimator finish");
mCallbacks.onAnimationFinished(reorderMode, false /* sendUserLeaveHint */);
}, mService);
@@ -827,6 +832,7 @@
private final Task mTask;
private SurfaceControl mCapturedLeash;
private OnAnimationFinishedCallback mCapturedFinishCallback;
+ private @AnimationType int mLastAnimationType;
private final boolean mIsRecentTaskInvisible;
private RemoteAnimationTarget mTarget;
private final Point mPosition = new Point();
@@ -868,7 +874,7 @@
@Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
- OnAnimationFinishedCallback finishCallback) {
+ @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
// Restore z-layering, position and stack crop until client has a chance to modify it.
t.setLayer(animationLeash, mTask.getPrefixOrderIndex());
t.setPosition(animationLeash, mPosition.x, mPosition.y);
@@ -877,6 +883,7 @@
t.setWindowCrop(animationLeash, mTmpRect);
mCapturedLeash = animationLeash;
mCapturedFinishCallback = finishCallback;
+ mLastAnimationType = type;
}
@Override
diff --git a/services/core/java/com/android/server/wm/RemoteAnimationController.java b/services/core/java/com/android/server/wm/RemoteAnimationController.java
index 6f7eeab..d2dbab8 100644
--- a/services/core/java/com/android/server/wm/RemoteAnimationController.java
+++ b/services/core/java/com/android/server/wm/RemoteAnimationController.java
@@ -40,6 +40,7 @@
import com.android.internal.util.FastPrintWriter;
import com.android.server.protolog.ProtoLogImpl;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
@@ -180,12 +181,14 @@
if (wrappers.mAdapter != null
&& wrappers.mAdapter.mCapturedFinishCallback != null) {
wrappers.mAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mAdapter);
+ .onAnimationFinished(wrappers.mAdapter.mAnimationType,
+ wrappers.mAdapter);
}
if (wrappers.mThumbnailAdapter != null
&& wrappers.mThumbnailAdapter.mCapturedFinishCallback != null) {
wrappers.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(wrappers.mThumbnailAdapter);
+ .onAnimationFinished(wrappers.mAdapter.mAnimationType,
+ wrappers.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
}
@@ -221,11 +224,13 @@
final RemoteAnimationRecord adapters = mPendingAnimations.get(i);
if (adapters.mAdapter != null) {
adapters.mAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mAdapter);
+ .onAnimationFinished(adapters.mAdapter.mAnimationType,
+ adapters.mAdapter);
}
if (adapters.mThumbnailAdapter != null) {
adapters.mThumbnailAdapter.mCapturedFinishCallback
- .onAnimationFinished(adapters.mThumbnailAdapter);
+ .onAnimationFinished(adapters.mAdapter.mAnimationType,
+ adapters.mThumbnailAdapter);
}
mPendingAnimations.remove(i);
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\tcontainer=%s",
@@ -234,7 +239,8 @@
for (int i = mPendingWallpaperAnimations.size() - 1; i >= 0; i--) {
final WallpaperAnimationAdapter adapter = mPendingWallpaperAnimations.get(i);
- adapter.getLeashFinishedCallback().onAnimationFinished(adapter);
+ adapter.getLeashFinishedCallback().onAnimationFinished(
+ adapter.getLastAnimationType(), adapter);
mPendingWallpaperAnimations.remove(i);
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "\twallpaper=%s", adapter.getToken());
}
@@ -393,6 +399,7 @@
private final RemoteAnimationRecord mRecord;
SurfaceControl mCapturedLeash;
private OnAnimationFinishedCallback mCapturedFinishCallback;
+ private @AnimationType int mAnimationType;
final Point mPosition = new Point();
final Rect mStackBounds = new Rect();
@@ -410,7 +417,7 @@
@Override
public void startAnimation(SurfaceControl animationLeash, Transaction t,
- OnAnimationFinishedCallback finishCallback) {
+ @AnimationType int type, OnAnimationFinishedCallback finishCallback) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
// Restore z-layering, position and stack crop until client has a chance to modify it.
@@ -425,6 +432,7 @@
}
mCapturedLeash = animationLeash;
mCapturedFinishCallback = finishCallback;
+ mAnimationType = type;
}
@Override
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e6fd512..2fdcbc90 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -16,7 +16,6 @@
package com.android.server.wm;
-import static android.app.ActivityTaskManager.INVALID_STACK_ID;
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
@@ -41,12 +40,6 @@
import static android.view.WindowManager.TRANSIT_CRASHING_ACTIVITY_CLOSE;
import static android.view.WindowManager.TRANSIT_SHOW_SINGLE_TASK_DISPLAY;
-import static com.android.server.am.ActivityStackSupervisorProto.FOCUSED_STACK_ID;
-import static com.android.server.am.ActivityStackSupervisorProto.IS_HOME_RECENTS_COMPONENT;
-import static com.android.server.am.ActivityStackSupervisorProto.KEYGUARD_CONTROLLER;
-import static com.android.server.am.ActivityStackSupervisorProto.PENDING_ACTIVITIES;
-import static com.android.server.am.ActivityStackSupervisorProto.RESUMED_ACTIVITY;
-import static com.android.server.am.ActivityStackSupervisorProto.ROOT_WINDOW_CONTAINER;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.wm.ActivityStack.ActivityState.PAUSED;
@@ -74,6 +67,9 @@
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_SURFACE_ALLOC;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
import static com.android.server.wm.RootWindowContainerProto.DISPLAYS;
+import static com.android.server.wm.RootWindowContainerProto.IS_HOME_RECENTS_COMPONENT;
+import static com.android.server.wm.RootWindowContainerProto.KEYGUARD_CONTROLLER;
+import static com.android.server.wm.RootWindowContainerProto.PENDING_ACTIVITIES;
import static com.android.server.wm.RootWindowContainerProto.WINDOWS;
import static com.android.server.wm.RootWindowContainerProto.WINDOW_CONTAINER;
import static com.android.server.wm.Task.REPARENT_LEAVE_STACK_IN_PLACE;
@@ -1012,6 +1008,9 @@
mWmService.scheduleAnimationLocked();
+ // Send any pending task-info changes that were queued-up during a layout deferment
+ mWmService.mAtmService.mTaskOrganizerController.dispatchPendingTaskInfoChanges();
+
if (DEBUG_WINDOW_TRACE) Slog.e(TAG,
"performSurfacePlacementInner exit: animating="
+ mWmService.mAnimator.isAnimating());
@@ -1275,7 +1274,8 @@
}
}
- public void dumpDebugInner(ProtoOutputStream proto, long fieldId,
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
return;
@@ -1287,14 +1287,20 @@
final int count = mChildren.size();
for (int i = 0; i < count; ++i) {
final DisplayContent displayContent = mChildren.get(i);
- displayContent.dumpDebugInner(proto, DISPLAYS, logLevel);
+ displayContent.dumpDebug(proto, DISPLAYS, logLevel);
}
}
if (logLevel == WindowTraceLogLevel.ALL) {
forAllWindows((w) -> {
- w.writeIdentifierToProto(proto, WINDOWS);
+ w.dumpDebug(proto, WINDOWS, logLevel);
}, true);
}
+
+ mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
+ proto.write(IS_HOME_RECENTS_COMPONENT,
+ mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser));
+ mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES);
+
proto.end(token);
}
@@ -2959,6 +2965,12 @@
case ACTIVITY_TYPE_RECENTS: return r.isActivityTypeRecents();
case ACTIVITY_TYPE_ASSISTANT: return r.isActivityTypeAssistant();
}
+ // TODO(task-hierarchy): Find another way to differentiate tile from normal stack once it is
+ // part of the hierarchy
+ if (stack instanceof TaskTile) {
+ // Don't launch directly into tiles.
+ return false;
+ }
// There is a 1-to-1 relationship between stack and task when not in
// primary split-windowing mode.
if (stack.getWindowingMode() == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
@@ -3532,15 +3544,6 @@
}
}
- public void dumpDisplays(PrintWriter pw) {
- for (int i = getChildCount() - 1; i >= 0; --i) {
- final DisplayContent display = getChildAt(i);
- pw.print("[id:" + display.mDisplayId + " stacks:");
- display.dumpStacks(pw);
- pw.print("]");
- }
- }
-
boolean dumpActivities(FileDescriptor fd, PrintWriter pw, boolean dumpAll, boolean dumpClient,
String dumpPackage) {
boolean printed = false;
@@ -3569,34 +3572,6 @@
return printed;
}
- @Override
- public void dumpDebug(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- final long token = proto.start(fieldId);
- dumpDebugInner(proto, ROOT_WINDOW_CONTAINER, logLevel);
- for (int displayNdx = 0; displayNdx < getChildCount(); ++displayNdx) {
- final DisplayContent displayContent = getChildAt(displayNdx);
- displayContent.dumpDebug(proto,
- com.android.server.am.ActivityStackSupervisorProto.DISPLAYS, logLevel);
- }
- mStackSupervisor.getKeyguardController().dumpDebug(proto, KEYGUARD_CONTROLLER);
- // TODO(b/111541062): Update tests to look for resumed activities on all displays
- final ActivityStack focusedStack = getTopDisplayFocusedStack();
- if (focusedStack != null) {
- proto.write(FOCUSED_STACK_ID, focusedStack.getRootTaskId());
- final ActivityRecord focusedActivity = focusedStack.getDisplay().getResumedActivity();
- if (focusedActivity != null) {
- focusedActivity.writeIdentifierToProto(proto, RESUMED_ACTIVITY);
- }
- } else {
- proto.write(FOCUSED_STACK_ID, INVALID_STACK_ID);
- }
- proto.write(IS_HOME_RECENTS_COMPONENT,
- mStackSupervisor.mRecentTasks.isRecentsComponentHomeActivity(mCurrentUser));
- mService.getActivityStartController().dumpDebug(proto, PENDING_ACTIVITIES);
- proto.end(token);
- }
-
private final class SleepTokenImpl extends ActivityTaskManagerInternal.SleepToken {
private final String mTag;
private final long mAcquireTime;
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index e7aca89..f6cdac5 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -24,6 +24,7 @@
import static com.android.server.wm.RotationAnimationSpecProto.START_LUMA;
import static com.android.server.wm.ScreenRotationAnimationProto.ANIMATION_RUNNING;
import static com.android.server.wm.ScreenRotationAnimationProto.STARTED;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_SCREEN_ROTATION;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
@@ -48,6 +49,8 @@
import com.android.internal.R;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import com.android.server.wm.utils.RotationAnimationUtils;
import java.io.PrintWriter;
@@ -670,33 +673,35 @@
* Start an animation defined by animationSpec on a new {@link SurfaceAnimator}.
*
* @param animatable The animatable used for the animation.
- * @param animationSpec The spec of the animation.
- * @param animationFinishedCallback Callback passed to the {@link SurfaceAnimator} and
- * called when the animation finishes.
+ * @param animationSpec The spec of the animation.
+ * @param animationFinishedCallback Callback passed to the {@link SurfaceAnimator}
+ * and called when the animation finishes.
* @return The newly created {@link SurfaceAnimator} that as been started.
*/
private SurfaceAnimator startAnimation(
SurfaceAnimator.Animatable animatable,
LocalAnimationAdapter.AnimationSpec animationSpec,
- Runnable animationFinishedCallback) {
+ OnAnimationFinishedCallback animationFinishedCallback) {
SurfaceAnimator animator = new SurfaceAnimator(
animatable, animationFinishedCallback, mService);
LocalAnimationAdapter localAnimationAdapter = new LocalAnimationAdapter(
animationSpec, mService.mSurfaceAnimationRunner);
animator.startAnimation(mDisplayContent.getPendingTransaction(),
- localAnimationAdapter, false);
+ localAnimationAdapter, false, ANIMATION_TYPE_SCREEN_ROTATION);
return animator;
}
- private void onAnimationEnd() {
+ private void onAnimationEnd(@AnimationType int type, AnimationAdapter anim) {
synchronized (mService.mGlobalLock) {
if (isAnimating()) {
ProtoLog.v(WM_DEBUG_ORIENTATION,
- "ScreenRotation sill animating: mDisplayAnimator: %s\n"
- + "mEnterBlackFrameAnimator: "
- + "%s\nmRotateScreenAnimator: %s\n"
+ "ScreenRotation still animating: type: %d\n"
+ + "mDisplayAnimator: %s\n"
+ + "mEnterBlackFrameAnimator: %s\n"
+ + "mRotateScreenAnimator: %s\n"
+ "mScreenshotRotationAnimator: %s",
+ type,
mDisplayAnimator != null
? mDisplayAnimator.isAnimating() : null,
mEnterBlackFrameAnimator != null
diff --git a/services/core/java/com/android/server/wm/Session.java b/services/core/java/com/android/server/wm/Session.java
index de7f9e4..ab1f34a 100644
--- a/services/core/java/com/android/server/wm/Session.java
+++ b/services/core/java/com/android/server/wm/Session.java
@@ -238,16 +238,12 @@
@Override
public void setInTouchMode(boolean mode) {
- synchronized (mService.mGlobalLock) {
- mService.mInTouchMode = mode;
- }
+ mService.setInTouchMode(mode);
}
@Override
public boolean getInTouchMode() {
- synchronized (mService.mGlobalLock) {
- return mService.mInTouchMode;
- }
+ return mService.getInTouchMode();
}
@Override
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimator.java b/services/core/java/com/android/server/wm/SurfaceAnimator.java
index cb1676f..7164cd8 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimator.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimator.java
@@ -23,6 +23,7 @@
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import android.annotation.IntDef;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.util.Slog;
@@ -33,6 +34,8 @@
import com.android.internal.annotations.VisibleForTesting;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
/**
* A class that can run animations on objects that have a set of child surfaces. We do this by
@@ -47,6 +50,7 @@
private static final String TAG = TAG_WITH_CLASS_NAME ? "SurfaceAnimator" : TAG_WM;
private final WindowManagerService mService;
private AnimationAdapter mAnimation;
+ private @AnimationType int mAnimationType;
@VisibleForTesting
SurfaceControl mLeash;
@@ -55,30 +59,32 @@
private final OnAnimationFinishedCallback mInnerAnimationFinishedCallback;
@VisibleForTesting
@Nullable
- final Runnable mStaticAnimationFinishedCallback;
+ final OnAnimationFinishedCallback mStaticAnimationFinishedCallback;
@Nullable
- private Runnable mAnimationFinishedCallback;
+ private OnAnimationFinishedCallback mAnimationFinishedCallback;
private boolean mAnimationStartDelayed;
/**
* @param animatable The object to animate.
- * @param animationFinishedCallback Callback to invoke when an animation has finished running.
+ * @param staticAnimationFinishedCallback Callback to invoke when an animation has finished
+ * running.
*/
- SurfaceAnimator(Animatable animatable, @Nullable Runnable animationFinishedCallback,
+ SurfaceAnimator(Animatable animatable,
+ @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback,
WindowManagerService service) {
mAnimatable = animatable;
mService = service;
- mStaticAnimationFinishedCallback = animationFinishedCallback;
- mInnerAnimationFinishedCallback = getFinishedCallback(animationFinishedCallback);
+ mStaticAnimationFinishedCallback = staticAnimationFinishedCallback;
+ mInnerAnimationFinishedCallback = getFinishedCallback(staticAnimationFinishedCallback);
}
private OnAnimationFinishedCallback getFinishedCallback(
- @Nullable Runnable animationFinishedCallback) {
- return anim -> {
+ @Nullable OnAnimationFinishedCallback staticAnimationFinishedCallback) {
+ return (type, anim) -> {
synchronized (mService.mGlobalLock) {
final SurfaceAnimator target = mService.mAnimationTransferMap.remove(anim);
if (target != null) {
- target.mInnerAnimationFinishedCallback.onAnimationFinished(anim);
+ target.mInnerAnimationFinishedCallback.onAnimationFinished(type, anim);
return;
}
@@ -91,13 +97,14 @@
if (anim != mAnimation) {
return;
}
- final Runnable animationFinishCallback = mAnimationFinishedCallback;
+ final OnAnimationFinishedCallback animationFinishCallback =
+ mAnimationFinishedCallback;
reset(mAnimatable.getPendingTransaction(), true /* destroyLeash */);
- if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
+ if (staticAnimationFinishedCallback != null) {
+ staticAnimationFinishedCallback.onAnimationFinished(type, anim);
}
if (animationFinishCallback != null) {
- animationFinishCallback.run();
+ animationFinishCallback.onAnimationFinished(type, anim);
}
};
if (!mAnimatable.shouldDeferAnimationFinish(resetAndInvokeFinish)) {
@@ -120,9 +127,11 @@
* @param animationFinishedCallback The callback being triggered when the animation finishes.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
- @Nullable Runnable animationFinishedCallback) {
+ @AnimationType int type,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mAnimation = anim;
+ mAnimationType = type;
mAnimationFinishedCallback = animationFinishedCallback;
final SurfaceControl surface = mAnimatable.getSurfaceControl();
if (surface == null) {
@@ -137,11 +146,12 @@
if (DEBUG_ANIM) Slog.i(TAG, "Animation start delayed");
return;
}
- mAnimation.startAnimation(mLeash, t, mInnerAnimationFinishedCallback);
+ mAnimation.startAnimation(mLeash, t, type, mInnerAnimationFinishedCallback);
}
- void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
- startAnimation(t, anim, hidden, null /* animationFinishedCallback */);
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+ @AnimationType int type) {
+ startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
}
/**
@@ -165,7 +175,7 @@
mAnimationStartDelayed = false;
if (delayed && mAnimation != null) {
mAnimation.startAnimation(mLeash, mAnimatable.getPendingTransaction(),
- mInnerAnimationFinishedCallback);
+ mAnimationType, mInnerAnimationFinishedCallback);
mAnimatable.commitPendingTransaction();
}
}
@@ -245,6 +255,7 @@
cancelAnimation(t, true /* restarting */, true /* forwardCancel */);
mLeash = from.mLeash;
mAnimation = from.mAnimation;
+ mAnimationType = from.mAnimationType;
mAnimationFinishedCallback = from.mAnimationFinishedCallback;
// Cancel source animation, but don't let animation runner cancel the animation.
@@ -272,7 +283,8 @@
if (DEBUG_ANIM) Slog.i(TAG, "Cancelling animation restarting=" + restarting);
final SurfaceControl leash = mLeash;
final AnimationAdapter animation = mAnimation;
- final Runnable animationFinishedCallback = mAnimationFinishedCallback;
+ final @AnimationType int animationType = mAnimationType;
+ final OnAnimationFinishedCallback animationFinishedCallback = mAnimationFinishedCallback;
reset(t, false);
if (animation != null) {
if (!mAnimationStartDelayed && forwardCancel) {
@@ -280,10 +292,10 @@
}
if (!restarting) {
if (mStaticAnimationFinishedCallback != null) {
- mStaticAnimationFinishedCallback.run();
+ mStaticAnimationFinishedCallback.onAnimationFinished(animationType, animation);
}
if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
+ animationFinishedCallback.onAnimationFinished(animationType, animation);
}
}
}
@@ -325,6 +337,7 @@
mLeash = null;
mAnimation = null;
mAnimationFinishedCallback = null;
+ mAnimationType = ANIMATION_TYPE_NONE;
if (reparent) {
// Make sure to inform the animatable after the surface was reparented (or reparent
@@ -392,12 +405,72 @@
}
}
+
+ /**
+ * No animation is specified.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_NONE = 0;
+
+ /**
+ * Animation for an app transition.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_APP_TRANSITION = 1;
+
+ /**
+ * Animation for screen rotation.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_SCREEN_ROTATION = 2;
+
+ /**
+ * Animation for dimming.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_DIMMER = 3;
+
+ /**
+ * Animation for recent apps.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_RECENTS = 4;
+
+ /**
+ * Animation for a {@link WindowState} without animating the activity.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_WINDOW_ANIMATION = 5;
+
+ /**
+ * Animation to control insets. This is actually not an animation, but is used to give the
+ * client a leash over the system window causing insets.
+ * @hide
+ */
+ static final int ANIMATION_TYPE_INSETS_CONTROL = 6;
+
+ /**
+ * The type of the animation.
+ * @hide
+ */
+ @IntDef(flag = true, prefix = { "ANIMATION_TYPE_" }, value = {
+ ANIMATION_TYPE_NONE,
+ ANIMATION_TYPE_APP_TRANSITION,
+ ANIMATION_TYPE_SCREEN_ROTATION,
+ ANIMATION_TYPE_DIMMER,
+ ANIMATION_TYPE_RECENTS,
+ ANIMATION_TYPE_WINDOW_ANIMATION,
+ ANIMATION_TYPE_INSETS_CONTROL
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ @interface AnimationType {}
+
/**
* Callback to be passed into {@link AnimationAdapter#startAnimation} to be invoked by the
* component that is running the animation when the animation is finished.
*/
interface OnAnimationFinishedCallback {
- void onAnimationFinished(AnimationAdapter anim);
+ void onAnimationFinished(@AnimationType int type, AnimationAdapter anim);
}
/**
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 36cae1f..87c91ef 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,17 +61,6 @@
import static com.android.internal.policy.DecorView.DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP;
import static com.android.internal.policy.DecorView.DECOR_SHADOW_UNFOCUSED_HEIGHT_IN_DIP;
-import static com.android.server.am.TaskRecordProto.ACTIVITIES;
-import static com.android.server.am.TaskRecordProto.ACTIVITY_TYPE;
-import static com.android.server.am.TaskRecordProto.FULLSCREEN;
-import static com.android.server.am.TaskRecordProto.LAST_NON_FULLSCREEN_BOUNDS;
-import static com.android.server.am.TaskRecordProto.MIN_HEIGHT;
-import static com.android.server.am.TaskRecordProto.MIN_WIDTH;
-import static com.android.server.am.TaskRecordProto.ORIG_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.REAL_ACTIVITY;
-import static com.android.server.am.TaskRecordProto.RESIZE_MODE;
-import static com.android.server.am.TaskRecordProto.STACK_ID;
-import static com.android.server.am.TaskRecordProto.TASK;
import static com.android.server.wm.ActivityRecord.STARTING_WINDOW_SHOWN;
import static com.android.server.wm.ActivityStack.ActivityState.RESUMED;
import static com.android.server.wm.ActivityStackSupervisor.ON_TOP;
@@ -90,7 +79,6 @@
import static com.android.server.wm.ActivityTaskManagerService.TAG_STACK;
import static com.android.server.wm.DragResizeMode.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ADD_REMOVE;
-import static com.android.server.wm.TaskProto.ACTIVITY;
import static com.android.server.wm.TaskProto.DISPLAYED_BOUNDS;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
import static com.android.server.wm.TaskProto.SURFACE_HEIGHT;
@@ -1257,7 +1245,7 @@
if (affinityIntent != null) return affinityIntent;
// Probably a task that contains other tasks, so return the intent for the top task?
final Task topTask = getTopMostTask();
- return topTask != null ? topTask.getBaseIntent() : null;
+ return (topTask != this && topTask != null) ? topTask.getBaseIntent() : null;
}
/** Returns the first non-finishing activity from the bottom. */
@@ -3160,29 +3148,6 @@
}
}
- // TODO(proto-merge): Remove once protos for TaskRecord and Task are merged.
- void dumpDebugInnerTaskOnly(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- super.dumpDebug(proto, WINDOW_CONTAINER, logLevel);
- proto.write(TaskProto.ID, mTaskId);
- forAllActivities((r) -> {
- r.dumpDebug(proto, ACTIVITY);
- });
- proto.write(FILLS_PARENT, matchParentBounds());
- getBounds().dumpDebug(proto, TaskProto.BOUNDS);
- mOverrideDisplayedBounds.dumpDebug(proto, DISPLAYED_BOUNDS);
- if (mSurfaceControl != null) {
- proto.write(SURFACE_WIDTH, mSurfaceControl.getWidth());
- proto.write(SURFACE_HEIGHT, mSurfaceControl.getHeight());
- }
- proto.end(token);
- }
-
@Override
void dump(PrintWriter pw, String prefix, boolean dumpAll) {
super.dump(pw, prefix, dumpAll);
@@ -3214,7 +3179,10 @@
info.taskId = mTaskId;
info.displayId = getDisplayId();
info.isRunning = getTopNonFinishingActivity() != null;
- info.baseIntent = new Intent(getBaseIntent());
+ final Intent baseIntent = getBaseIntent();
+ // Make a copy of base intent because this is like a snapshot info.
+ // Besides, {@link RecentTasks#getRecentTasksImpl} may modify it.
+ info.baseIntent = baseIntent == null ? new Intent() : new Intent(baseIntent);
info.baseActivity = mReuseActivitiesReport.base != null
? mReuseActivitiesReport.base.intent.getComponent()
: null;
@@ -3229,6 +3197,10 @@
info.supportsSplitScreenMultiWindow = supportsSplitScreenWindowingMode();
info.resizeMode = mResizeMode;
info.configuration.setTo(getConfiguration());
+ info.token = mRemoteToken;
+ // Get's the first non-undefined activity type among this and children. Can't use
+ // configuration.windowConfiguration because that would only be this level.
+ info.topActivityType = getActivityType();
}
/**
@@ -3375,7 +3347,7 @@
if (affinity != null) {
sb.append(" A=");
sb.append(affinity);
- } else if (intent != null) {
+ } else if (intent != null && intent.getComponent() != null) {
sb.append(" I=");
sb.append(intent.getComponent().flattenToShortString());
} else if (affinityIntent != null && affinityIntent.getComponent() != null) {
@@ -3388,43 +3360,6 @@
return toString();
}
- void dumpDebugInner(ProtoOutputStream proto, long fieldId,
- @WindowTraceLogLevel int logLevel) {
- if (logLevel == WindowTraceLogLevel.CRITICAL && !isVisible()) {
- return;
- }
-
- final long token = proto.start(fieldId);
- dumpDebugInnerTaskOnly(proto, TASK, logLevel);
- proto.write(com.android.server.am.TaskRecordProto.ID, mTaskId);
-
- forAllActivities((r) -> {
- r.dumpDebug(proto, ACTIVITIES);
- });
- proto.write(STACK_ID, getRootTaskId());
- if (mLastNonFullscreenBounds != null) {
- mLastNonFullscreenBounds.dumpDebug(proto, LAST_NON_FULLSCREEN_BOUNDS);
- }
- if (realActivity != null) {
- proto.write(REAL_ACTIVITY, realActivity.flattenToShortString());
- }
- if (origActivity != null) {
- proto.write(ORIG_ACTIVITY, origActivity.flattenToShortString());
- }
- proto.write(ACTIVITY_TYPE, getActivityType());
- proto.write(RESIZE_MODE, mResizeMode);
- // TODO: Remove, no longer needed with windowingMode.
- proto.write(FULLSCREEN, matchParentBounds());
-
- if (!matchParentBounds()) {
- final Rect bounds = getRequestedOverrideBounds();
- bounds.dumpDebug(proto, com.android.server.am.TaskRecordProto.BOUNDS);
- }
- proto.write(MIN_WIDTH, mMinWidth);
- proto.write(MIN_HEIGHT, mMinHeight);
- proto.end(token);
- }
-
/** @see #getNumRunningActivities(TaskActivitiesReport) */
static class TaskActivitiesReport implements Consumer<ActivityRecord> {
int numRunning;
@@ -3865,7 +3800,12 @@
boolean isControlledByTaskOrganizer() {
final Task rootTask = getRootTask();
- return rootTask == this && rootTask.mTaskOrganizer != null;
+ return rootTask == this && rootTask.mTaskOrganizer != null
+ // TODO(task-hierarchy): Figure out how to control nested tasks.
+ // For now, if this is in a tile let WM drive.
+ && !(rootTask instanceof TaskTile)
+ && !(rootTask instanceof ActivityStack
+ && ((ActivityStack) rootTask).getTile() != null);
}
@Override
@@ -3893,6 +3833,9 @@
}
void setTaskOrganizer(ITaskOrganizer organizer) {
+ if (mTaskOrganizer == organizer) {
+ return;
+ }
// Let the old organizer know it has lost control.
if (mTaskOrganizer != null) {
sendTaskVanished();
@@ -3918,8 +3861,6 @@
public void updateSurfacePosition() {
// Avoid fighting with the TaskOrganizer over Surface position.
if (isControlledByTaskOrganizer()) {
- getPendingTransaction().setPosition(mSurfaceControl, 0, 0);
- scheduleAnimation();
return;
} else {
super.updateSurfacePosition();
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index 66c65e2..44a6fc9 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -16,26 +16,51 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+import android.annotation.Nullable;
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ITaskOrganizerController;
+import android.app.WindowConfiguration;
+import android.content.pm.ActivityInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
+import android.util.ArraySet;
import android.util.Slog;
import android.view.ITaskOrganizer;
-import android.view.SurfaceControl;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+
+import com.android.internal.util.function.pooled.PooledConsumer;
+import com.android.internal.util.function.pooled.PooledLambda;
import java.util.ArrayList;
import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.WeakHashMap;
/**
* Stores the TaskOrganizers associated with a given windowing mode and
* their associated state.
*/
-class TaskOrganizerController {
+class TaskOrganizerController extends ITaskOrganizerController.Stub {
private static final String TAG = "TaskOrganizerController";
- private WindowManagerGlobalLock mGlobalLock;
+ /** Flag indicating that an applied transaction may have effected lifecycle */
+ private static final int TRANSACT_EFFECTS_CLIENT_CONFIG = 1;
+ private static final int TRANSACT_EFFECTS_LIFECYCLE = 1 << 1;
+
+ private final WindowManagerGlobalLock mGlobalLock;
private class DeathRecipient implements IBinder.DeathRecipient {
int mWindowingMode;
@@ -87,11 +112,20 @@
final HashMap<Integer, ITaskOrganizer> mTaskOrganizersByPendingSyncId = new HashMap();
+ private final WeakHashMap<Task, RunningTaskInfo> mLastSentTaskInfos = new WeakHashMap<>();
+ private final ArrayList<Task> mPendingTaskInfoChanges = new ArrayList<>();
+
final ActivityTaskManagerService mService;
- TaskOrganizerController(ActivityTaskManagerService atm, WindowManagerGlobalLock lock) {
+ RunningTaskInfo mTmpTaskInfo;
+
+ TaskOrganizerController(ActivityTaskManagerService atm) {
mService = atm;
- mGlobalLock = lock;
+ mGlobalLock = atm.mGlobalLock;
+ }
+
+ private void enforceStackPermission(String func) {
+ mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
}
private void clearIfNeeded(int windowingMode) {
@@ -106,26 +140,35 @@
* If there was already a TaskOrganizer for this windowing mode it will be evicted
* and receive taskVanished callbacks in the process.
*/
- void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
- if (windowingMode != WINDOWING_MODE_PINNED &&
- windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
- throw new UnsupportedOperationException(
- "As of now only Pinned and Multiwindow windowing modes are"
- + " supported for registerTaskOrganizer");
-
+ @Override
+ public void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode) {
+ if (windowingMode != WINDOWING_MODE_PINNED
+ && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_PRIMARY
+ && windowingMode != WINDOWING_MODE_SPLIT_SCREEN_SECONDARY
+ && windowingMode != WINDOWING_MODE_MULTI_WINDOW) {
+ throw new UnsupportedOperationException("As of now only Pinned/Split/Multiwindow"
+ + " windowing modes are supported for registerTaskOrganizer");
}
- clearIfNeeded(windowingMode);
- DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
+ enforceStackPermission("registerTaskOrganizer()");
+ final long origId = Binder.clearCallingIdentity();
try {
- organizer.asBinder().linkToDeath(dr, 0);
- } catch (RemoteException e) {
- Slog.e(TAG, "TaskOrganizer failed to register death recipient");
+ synchronized (mGlobalLock) {
+ clearIfNeeded(windowingMode);
+ DeathRecipient dr = new DeathRecipient(organizer, windowingMode);
+ try {
+ organizer.asBinder().linkToDeath(dr, 0);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "TaskOrganizer failed to register death recipient");
+ }
+
+ final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
+ mTaskOrganizersForWindowingMode.put(windowingMode, state);
+
+ mTaskOrganizerStates.put(organizer, state);
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
}
-
- final TaskOrganizerState state = new TaskOrganizerState(organizer, dr);
- mTaskOrganizersForWindowingMode.put(windowingMode, state);
-
- mTaskOrganizerStates.put(organizer, state);
}
ITaskOrganizer getTaskOrganizer(int windowingMode) {
@@ -138,7 +181,7 @@
private void sendTaskAppeared(ITaskOrganizer organizer, Task task) {
try {
- organizer.taskAppeared(task.getRemoteToken(), task.getTaskInfo());
+ organizer.taskAppeared(task.getTaskInfo());
} catch (Exception e) {
Slog.e(TAG, "Exception sending taskAppeared callback" + e);
}
@@ -167,4 +210,254 @@
// we do this AFTER sending taskVanished.
state.removeTask(task);
}
+
+ @Override
+ public RunningTaskInfo createRootTask(int displayId, int windowingMode) {
+ enforceStackPermission("createRootTask()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
+ if (display == null) {
+ return null;
+ }
+ final int nextId = display.getNextStackId();
+ TaskTile tile = new TaskTile(mService, nextId, windowingMode);
+ display.addTile(tile);
+ RunningTaskInfo out = new RunningTaskInfo();
+ tile.fillTaskInfo(out);
+ mLastSentTaskInfos.put(tile, out);
+ return out;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public boolean deleteRootTask(IWindowContainer token) {
+ enforceStackPermission("deleteRootTask()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ TaskTile tile = TaskTile.forToken(token.asBinder());
+ if (tile == null) {
+ return false;
+ }
+ tile.removeImmediately();
+ return true;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ void dispatchPendingTaskInfoChanges() {
+ if (mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ return;
+ }
+ for (int i = 0, n = mPendingTaskInfoChanges.size(); i < n; ++i) {
+ dispatchTaskInfoChanged(mPendingTaskInfoChanges.get(i), false /* force */);
+ }
+ mPendingTaskInfoChanges.clear();
+ }
+
+ void dispatchTaskInfoChanged(Task task, boolean force) {
+ if (!force && mService.mWindowManager.mWindowPlacerLocked.isLayoutDeferred()) {
+ // Defer task info reporting while layout is deferred. This is because layout defer
+ // blocks tend to do lots of re-ordering which can mess up animations in receivers.
+ mPendingTaskInfoChanges.remove(task);
+ mPendingTaskInfoChanges.add(task);
+ return;
+ }
+ RunningTaskInfo lastInfo = mLastSentTaskInfos.get(task);
+ if (mTmpTaskInfo == null) {
+ mTmpTaskInfo = new RunningTaskInfo();
+ }
+ task.fillTaskInfo(mTmpTaskInfo);
+ boolean changed = lastInfo == null
+ || mTmpTaskInfo.topActivityType != lastInfo.topActivityType
+ || mTmpTaskInfo.isResizable() != lastInfo.isResizable();
+ if (!(changed || force)) {
+ return;
+ }
+ final RunningTaskInfo newInfo = mTmpTaskInfo;
+ mLastSentTaskInfos.put(task, mTmpTaskInfo);
+ // Since we've stored this, clean up the reference so a new one will be created next time.
+ // Transferring it this way means we only have to construct new RunningTaskInfos when they
+ // change.
+ mTmpTaskInfo = null;
+
+ if (task.mTaskOrganizer != null) {
+ try {
+ task.mTaskOrganizer.onTaskInfoChanged(newInfo);
+ } catch (RemoteException e) {
+ }
+ }
+ }
+
+ @Override
+ public IWindowContainer getImeTarget(int displayId) {
+ enforceStackPermission("getImeTarget()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent dc = mService.mWindowManager.mRoot
+ .getDisplayContent(displayId);
+ if (dc == null || dc.mInputMethodTarget == null) {
+ return null;
+ }
+ // Avoid WindowState#getRootTask() so we don't attribute system windows to a task.
+ final Task task = dc.mInputMethodTarget.getTask();
+ if (task == null) {
+ return null;
+ }
+ ActivityStack rootTask = (ActivityStack) task.getRootTask();
+ final TaskTile tile = rootTask.getTile();
+ if (tile != null) {
+ rootTask = tile;
+ }
+ return rootTask.mRemoteToken;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ @Override
+ public void setLaunchRoot(int displayId, @Nullable IWindowContainer tile) {
+ enforceStackPermission("setLaunchRoot()");
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ DisplayContent display = mService.mRootWindowContainer.getDisplayContent(displayId);
+ if (display == null) {
+ return;
+ }
+ TaskTile taskTile = tile == null ? null : TaskTile.forToken(tile.asBinder());
+ if (taskTile == null) {
+ display.mLaunchTile = null;
+ return;
+ }
+ if (taskTile.getDisplay() != display) {
+ throw new RuntimeException("Can't set launch root for display " + displayId
+ + " to task on display " + taskTile.getDisplay().getDisplayId());
+ }
+ display.mLaunchTile = taskTile;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(origId);
+ }
+ }
+
+ private int sanitizeAndApplyChange(WindowContainer container,
+ WindowContainerTransaction.Change change) {
+ if (!(container instanceof Task)) {
+ throw new RuntimeException("Invalid token in task transaction");
+ }
+ // The "client"-facing API should prevent bad changes; however, just in case, sanitize
+ // masks here.
+ int configMask = change.getConfigSetMask();
+ int windowMask = change.getWindowSetMask();
+ configMask &= ActivityInfo.CONFIG_WINDOW_CONFIGURATION
+ | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+ windowMask &= WindowConfiguration.WINDOW_CONFIG_BOUNDS;
+ int effects = 0;
+ if (configMask != 0) {
+ Configuration c = new Configuration(container.getRequestedOverrideConfiguration());
+ c.setTo(change.getConfiguration(), configMask, windowMask);
+ container.onRequestedOverrideConfigurationChanged(c);
+ // TODO(b/145675353): remove the following once we could apply new bounds to the
+ // pinned stack together with its children.
+ resizePinnedStackIfNeeded(container, configMask, windowMask, c);
+ effects |= TRANSACT_EFFECTS_CLIENT_CONFIG;
+ }
+ if ((change.getChangeMask() & WindowContainerTransaction.Change.CHANGE_FOCUSABLE) != 0) {
+ if (container.setFocusable(change.getFocusable())) {
+ effects |= TRANSACT_EFFECTS_LIFECYCLE;
+ }
+ }
+ return effects;
+ }
+
+ private void resizePinnedStackIfNeeded(ConfigurationContainer container, int configMask,
+ int windowMask, Configuration config) {
+ if ((container instanceof ActivityStack)
+ && ((configMask & ActivityInfo.CONFIG_WINDOW_CONFIGURATION) != 0)
+ && ((windowMask & WindowConfiguration.WINDOW_CONFIG_BOUNDS) != 0)) {
+ final ActivityStack stack = (ActivityStack) container;
+ if (stack.inPinnedWindowingMode()) {
+ stack.resize(config.windowConfiguration.getBounds(),
+ null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+ PRESERVE_WINDOWS, true /* deferResume */);
+ }
+ }
+ }
+
+ private int applyWindowContainerChange(WindowContainer wc,
+ WindowContainerTransaction.Change c) {
+ int effects = sanitizeAndApplyChange(wc, c);
+
+ Rect enterPipBounds = c.getEnterPipBounds();
+ if (enterPipBounds != null) {
+ Task tr = (Task) wc;
+ mService.mStackSupervisor.updatePictureInPictureMode(tr,
+ enterPipBounds, true);
+ }
+ return effects;
+ }
+
+ @Override
+ public void applyContainerTransaction(WindowContainerTransaction t) {
+ enforceStackPermission("applyContainerTransaction()");
+ if (t == null) {
+ return;
+ }
+ long ident = Binder.clearCallingIdentity();
+ try {
+ synchronized (mGlobalLock) {
+ int effects = 0;
+ mService.deferWindowLayout();
+ try {
+ ArraySet<WindowContainer> haveConfigChanges = new ArraySet<>();
+ Iterator<Map.Entry<IBinder, WindowContainerTransaction.Change>> entries =
+ t.getChanges().entrySet().iterator();
+ while (entries.hasNext()) {
+ final Map.Entry<IBinder, WindowContainerTransaction.Change> entry =
+ entries.next();
+ final WindowContainer wc = WindowContainer.RemoteToken.fromBinder(
+ entry.getKey()).getContainer();
+ int containerEffect = applyWindowContainerChange(wc, entry.getValue());
+ effects |= containerEffect;
+ // Lifecycle changes will trigger ensureConfig for everything.
+ if ((effects & TRANSACT_EFFECTS_LIFECYCLE) == 0
+ && (containerEffect & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
+ haveConfigChanges.add(wc);
+ }
+ }
+ if ((effects & TRANSACT_EFFECTS_LIFECYCLE) != 0) {
+ // Already calls ensureActivityConfig
+ mService.mRootWindowContainer.ensureActivitiesVisible(
+ null, 0, PRESERVE_WINDOWS);
+ } else if ((effects & TRANSACT_EFFECTS_CLIENT_CONFIG) != 0) {
+ final PooledConsumer f = PooledLambda.obtainConsumer(
+ ActivityRecord::ensureActivityConfiguration,
+ PooledLambda.__(ActivityRecord.class), 0,
+ false /* preserveWindow */);
+ try {
+ for (int i = haveConfigChanges.size() - 1; i >= 0; --i) {
+ haveConfigChanges.valueAt(i).forAllActivities(f);
+ }
+ } finally {
+ f.recycle();
+ }
+ }
+ } finally {
+ mService.continueWindowLayout();
+ }
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
+ }
+ }
}
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
index e47eaee..f4e4245 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotSurface.java
@@ -36,7 +36,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DRAW_BAR_BACKGROUNDS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-
import static com.android.internal.policy.DecorView.NAVIGATION_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.STATUS_BAR_COLOR_VIEW_ATTRIBUTES;
import static com.android.internal.policy.DecorView.getColorViewLeftInset;
@@ -188,8 +187,9 @@
return null;
}
sysUiVis = topFullscreenOpaqueWindow.getSystemUiVisibility();
- windowFlags = topFullscreenOpaqueWindow.getAttrs().flags;
- windowPrivateFlags = topFullscreenOpaqueWindow.getAttrs().privateFlags;
+ WindowManager.LayoutParams attrs = topFullscreenOpaqueWindow.mAttrs;
+ windowFlags = attrs.flags;
+ windowPrivateFlags = attrs.privateFlags;
layoutParams.packageName = mainWindow.getAttrs().packageName;
layoutParams.windowAnimations = mainWindow.getAttrs().windowAnimations;
@@ -204,6 +204,14 @@
layoutParams.width = LayoutParams.MATCH_PARENT;
layoutParams.height = LayoutParams.MATCH_PARENT;
layoutParams.systemUiVisibility = sysUiVis;
+ layoutParams.insetsFlags.behavior
+ = topFullscreenOpaqueWindow.mAttrs.insetsFlags.behavior;
+ layoutParams.insetsFlags.appearance
+ = topFullscreenOpaqueWindow.mAttrs.insetsFlags.appearance;
+ layoutParams.setFitInsetsTypes(attrs.getFitInsetsTypes());
+ layoutParams.setFitInsetsSides(attrs.getFitInsetsSides());
+ layoutParams.setFitInsetsIgnoringVisibility(attrs.isFitInsetsIgnoringVisibility());
+
layoutParams.setTitle(String.format(TITLE_FORMAT, task.mTaskId));
final TaskDescription td = task.getTaskDescription();
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
new file mode 100644
index 0000000..add11d6
--- /dev/null
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -0,0 +1,225 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.app.ActivityTaskManager.INVALID_TASK_ID;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_RESIZEABLE;
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
+import android.app.ActivityManager;
+import android.app.TaskInfo;
+import android.app.WindowConfiguration;
+import android.content.Intent;
+import android.content.pm.ActivityInfo;
+import android.content.pm.ApplicationInfo;
+import android.content.res.Configuration;
+import android.graphics.Rect;
+import android.os.IBinder;
+import android.util.Slog;
+import android.view.SurfaceControl;
+
+import java.util.ArrayList;
+import java.util.Comparator;
+
+/**
+ * A Tile. Right now this acts as a proxy for manipulating non-child stacks. Eventually, this
+ * can become an actual parent.
+ */
+// TODO(task-hierarchy): Remove when tasks can nest >2 or when single tasks can handle their
+// own lifecycles.
+public class TaskTile extends ActivityStack {
+ private static final String TAG = "TaskTile";
+ final ArrayList<WindowContainer> mChildren = new ArrayList<>();
+
+ private static ActivityInfo createEmptyActivityInfo() {
+ ActivityInfo info = new ActivityInfo();
+ info.applicationInfo = new ApplicationInfo();
+ return info;
+ }
+
+ TaskTile(ActivityTaskManagerService atmService, int id, int windowingMode) {
+ super(atmService, id, new Intent() /*intent*/, null /*affinityIntent*/, null /*affinity*/,
+ null /*rootAffinity*/, null /*realActivity*/, null /*origActivity*/,
+ false /*rootWasReset*/, false /*autoRemoveRecents*/, false /*askedCompatMode*/,
+ 0 /*userId*/, 0 /*effectiveUid*/, null /*lastDescription*/,
+ System.currentTimeMillis(), true /*neverRelinquishIdentity*/,
+ new ActivityManager.TaskDescription(), id, INVALID_TASK_ID, INVALID_TASK_ID,
+ 0 /*taskAffiliationColor*/, 0 /*callingUid*/, "" /*callingPackage*/,
+ RESIZE_MODE_RESIZEABLE, false /*supportsPictureInPicture*/,
+ false /*_realActivitySuspended*/, false /*userSetupComplete*/, INVALID_MIN_SIZE,
+ INVALID_MIN_SIZE, createEmptyActivityInfo(), null /*voiceSession*/,
+ null /*voiceInteractor*/, null /*stack*/);
+ getRequestedOverrideConfiguration().windowConfiguration.setWindowingMode(windowingMode);
+ }
+
+ @Override
+ void onDisplayChanged(DisplayContent dc) {
+ mDisplayContent = null;
+ if (dc != null) {
+ dc.getPendingTransaction().merge(getPendingTransaction());
+ }
+ mDisplayContent = dc;
+ // Virtual parent, so don't notify children.
+ }
+
+ /**
+ * If there is a disconnection, this will clean up any vestigial surfaces left on the tile
+ * leash by moving known children to a new surfacecontrol and then removing the old one.
+ */
+ void cleanupSurfaces() {
+ if (mSurfaceControl == null) {
+ return;
+ }
+ SurfaceControl oldSurface = mSurfaceControl;
+ WindowContainer parentWin = getParent();
+ if (parentWin == null) {
+ return;
+ }
+ mSurfaceControl = parentWin.makeChildSurface(null).setName("TaskTile " + mTaskId + " - "
+ + getRequestedOverrideWindowingMode()).setContainerLayer().build();
+ SurfaceControl.Transaction t = parentWin.getPendingTransaction();
+ t.show(mSurfaceControl);
+ for (int i = 0; i < mChildren.size(); ++i) {
+ if (mChildren.get(i).getSurfaceControl() == null) {
+ continue;
+ }
+ mChildren.get(i).reparentSurfaceControl(t, mSurfaceControl);
+ }
+ t.remove(oldSurface);
+ }
+
+ @Override
+ protected void addChild(WindowContainer child, Comparator<WindowContainer> comparator) {
+ throw new RuntimeException("Improper use of addChild() on Tile");
+ }
+
+ @Override
+ void addChild(WindowContainer child, int index) {
+ mChildren.add(child);
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(this);
+ }
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ @Override
+ void removeChild(WindowContainer child) {
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(null);
+ }
+ mChildren.remove(child);
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ void removeAllChildren() {
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ if (child instanceof ActivityStack) {
+ ((ActivityStack) child).setTile(null);
+ }
+ }
+ mChildren.clear();
+ mAtmService.mTaskOrganizerController.dispatchTaskInfoChanged(
+ this, false /* force */);
+ }
+
+ @Override
+ protected int getChildCount() {
+ // Currently 0 as this isn't a proper hierarchy member yet.
+ return 0;
+ }
+
+ @Override
+ public void setWindowingMode(/*@WindowConfiguration.WindowingMode*/ int windowingMode) {
+ Configuration c = new Configuration(getRequestedOverrideConfiguration());
+ c.windowConfiguration.setWindowingMode(windowingMode);
+ onRequestedOverrideConfigurationChanged(c);
+ }
+
+ @Override
+ public void onConfigurationChanged(Configuration newParentConfig) {
+ super.onConfigurationChanged(newParentConfig);
+ for (int i = mChildren.size() - 1; i >= 0; --i) {
+ final WindowContainer child = mChildren.get(i);
+ child.onConfigurationChanged(child.getParent().getConfiguration());
+ }
+ }
+
+ /**
+ * Until this can be part of the hierarchy, the Stack level can use this utility during
+ * resolveOverrideConfig to simulate inheritance.
+ */
+ void updateResolvedConfig(Configuration inOutResolvedConfig) {
+ Rect resolveBounds = inOutResolvedConfig.windowConfiguration.getBounds();
+ if (resolveBounds == null || resolveBounds.isEmpty()) {
+ resolveBounds.set(getRequestedOverrideBounds());
+ }
+ int stackMode = inOutResolvedConfig.windowConfiguration.getWindowingMode();
+ if (stackMode == WindowConfiguration.WINDOWING_MODE_UNDEFINED
+ || stackMode == WindowConfiguration.WINDOWING_MODE_FULLSCREEN) {
+ // Also replace FULLSCREEN because we interpret FULLSCREEN as "fill parent"
+ inOutResolvedConfig.windowConfiguration.setWindowingMode(
+ getRequestedOverrideWindowingMode());
+ }
+ if (inOutResolvedConfig.smallestScreenWidthDp
+ == Configuration.SMALLEST_SCREEN_WIDTH_DP_UNDEFINED) {
+ inOutResolvedConfig.smallestScreenWidthDp =
+ getRequestedOverrideConfiguration().smallestScreenWidthDp;
+ }
+ }
+
+ @Override
+ void fillTaskInfo(TaskInfo info) {
+ super.fillTaskInfo(info);
+ WindowContainer top = null;
+ // Check mChildren.isEmpty directly because hasChild() -> getChildCount() always returns 0
+ if (!mChildren.isEmpty()) {
+ // Find the top-most root task which is a virtual child of this Tile. Because this is a
+ // virtual parent, the mChildren order here isn't changed during hierarchy operations.
+ WindowContainer parent = mChildren.get(0).getParent();
+ for (int i = parent.getChildCount() - 1; i >= 0; --i) {
+ if (mChildren.contains(parent.getChildAt(i))) {
+ top = parent.getChildAt(i);
+ break;
+ }
+ }
+ }
+ final Task topTask = top == null ? null : top.getTopMostTask();
+ boolean isResizable = topTask == null || topTask.isResizeable();
+ info.resizeMode = isResizable ? RESIZE_MODE_RESIZEABLE : RESIZE_MODE_UNRESIZEABLE;
+ info.topActivityType = top == null ? ACTIVITY_TYPE_UNDEFINED : top.getActivityType();
+ info.configuration.setTo(getRequestedOverrideConfiguration());
+ }
+
+ @Override
+ void removeImmediately() {
+ removeAllChildren();
+ super.removeImmediately();
+ }
+
+ static TaskTile forToken(IBinder token) {
+ try {
+ return (TaskTile) ((TaskToken) token).getContainer();
+ } catch (ClassCastException e) {
+ Slog.w(TAG, "Bad tile token: " + token, e);
+ return null;
+ }
+ }
+}
diff --git a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
index 801e521..bd70599 100644
--- a/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
+++ b/services/core/java/com/android/server/wm/WallpaperAnimationAdapter.java
@@ -18,6 +18,7 @@
import static com.android.server.wm.AnimationAdapterProto.REMOTE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_REMOTE_ANIMATIONS;
import static com.android.server.wm.RemoteAnimationAdapterWrapperProto.TARGET;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import android.graphics.Point;
import android.os.SystemClock;
@@ -26,6 +27,7 @@
import android.view.SurfaceControl;
import com.android.server.protolog.common.ProtoLog;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import java.io.PrintWriter;
import java.util.ArrayList;
@@ -40,6 +42,7 @@
private final WallpaperWindowToken mWallpaperToken;
private SurfaceControl mCapturedLeash;
private SurfaceAnimator.OnAnimationFinishedCallback mCapturedLeashFinishCallback;
+ private @AnimationType int mLastAnimationType;
private long mDurationHint;
private long mStatusBarTransitionDelay;
@@ -77,7 +80,7 @@
wallpaperWindow, durationHint, statusBarTransitionDelay,
animationCanceledRunnable);
wallpaperWindow.startAnimation(wallpaperWindow.getPendingTransaction(),
- wallpaperAdapter, false /* hidden */);
+ wallpaperAdapter, false /* hidden */, ANIMATION_TYPE_WINDOW_ANIMATION);
targets.add(wallpaperAdapter.createRemoteAnimationTarget());
adaptersOut.add(wallpaperAdapter);
});
@@ -110,6 +113,13 @@
}
/**
+ * @return the type of animation.
+ */
+ @AnimationType int getLastAnimationType() {
+ return mLastAnimationType;
+ }
+
+ /**
* @return the wallpaper window
*/
WallpaperWindowToken getToken() {
@@ -124,13 +134,14 @@
@Override
public void startAnimation(SurfaceControl animationLeash, SurfaceControl.Transaction t,
- SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
+ @AnimationType int type, SurfaceAnimator.OnAnimationFinishedCallback finishCallback) {
ProtoLog.d(WM_DEBUG_REMOTE_ANIMATIONS, "startAnimation");
// Restore z-layering until client has a chance to modify it.
t.setLayer(animationLeash, mWallpaperToken.getPrefixOrderIndex());
mCapturedLeash = animationLeash;
mCapturedLeashFinishCallback = finishCallback;
+ mLastAnimationType = type;
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index d828ca6..8672315 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -31,6 +31,7 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS_ANIM;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -74,6 +75,8 @@
import com.android.internal.util.ToBooleanFunction;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
@@ -1851,19 +1854,24 @@
* @param anim The animation to run.
* @param hidden Whether our container is currently hidden. TODO This should use isVisible at
* some point but the meaning is too weird to work for all containers.
+ * @param type The type of animation defined as {@link AnimationType}.
* @param animationFinishedCallback The callback being triggered when the animation finishes.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
- @Nullable Runnable animationFinishedCallback) {
- if (DEBUG_ANIM) Slog.v(TAG, "Starting animation on " + this + ": " + anim);
+ @AnimationType int type,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+ if (DEBUG_ANIM) {
+ Slog.v(TAG, "Starting animation on " + this + ": type=" + type + ", anim=" + anim);
+ }
// TODO: This should use isVisible() but because isVisible has a really weird meaning at
// the moment this doesn't work for all animatable window containers.
- mSurfaceAnimator.startAnimation(t, anim, hidden, animationFinishedCallback);
+ mSurfaceAnimator.startAnimation(t, anim, hidden, type, animationFinishedCallback);
}
- void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
- startAnimation(t, anim, hidden, null /* animationFinishedCallback */);
+ void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden,
+ @AnimationType int type) {
+ startAnimation(t, anim, hidden, type, null /* animationFinishedCallback */);
}
void transferAnimation(WindowContainer from) {
@@ -1916,7 +1924,8 @@
* @see #getAnimationAdapter
*/
boolean applyAnimation(WindowManager.LayoutParams lp, int transit, boolean enter,
- boolean isVoiceInteraction, @Nullable Runnable animationFinishedCallback) {
+ boolean isVoiceInteraction,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
if (mWmService.mDisableTransitionAnimation) {
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
"applyAnimation: transition animation is disabled or skipped. "
@@ -1937,7 +1946,7 @@
AnimationAdapter thumbnailAdapter = adapters.second;
if (adapter != null) {
startAnimation(getPendingTransaction(), adapter, !isVisible(),
- animationFinishedCallback);
+ ANIMATION_TYPE_APP_TRANSITION, animationFinishedCallback);
if (adapter.getShowWallpaper()) {
getDisplayContent().pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
}
@@ -2128,7 +2137,7 @@
/**
* Called when an animation has finished running.
*/
- protected void onAnimationFinished() {
+ protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
mWmService.onAnimationFinished();
}
diff --git a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
index 8948f6f..90e3be7 100644
--- a/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
+++ b/services/core/java/com/android/server/wm/WindowContainerThumbnail.java
@@ -20,6 +20,7 @@
import static android.view.SurfaceControl.METADATA_WINDOW_TYPE;
import static com.android.server.wm.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static com.android.server.wm.WindowContainerThumbnailProto.HEIGHT;
import static com.android.server.wm.WindowContainerThumbnailProto.SURFACE_ANIMATOR;
import static com.android.server.wm.WindowContainerThumbnailProto.WIDTH;
@@ -40,6 +41,7 @@
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.SurfaceAnimator.Animatable;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import java.util.function.Supplier;
@@ -85,7 +87,7 @@
// We can't use a delegating constructor since we need to
// reference this::onAnimationFinished
mSurfaceAnimator =
- new SurfaceAnimator(this, null /* animationFinishedCallback */,
+ new SurfaceAnimator(this, this::onAnimationFinished /* animationFinishedCallback */,
container.mWmService);
}
mWidth = thumbnailHeader.getWidth();
@@ -130,14 +132,19 @@
new WindowAnimationSpec(anim, position,
mWindowContainer.getDisplayContent().mAppTransition.canSkipFirstFrame(),
mWindowContainer.getDisplayContent().getWindowCornerRadius()),
- mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */);
+ mWindowContainer.mWmService.mSurfaceAnimationRunner), false /* hidden */,
+ ANIMATION_TYPE_RECENTS, null /* animationFinishedCallback */);
}
/**
* Start animation with existing adapter.
*/
void startAnimation(Transaction t, AnimationAdapter anim, boolean hidden) {
- mSurfaceAnimator.startAnimation(t, anim, hidden);
+ mSurfaceAnimator.startAnimation(t, anim, hidden, ANIMATION_TYPE_RECENTS,
+ null /* animationFinishedCallback */);
+ }
+
+ private void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
}
void setShowing(Transaction pendingTransaction, boolean show) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 229bd2f..98c584f 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -397,7 +397,7 @@
* @see #HIERARCHICAL_ANIMATIONS_PROPERTY
*/
static boolean sHierarchicalAnimations =
- SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, false);
+ SystemProperties.getBoolean(HIERARCHICAL_ANIMATIONS_PROPERTY, true);
// Enums for animation scale update types.
@Retention(RetentionPolicy.SOURCE)
@@ -938,7 +938,7 @@
* Whether the UI is currently running in touch mode (not showing
* navigational focus because the user is directly pressing the screen).
*/
- boolean mInTouchMode;
+ private boolean mInTouchMode;
private ViewServer mViewServer;
final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
@@ -2536,11 +2536,12 @@
@Override
public void addWindowToken(IBinder binder, int type, int displayId) {
- addWindowContextToken(binder, type, displayId, null);
+ addWindowTokenWithOptions(binder, type, displayId, null /* options */,
+ null /* packageName */);
}
- @Override
- public int addWindowContextToken(IBinder binder, int type, int displayId, String packageName) {
+ public int addWindowTokenWithOptions(IBinder binder, int type, int displayId, Bundle options,
+ String packageName) {
final boolean callerCanManageAppTokens =
checkCallingPermission(MANAGE_APP_TOKENS, "addWindowToken()");
if (!callerCanManageAppTokens) {
@@ -3460,6 +3461,12 @@
mInputManager.setInTouchMode(mode);
}
+ boolean getInTouchMode() {
+ synchronized (mGlobalLock) {
+ return mInTouchMode;
+ }
+ }
+
public void showEmulatorDisplayOverlayIfNeeded() {
if (mContext.getResources().getBoolean(
com.android.internal.R.bool.config_windowEnableCircularEmulatorDisplayOverlay)
@@ -5905,7 +5912,7 @@
*/
void dumpDebugLocked(ProtoOutputStream proto, @WindowTraceLogLevel int logLevel) {
mPolicy.dumpDebug(proto, POLICY);
- mRoot.dumpDebugInner(proto, ROOT_WINDOW_CONTAINER, logLevel);
+ mRoot.dumpDebug(proto, ROOT_WINDOW_CONTAINER, logLevel);
final DisplayContent topFocusedDisplayContent = mRoot.getTopFocusedDisplayContent();
if (topFocusedDisplayContent.mCurrentFocus != null) {
topFocusedDisplayContent.mCurrentFocus.writeIdentifierToProto(proto, FOCUSED_WINDOW);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index fc04126..42e5bbc 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -115,6 +115,7 @@
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
@@ -231,6 +232,7 @@
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.protolog.common.ProtoLog;
import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.utils.WmDisplayCutout;
import java.io.PrintWriter;
@@ -415,6 +417,9 @@
private final WindowFrames mWindowFrames = new WindowFrames();
+ /** The frames used to compute a temporal layout appearance. */
+ private WindowFrames mSimulatedWindowFrames;
+
/**
* Usually empty. Set to the task's tempInsetFrame. See
*{@link android.app.IActivityTaskManager#resizeDockedStack}.
@@ -970,6 +975,16 @@
return super.getDisplayedBounds();
}
+ void computeFrame(DisplayFrames displayFrames) {
+ getLayoutingWindowFrames().setDisplayCutout(displayFrames.mDisplayCutout);
+ computeFrameLw();
+ // Update the source frame to provide insets to other windows during layout. If the
+ // simulated frames exist, then this is not computing a stable result so just skip.
+ if (mControllableInsetProvider != null && mSimulatedWindowFrames == null) {
+ mControllableInsetProvider.updateSourceFrame();
+ }
+ }
+
@Override
public void computeFrameLw() {
if (mWillReplaceWindow && (mAnimatingExit || !mReplacingRemoveRequested)) {
@@ -985,6 +1000,7 @@
final boolean isFullscreenAndFillsDisplay = !inMultiWindowMode() && matchesDisplayBounds();
final boolean windowsAreFloating = task != null && task.isFloating();
final DisplayContent dc = getDisplayContent();
+ final WindowFrames windowFrames = getLayoutingWindowFrames();
mInsetFrame.set(getBounds());
@@ -1006,43 +1022,43 @@
imeWin != null && imeWin.isVisibleNow() && isInputMethodAdjustTarget;
if (isFullscreenAndFillsDisplay || layoutInParentFrame()) {
// We use the parent frame as the containing frame for fullscreen and child windows
- mWindowFrames.mContainingFrame.set(mWindowFrames.mParentFrame);
- layoutDisplayFrame = mWindowFrames.mDisplayFrame;
- layoutContainingFrame = mWindowFrames.mParentFrame;
+ windowFrames.mContainingFrame.set(windowFrames.mParentFrame);
+ layoutDisplayFrame = windowFrames.mDisplayFrame;
+ layoutContainingFrame = windowFrames.mParentFrame;
layoutXDiff = 0;
layoutYDiff = 0;
} else {
- mWindowFrames.mContainingFrame.set(getDisplayedBounds());
+ windowFrames.mContainingFrame.set(getDisplayedBounds());
if (mActivityRecord != null && !mActivityRecord.mFrozenBounds.isEmpty()) {
// If the bounds are frozen, we still want to translate the window freely and only
// freeze the size.
Rect frozen = mActivityRecord.mFrozenBounds.peek();
- mWindowFrames.mContainingFrame.right =
- mWindowFrames.mContainingFrame.left + frozen.width();
- mWindowFrames.mContainingFrame.bottom =
- mWindowFrames.mContainingFrame.top + frozen.height();
+ windowFrames.mContainingFrame.right =
+ windowFrames.mContainingFrame.left + frozen.width();
+ windowFrames.mContainingFrame.bottom =
+ windowFrames.mContainingFrame.top + frozen.height();
}
// IME is up and obscuring this window. Adjust the window position so it is visible.
if (isImeTarget) {
if (inFreeformWindowingMode()) {
// Push the freeform window up to make room for the IME. However, don't push
// it up past the top of the screen.
- final int bottomOverlap = mWindowFrames.mContainingFrame.bottom
- - mWindowFrames.mVisibleFrame.bottom;
+ final int bottomOverlap = windowFrames.mContainingFrame.bottom
+ - windowFrames.mVisibleFrame.bottom;
if (bottomOverlap > 0) {
- final int distanceToTop = Math.max(mWindowFrames.mContainingFrame.top
- - mWindowFrames.mContentFrame.top, 0);
+ final int distanceToTop = Math.max(windowFrames.mContainingFrame.top
+ - windowFrames.mContentFrame.top, 0);
int offs = Math.min(bottomOverlap, distanceToTop);
- mWindowFrames.mContainingFrame.offset(0, -offs);
+ windowFrames.mContainingFrame.offset(0, -offs);
mInsetFrame.offset(0, -offs);
}
- } else if (!inPinnedWindowingMode() && mWindowFrames.mContainingFrame.bottom
- > mWindowFrames.mParentFrame.bottom) {
+ } else if (!inPinnedWindowingMode() && windowFrames.mContainingFrame.bottom
+ > windowFrames.mParentFrame.bottom) {
// But in docked we want to behave like fullscreen and behave as if the task
// were given smaller bounds for the purposes of layout. Skip adjustments for
// the pinned stack, they are handled separately in the PinnedStackController.
- mWindowFrames.mContainingFrame.bottom = mWindowFrames.mParentFrame.bottom;
+ windowFrames.mContainingFrame.bottom = windowFrames.mParentFrame.bottom;
}
}
@@ -1050,8 +1066,8 @@
// In floating modes (e.g. freeform, pinned) we have only to set the rectangle
// if it wasn't set already. No need to intersect it with the (visible)
// "content frame" since it is allowed to be outside the visible desktop.
- if (mWindowFrames.mContainingFrame.isEmpty()) {
- mWindowFrames.mContainingFrame.set(mWindowFrames.mContentFrame);
+ if (windowFrames.mContainingFrame.isEmpty()) {
+ windowFrames.mContainingFrame.set(windowFrames.mContentFrame);
}
}
@@ -1061,115 +1077,115 @@
// PIP edge case: When going from pinned to fullscreen, we apply a
// tempInsetFrame for the full task - but we're still at the start of the animation.
// To prevent a jump if there's a letterbox, restrict to the parent frame.
- mInsetFrame.intersectUnchecked(mWindowFrames.mParentFrame);
- mWindowFrames.mContainingFrame.intersectUnchecked(mWindowFrames.mParentFrame);
+ mInsetFrame.intersectUnchecked(windowFrames.mParentFrame);
+ windowFrames.mContainingFrame.intersectUnchecked(windowFrames.mParentFrame);
}
- layoutDisplayFrame = new Rect(mWindowFrames.mDisplayFrame);
- mWindowFrames.mDisplayFrame.set(mWindowFrames.mContainingFrame);
- layoutXDiff = mInsetFrame.left - mWindowFrames.mContainingFrame.left;
- layoutYDiff = mInsetFrame.top - mWindowFrames.mContainingFrame.top;
+ layoutDisplayFrame = new Rect(windowFrames.mDisplayFrame);
+ windowFrames.mDisplayFrame.set(windowFrames.mContainingFrame);
+ layoutXDiff = mInsetFrame.left - windowFrames.mContainingFrame.left;
+ layoutYDiff = mInsetFrame.top - windowFrames.mContainingFrame.top;
layoutContainingFrame = mInsetFrame;
mTmpRect.set(0, 0, dc.getDisplayInfo().logicalWidth, dc.getDisplayInfo().logicalHeight);
- subtractInsets(mWindowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame,
+ subtractInsets(windowFrames.mDisplayFrame, layoutContainingFrame, layoutDisplayFrame,
mTmpRect);
if (!layoutInParentFrame()) {
- subtractInsets(mWindowFrames.mContainingFrame, layoutContainingFrame,
- mWindowFrames.mParentFrame, mTmpRect);
- subtractInsets(mInsetFrame, layoutContainingFrame, mWindowFrames.mParentFrame,
+ subtractInsets(windowFrames.mContainingFrame, layoutContainingFrame,
+ windowFrames.mParentFrame, mTmpRect);
+ subtractInsets(mInsetFrame, layoutContainingFrame, windowFrames.mParentFrame,
mTmpRect);
}
layoutDisplayFrame.intersect(layoutContainingFrame);
}
- final int pw = mWindowFrames.mContainingFrame.width();
- final int ph = mWindowFrames.mContainingFrame.height();
+ final int pw = windowFrames.mContainingFrame.width();
+ final int ph = windowFrames.mContainingFrame.height();
if (mRequestedWidth != mLastRequestedWidth || mRequestedHeight != mLastRequestedHeight) {
mLastRequestedWidth = mRequestedWidth;
mLastRequestedHeight = mRequestedHeight;
- mWindowFrames.setContentChanged(true);
+ windowFrames.setContentChanged(true);
}
- final int fw = mWindowFrames.mFrame.width();
- final int fh = mWindowFrames.mFrame.height();
+ final int fw = windowFrames.mFrame.width();
+ final int fh = windowFrames.mFrame.height();
- applyGravityAndUpdateFrame(layoutContainingFrame, layoutDisplayFrame);
+ applyGravityAndUpdateFrame(windowFrames, layoutContainingFrame, layoutDisplayFrame);
// Make sure the content and visible frames are inside of the
// final window frame.
- if (windowsAreFloating && !mWindowFrames.mFrame.isEmpty()) {
- final int visBottom = mWindowFrames.mVisibleFrame.bottom;
- final int contentBottom = mWindowFrames.mContentFrame.bottom;
- mWindowFrames.mContentFrame.set(mWindowFrames.mFrame);
- mWindowFrames.mVisibleFrame.set(mWindowFrames.mContentFrame);
- mWindowFrames.mStableFrame.set(mWindowFrames.mContentFrame);
+ if (windowsAreFloating && !windowFrames.mFrame.isEmpty()) {
+ final int visBottom = windowFrames.mVisibleFrame.bottom;
+ final int contentBottom = windowFrames.mContentFrame.bottom;
+ windowFrames.mContentFrame.set(windowFrames.mFrame);
+ windowFrames.mVisibleFrame.set(windowFrames.mContentFrame);
+ windowFrames.mStableFrame.set(windowFrames.mContentFrame);
if (isImeTarget && inFreeformWindowingMode()) {
// After displacing a freeform window to make room for the ime, any part of
// the window still covered by IME should be inset.
- if (contentBottom + layoutYDiff < mWindowFrames.mContentFrame.bottom) {
- mWindowFrames.mContentFrame.bottom = contentBottom + layoutYDiff;
+ if (contentBottom + layoutYDiff < windowFrames.mContentFrame.bottom) {
+ windowFrames.mContentFrame.bottom = contentBottom + layoutYDiff;
}
- if (visBottom + layoutYDiff < mWindowFrames.mVisibleFrame.bottom) {
- mWindowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff;
+ if (visBottom + layoutYDiff < windowFrames.mVisibleFrame.bottom) {
+ windowFrames.mVisibleFrame.bottom = visBottom + layoutYDiff;
}
}
} else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- dc.getDockedDividerController().positionDockedStackedDivider(mWindowFrames.mFrame);
- mWindowFrames.mContentFrame.set(mWindowFrames.mFrame);
- if (!mWindowFrames.mFrame.equals(mWindowFrames.mLastFrame)) {
+ dc.getDockedDividerController().positionDockedStackedDivider(windowFrames.mFrame);
+ windowFrames.mContentFrame.set(windowFrames.mFrame);
+ if (!windowFrames.mFrame.equals(windowFrames.mLastFrame)) {
mMovedByResize = true;
}
} else {
- mWindowFrames.mContentFrame.set(
- Math.max(mWindowFrames.mContentFrame.left, mWindowFrames.mFrame.left),
- Math.max(mWindowFrames.mContentFrame.top, mWindowFrames.mFrame.top),
- Math.min(mWindowFrames.mContentFrame.right, mWindowFrames.mFrame.right),
- Math.min(mWindowFrames.mContentFrame.bottom, mWindowFrames.mFrame.bottom));
+ windowFrames.mContentFrame.set(
+ Math.max(windowFrames.mContentFrame.left, windowFrames.mFrame.left),
+ Math.max(windowFrames.mContentFrame.top, windowFrames.mFrame.top),
+ Math.min(windowFrames.mContentFrame.right, windowFrames.mFrame.right),
+ Math.min(windowFrames.mContentFrame.bottom, windowFrames.mFrame.bottom));
- mWindowFrames.mVisibleFrame.set(
- Math.max(mWindowFrames.mVisibleFrame.left, mWindowFrames.mFrame.left),
- Math.max(mWindowFrames.mVisibleFrame.top, mWindowFrames.mFrame.top),
- Math.min(mWindowFrames.mVisibleFrame.right, mWindowFrames.mFrame.right),
- Math.min(mWindowFrames.mVisibleFrame.bottom, mWindowFrames.mFrame.bottom));
+ windowFrames.mVisibleFrame.set(
+ Math.max(windowFrames.mVisibleFrame.left, windowFrames.mFrame.left),
+ Math.max(windowFrames.mVisibleFrame.top, windowFrames.mFrame.top),
+ Math.min(windowFrames.mVisibleFrame.right, windowFrames.mFrame.right),
+ Math.min(windowFrames.mVisibleFrame.bottom, windowFrames.mFrame.bottom));
- mWindowFrames.mStableFrame.set(
- Math.max(mWindowFrames.mStableFrame.left, mWindowFrames.mFrame.left),
- Math.max(mWindowFrames.mStableFrame.top, mWindowFrames.mFrame.top),
- Math.min(mWindowFrames.mStableFrame.right, mWindowFrames.mFrame.right),
- Math.min(mWindowFrames.mStableFrame.bottom, mWindowFrames.mFrame.bottom));
+ windowFrames.mStableFrame.set(
+ Math.max(windowFrames.mStableFrame.left, windowFrames.mFrame.left),
+ Math.max(windowFrames.mStableFrame.top, windowFrames.mFrame.top),
+ Math.min(windowFrames.mStableFrame.right, windowFrames.mFrame.right),
+ Math.min(windowFrames.mStableFrame.bottom, windowFrames.mFrame.bottom));
}
if (mAttrs.type == TYPE_DOCK_DIVIDER) {
- final WmDisplayCutout c = mWindowFrames.mDisplayCutout.calculateRelativeTo(
- mWindowFrames.mDisplayFrame);
- mWindowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
+ final WmDisplayCutout c = windowFrames.mDisplayCutout.calculateRelativeTo(
+ windowFrames.mDisplayFrame);
+ windowFrames.calculateDockedDividerInsets(c.getDisplayCutout().getSafeInsets());
} else {
getDisplayContent().getBounds(mTmpRect);
- mWindowFrames.calculateInsets(
+ windowFrames.calculateInsets(
windowsAreFloating, isFullscreenAndFillsDisplay, mTmpRect);
}
- mWindowFrames.setDisplayCutout(
- mWindowFrames.mDisplayCutout.calculateRelativeTo(mWindowFrames.mFrame));
+ windowFrames.setDisplayCutout(
+ windowFrames.mDisplayCutout.calculateRelativeTo(windowFrames.mFrame));
// Offset the actual frame by the amount layout frame is off.
- mWindowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
+ windowFrames.offsetFrames(-layoutXDiff, -layoutYDiff);
- mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
+ windowFrames.mCompatFrame.set(windowFrames.mFrame);
if (inSizeCompatMode()) {
// If there is a size compatibility scale being applied to the
// window, we need to apply this to its insets so that they are
// reported to the app in its coordinate space.
- mWindowFrames.scaleInsets(mInvGlobalScale);
+ windowFrames.scaleInsets(mInvGlobalScale);
// Also the scaled frame that we report to the app needs to be
// adjusted to be in its coordinate space.
- mWindowFrames.mCompatFrame.scale(mInvGlobalScale);
+ windowFrames.mCompatFrame.scale(mInvGlobalScale);
}
- if (mIsWallpaper && (fw != mWindowFrames.mFrame.width()
- || fh != mWindowFrames.mFrame.height())) {
+ if (mIsWallpaper && (fw != windowFrames.mFrame.width()
+ || fh != windowFrames.mFrame.height())) {
final DisplayContent displayContent = getDisplayContent();
if (displayContent != null) {
final DisplayInfo displayInfo = displayContent.getDisplayInfo();
@@ -1179,7 +1195,7 @@
}
// Calculate relative frame
- mWindowFrames.mRelFrame.set(mWindowFrames.mFrame);
+ windowFrames.mRelFrame.set(windowFrames.mFrame);
WindowContainer parent = getParent();
int parentLeft = 0;
int parentTop = 0;
@@ -1191,15 +1207,15 @@
parentLeft = parentBounds.left;
parentTop = parentBounds.top;
}
- mWindowFrames.mRelFrame.offsetTo(mWindowFrames.mFrame.left - parentLeft,
- mWindowFrames.mFrame.top - parentTop);
+ windowFrames.mRelFrame.offsetTo(windowFrames.mFrame.left - parentLeft,
+ windowFrames.mFrame.top - parentTop);
if (DEBUG_LAYOUT || DEBUG) {
Slog.v(TAG, "Resolving (mRequestedWidth="
+ mRequestedWidth + ", mRequestedheight="
+ mRequestedHeight + ") to" + " (pw=" + pw + ", ph=" + ph
- + "): frame=" + mWindowFrames.mFrame.toShortString()
- + " " + mWindowFrames.getInsetsInfo()
+ + "): frame=" + windowFrames.mFrame.toShortString()
+ + " " + windowFrames.getInsetsInfo()
+ " " + mAttrs.getTitle());
}
}
@@ -3984,7 +4000,8 @@
}
}
- private void applyGravityAndUpdateFrame(Rect containingFrame, Rect displayFrame) {
+ private void applyGravityAndUpdateFrame(WindowFrames windowFrames, Rect containingFrame,
+ Rect displayFrame) {
final int pw = containingFrame.width();
final int ph = containingFrame.height();
final Task task = getTask();
@@ -4054,19 +4071,19 @@
// Set mFrame
Gravity.apply(mAttrs.gravity, w, h, containingFrame,
(int) (x + mAttrs.horizontalMargin * pw),
- (int) (y + mAttrs.verticalMargin * ph), mWindowFrames.mFrame);
+ (int) (y + mAttrs.verticalMargin * ph), windowFrames.mFrame);
// Now make sure the window fits in the overall display frame.
if (fitToDisplay) {
- Gravity.applyDisplay(mAttrs.gravity, displayFrame, mWindowFrames.mFrame);
+ Gravity.applyDisplay(mAttrs.gravity, displayFrame, windowFrames.mFrame);
}
// We need to make sure we update the CompatFrame as it is used for
// cropping decisions, etc, on systems where we lack a decor layer.
- mWindowFrames.mCompatFrame.set(mWindowFrames.mFrame);
+ windowFrames.mCompatFrame.set(windowFrames.mFrame);
if (inSizeCompatMode) {
// See comparable block in computeFrameLw.
- mWindowFrames.mCompatFrame.scale(mInvGlobalScale);
+ windowFrames.mCompatFrame.scale(mInvGlobalScale);
}
}
@@ -5027,12 +5044,13 @@
}
private void startAnimation(Transaction t, AnimationAdapter adapter) {
- startAnimation(t, adapter, mWinAnimator.mLastHidden, null /* animationFinishedCallback */);
+ startAnimation(t, adapter, mWinAnimator.mLastHidden, ANIMATION_TYPE_WINDOW_ANIMATION,
+ null /* animationFinishedCallback */);
}
@Override
- protected void onAnimationFinished() {
- super.onAnimationFinished();
+ protected void onAnimationFinished(@AnimationType int type, AnimationAdapter anim) {
+ super.onAnimationFinished(type, anim);
mWinAnimator.onAnimationFinished();
}
@@ -5530,6 +5548,22 @@
return mWindowFrames;
}
+ /**
+ * If the transient frame is set, the computed result won't be used in real layout. So this
+ * frames must be cleared when the simulated computation is done.
+ */
+ void setSimulatedWindowFrames(WindowFrames windowFrames) {
+ mSimulatedWindowFrames = windowFrames;
+ }
+
+ /**
+ * Use this method only when the simulated frames may be set, so it is clearer that the calling
+ * path may be used to simulate layout.
+ */
+ WindowFrames getLayoutingWindowFrames() {
+ return mSimulatedWindowFrames != null ? mSimulatedWindowFrames : mWindowFrames;
+ }
+
void resetContentChanged() {
mWindowFrames.setContentChanged(false);
}
diff --git a/services/core/jni/Android.bp b/services/core/jni/Android.bp
index 4a2636e..390068e 100644
--- a/services/core/jni/Android.bp
+++ b/services/core/jni/Android.bp
@@ -22,6 +22,8 @@
"BroadcastRadio/TunerCallback.cpp",
"BroadcastRadio/convert.cpp",
"BroadcastRadio/regions.cpp",
+ "stats/PowerStatsPuller.cpp",
+ "stats/SubsystemSleepStatePuller.cpp",
"com_android_server_am_BatteryStatsService.cpp",
"com_android_server_connectivity_Vpn.cpp",
"com_android_server_ConsumerIrService.cpp",
@@ -37,6 +39,7 @@
"com_android_server_security_VerityUtils.cpp",
"com_android_server_SerialService.cpp",
"com_android_server_soundtrigger_middleware_AudioSessionProviderImpl.cpp",
+ "com_android_server_stats_pull_StatsPullAtomService.cpp",
"com_android_server_storage_AppFuseBridge.cpp",
"com_android_server_SystemServer.cpp",
"com_android_server_TestNetworkService.cpp",
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 78b64ca..67254b8 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -14,6 +14,12 @@
* limitations under the License.
*/
+#include <dlfcn.h>
+#include <pthread.h>
+
+#include <chrono>
+#include <thread>
+
#include <jni.h>
#include <nativehelper/JNIHelp.h>
@@ -25,12 +31,17 @@
#include <sensorservicehidl/SensorManager.h>
#include <bionic/malloc.h>
+#include <bionic/reserved_signals.h>
+#include <android-base/properties.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/misc.h>
#include <utils/AndroidThreads.h>
+using android::base::GetIntProperty;
+using namespace std::chrono_literals;
+
namespace android {
static void android_server_SystemServer_startSensorService(JNIEnv* /* env */, jobject /* clazz */) {
@@ -68,7 +79,50 @@
static void android_server_SystemServer_initZygoteChildHeapProfiling(JNIEnv* /* env */,
jobject /* clazz */) {
- android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+ android_mallopt(M_INIT_ZYGOTE_CHILD_PROFILING, nullptr, 0);
+}
+
+static int get_current_max_fd() {
+ // Not actually guaranteed to be the max, but close enough for our purposes.
+ int fd = open("/dev/null", O_RDONLY | O_CLOEXEC);
+ LOG_ALWAYS_FATAL_IF(fd == -1, "failed to open /dev/null: %s", strerror(errno));
+ close(fd);
+ return fd;
+}
+
+static const char kFdLeakEnableThresholdProperty[] = "persist.sys.debug.fdtrack_enable_threshold";
+static const char kFdLeakAbortThresholdProperty[] = "persist.sys.debug.fdtrack_abort_threshold";
+static const char kFdLeakCheckIntervalProperty[] = "persist.sys.debug.fdtrack_interval";
+
+static void android_server_SystemServer_spawnFdLeakCheckThread(JNIEnv*, jobject) {
+ std::thread([]() {
+ pthread_setname_np(pthread_self(), "FdLeakCheckThread");
+ bool loaded = false;
+ while (true) {
+ const int enable_threshold = GetIntProperty(kFdLeakEnableThresholdProperty, 1024);
+ const int abort_threshold = GetIntProperty(kFdLeakAbortThresholdProperty, 2048);
+ const int check_interval = GetIntProperty(kFdLeakCheckIntervalProperty, 120);
+ int max_fd = get_current_max_fd();
+ if (max_fd > enable_threshold && !loaded) {
+ loaded = true;
+ ALOGE("fd count above threshold of %d, starting fd backtraces", enable_threshold);
+ if (dlopen("libfdtrack.so", RTLD_GLOBAL) == nullptr) {
+ ALOGE("failed to load libfdtrack.so: %s", dlerror());
+ }
+ } else if (max_fd > abort_threshold) {
+ raise(BIONIC_SIGNAL_FDTRACK);
+
+ // Wait for a bit to allow fdtrack to dump backtraces to logcat.
+ std::this_thread::sleep_for(5s);
+
+ LOG_ALWAYS_FATAL(
+ "b/140703823: aborting due to fd leak: check logs for fd "
+ "backtraces");
+ }
+
+ std::this_thread::sleep_for(std::chrono::seconds(check_interval));
+ }
+ }).detach();
}
/*
@@ -80,6 +134,9 @@
{ "startHidlServices", "()V", (void*) android_server_SystemServer_startHidlServices },
{ "initZygoteChildHeapProfiling", "()V",
(void*) android_server_SystemServer_initZygoteChildHeapProfiling },
+ { "spawnFdLeakCheckThread", "()V",
+ (void*) android_server_SystemServer_spawnFdLeakCheckThread },
+
};
int register_android_server_SystemServer(JNIEnv* env)
diff --git a/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp b/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp
new file mode 100644
index 0000000..f5b778e
--- /dev/null
+++ b/services/core/jni/com_android_server_stats_pull_StatsPullAtomService.cpp
@@ -0,0 +1,73 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "StatsPullAtomService"
+
+#include <jni.h>
+#include <log/log.h>
+#include <nativehelper/JNIHelp.h>
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
+#include <statslog.h>
+
+#include "stats/PowerStatsPuller.h"
+#include "stats/SubsystemSleepStatePuller.h"
+
+namespace android {
+
+static server::stats::PowerStatsPuller gPowerStatsPuller;
+static server::stats::SubsystemSleepStatePuller gSubsystemSleepStatePuller;
+
+static status_pull_atom_return_t onDevicePowerMeasurementCallback(int32_t atom_tag,
+ pulled_stats_event_list* data,
+ void* cookie) {
+ return gPowerStatsPuller.Pull(atom_tag, data);
+}
+
+static status_pull_atom_return_t subsystemSleepStateCallback(int32_t atom_tag,
+ pulled_stats_event_list* data,
+ void* cookie) {
+ return gSubsystemSleepStatePuller.Pull(atom_tag, data);
+}
+
+static void nativeInit(JNIEnv* env, jobject javaObject) {
+ // on device power measurement
+ gPowerStatsPuller = server::stats::PowerStatsPuller();
+ register_stats_pull_atom_callback(android::util::ON_DEVICE_POWER_MEASUREMENT,
+ onDevicePowerMeasurementCallback,
+ /* metadata= */ nullptr,
+ /* cookie= */ nullptr);
+
+ // subsystem sleep state
+ gSubsystemSleepStatePuller = server::stats::SubsystemSleepStatePuller();
+ register_stats_pull_atom_callback(android::util::SUBSYSTEM_SLEEP_STATE,
+ subsystemSleepStateCallback,
+ /* metadata= */ nullptr,
+ /* cookie= */ nullptr);
+}
+
+static const JNINativeMethod sMethods[] = {{"nativeInit", "()V", (void*)nativeInit}};
+
+int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env) {
+ int res = jniRegisterNativeMethods(env, "com/android/server/stats/pull/StatsPullAtomService",
+ sMethods, NELEM(sMethods));
+ if (res < 0) {
+ ALOGE("failed to register native methods");
+ }
+ return res;
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index 19fa062..1202ad3 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -59,6 +59,7 @@
int register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
JNIEnv* env);
int register_android_server_incremental_IncrementalManagerService(JNIEnv* env);
+int register_android_server_stats_pull_StatsPullAtomService(JNIEnv* env);
};
using namespace android;
@@ -111,5 +112,6 @@
register_com_android_server_soundtrigger_middleware_AudioSessionProviderImpl(
env);
register_android_server_incremental_IncrementalManagerService(env);
+ register_android_server_stats_pull_StatsPullAtomService(env);
return JNI_VERSION_1_4;
}
diff --git a/services/core/jni/stats/OWNERS b/services/core/jni/stats/OWNERS
new file mode 100644
index 0000000..a61babf
--- /dev/null
+++ b/services/core/jni/stats/OWNERS
@@ -0,0 +1,9 @@
+jeffreyhuang@google.com
+joeo@google.com
+jtnguyen@google.com
+muhammadq@google.com
+ruchirr@google.com
+singhtejinder@google.com
+tsaichristine@google.com
+yaochen@google.com
+yro@google.com
diff --git a/services/core/jni/stats/PowerStatsPuller.cpp b/services/core/jni/stats/PowerStatsPuller.cpp
new file mode 100644
index 0000000..e80b5cfc
--- /dev/null
+++ b/services/core/jni/stats/PowerStatsPuller.cpp
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "PowerStatsPuller"
+
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+#include <log/log.h>
+#include <statslog.h>
+
+#include <vector>
+
+#include "PowerStatsPuller.h"
+
+using android::hardware::hidl_vec;
+using android::hardware::Return;
+using android::hardware::Void;
+using android::hardware::power::stats::V1_0::EnergyData;
+using android::hardware::power::stats::V1_0::IPowerStats;
+using android::hardware::power::stats::V1_0::RailInfo;
+using android::hardware::power::stats::V1_0::Status;
+
+namespace android {
+namespace server {
+namespace stats {
+
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHal = nullptr;
+static std::mutex gPowerStatsHalMutex;
+static bool gPowerStatsExist = true; // Initialized to ensure making a first attempt.
+static std::vector<RailInfo> gRailInfo;
+
+struct PowerStatsPullerDeathRecipient : virtual public hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<android::hidl::base::V1_0::IBase>& who) override {
+ // The HAL just died. Reset all handles to HAL services.
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+ gPowerStatsHal = nullptr;
+ }
+};
+
+static sp<PowerStatsPullerDeathRecipient> gDeathRecipient = new PowerStatsPullerDeathRecipient();
+
+static bool getPowerStatsHalLocked() {
+ if (gPowerStatsHal == nullptr && gPowerStatsExist) {
+ gPowerStatsHal = android::hardware::power::stats::V1_0::IPowerStats::getService();
+ if (gPowerStatsHal == nullptr) {
+ ALOGW("Couldn't load power.stats HAL service");
+ gPowerStatsExist = false;
+ } else {
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked = gPowerStatsHal->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ gPowerStatsHal = nullptr;
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ // We should still continue even though linking failed
+ }
+ }
+ }
+ return gPowerStatsHal != nullptr;
+}
+
+PowerStatsPuller::PowerStatsPuller() {}
+
+status_pull_atom_return_t PowerStatsPuller::Pull(int32_t atomTag, pulled_stats_event_list* data) {
+ std::lock_guard<std::mutex> lock(gPowerStatsHalMutex);
+
+ if (!getPowerStatsHalLocked()) {
+ return STATS_PULL_SKIP;
+ }
+
+ // Pull getRailInfo if necessary
+ if (gRailInfo.empty()) {
+ bool resultSuccess = true;
+ Return<void> ret = gPowerStatsHal->getRailInfo(
+ [&resultSuccess](const hidl_vec<RailInfo>& list, Status status) {
+ resultSuccess = (status == Status::SUCCESS || status == Status::NOT_SUPPORTED);
+ if (status != Status::SUCCESS) return;
+ gRailInfo.reserve(list.size());
+ for (size_t i = 0; i < list.size(); ++i) {
+ gRailInfo.push_back(list[i]);
+ }
+ });
+ if (!resultSuccess || !ret.isOk()) {
+ ALOGE("power.stats getRailInfo() failed. Description: %s", ret.description().c_str());
+ gPowerStatsHal = nullptr;
+ return STATS_PULL_SKIP;
+ }
+ // If SUCCESS but empty, or if NOT_SUPPORTED, then never try again.
+ if (gRailInfo.empty()) {
+ ALOGE("power.stats has no rail information");
+ gPowerStatsExist = false; // No rail info, so never try again.
+ gPowerStatsHal = nullptr;
+ return STATS_PULL_SKIP;
+ }
+ }
+
+ // Pull getEnergyData and write the data out
+ const hidl_vec<uint32_t> desiredRailIndices; // Empty vector indicates we want all.
+ bool resultSuccess = true;
+ Return<void> ret =
+ gPowerStatsHal
+ ->getEnergyData(desiredRailIndices,
+ [&data, &resultSuccess](hidl_vec<EnergyData> energyDataList,
+ Status status) {
+ resultSuccess = (status == Status::SUCCESS);
+ if (!resultSuccess) return;
+
+ for (size_t i = 0; i < energyDataList.size(); i++) {
+ const EnergyData& energyData = energyDataList[i];
+
+ if (energyData.index >= gRailInfo.size()) {
+ ALOGE("power.stats getEnergyData() returned an "
+ "invalid rail index %u.",
+ energyData.index);
+ resultSuccess = false;
+ return;
+ }
+ const RailInfo& rail = gRailInfo[energyData.index];
+
+ stats_event* event = add_stats_event_to_pull_data(data);
+ stats_event_set_atom_id(event,
+ android::util::ON_DEVICE_POWER_MEASUREMENT);
+ stats_event_write_string8(event,
+ rail.subsysName.c_str());
+ stats_event_write_string8(event, rail.railName.c_str());
+ stats_event_write_int64(event, energyData.timestamp);
+ stats_event_write_int64(event, energyData.energy);
+ stats_event_build(event);
+
+ ALOGV("power.stat: %s.%s: %llu, %llu",
+ rail.subsysName.c_str(), rail.railName.c_str(),
+ (unsigned long long)energyData.timestamp,
+ (unsigned long long)energyData.energy);
+ }
+ });
+ if (!resultSuccess || !ret.isOk()) {
+ ALOGE("power.stats getEnergyData() failed. Description: %s", ret.description().c_str());
+ gPowerStatsHal = nullptr;
+ return STATS_PULL_SKIP;
+ }
+ return STATS_PULL_SUCCESS;
+}
+
+} // namespace stats
+} // namespace server
+} // namespace android
diff --git a/cmds/statsd/src/external/PowerStatsPuller.h b/services/core/jni/stats/PowerStatsPuller.h
similarity index 72%
rename from cmds/statsd/src/external/PowerStatsPuller.h
rename to services/core/jni/stats/PowerStatsPuller.h
index 6f15bd6..048dbb9 100644
--- a/cmds/statsd/src/external/PowerStatsPuller.h
+++ b/services/core/jni/stats/PowerStatsPuller.h
@@ -16,23 +16,22 @@
#pragma once
-#include "StatsPuller.h"
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
namespace android {
-namespace os {
-namespace statsd {
+namespace server {
+namespace stats {
/**
* Reads hal for power.stats
*/
-class PowerStatsPuller : public StatsPuller {
+class PowerStatsPuller {
public:
PowerStatsPuller();
-
-private:
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+ status_pull_atom_return_t Pull(int32_t atomTag, pulled_stats_event_list* data);
};
-} // namespace statsd
-} // namespace os
-} // namespace android
+} // namespace stats
+} // namespace server
+} // namespace android
diff --git a/services/core/jni/stats/SubsystemSleepStatePuller.cpp b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
new file mode 100644
index 0000000..c6a836c
--- /dev/null
+++ b/services/core/jni/stats/SubsystemSleepStatePuller.cpp
@@ -0,0 +1,367 @@
+/*
+ * 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.
+ */
+
+#define DEBUG false // STOPSHIP if true
+#define LOG_TAG "SubsystemSleepStatePuller"
+
+#include <log/log.h>
+#include <statslog.h>
+
+#include <android/hardware/power/1.0/IPower.h>
+#include <android/hardware/power/1.1/IPower.h>
+#include <android/hardware/power/stats/1.0/IPowerStats.h>
+
+#include <fcntl.h>
+#include <hardware/power.h>
+#include <hardware_legacy/power.h>
+#include <inttypes.h>
+#include <semaphore.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <unordered_map>
+#include "SubsystemSleepStatePuller.h"
+
+using android::hardware::hidl_vec;
+using android::hardware::power::V1_0::IPower;
+using android::hardware::power::V1_0::PowerStatePlatformSleepState;
+using android::hardware::power::V1_0::PowerStateVoter;
+using android::hardware::power::V1_1::PowerStateSubsystem;
+using android::hardware::power::V1_1::PowerStateSubsystemSleepState;
+using android::hardware::power::stats::V1_0::PowerEntityInfo;
+using android::hardware::power::stats::V1_0::PowerEntityStateResidencyResult;
+using android::hardware::power::stats::V1_0::PowerEntityStateSpace;
+
+using android::hardware::Return;
+using android::hardware::Void;
+
+namespace android {
+namespace server {
+namespace stats {
+
+static std::function<status_pull_atom_return_t(int32_t atomTag, pulled_stats_event_list* data)>
+ gPuller = {};
+
+static sp<android::hardware::power::V1_0::IPower> gPowerHalV1_0 = nullptr;
+static sp<android::hardware::power::V1_1::IPower> gPowerHalV1_1 = nullptr;
+static sp<android::hardware::power::stats::V1_0::IPowerStats> gPowerStatsHalV1_0 = nullptr;
+
+static std::unordered_map<uint32_t, std::string> gEntityNames = {};
+static std::unordered_map<uint32_t, std::unordered_map<uint32_t, std::string>> gStateNames = {};
+
+static std::mutex gPowerHalMutex;
+
+// The caller must be holding gPowerHalMutex.
+static void deinitPowerStatsLocked() {
+ gPowerHalV1_0 = nullptr;
+ gPowerHalV1_1 = nullptr;
+ gPowerStatsHalV1_0 = nullptr;
+}
+
+struct SubsystemSleepStatePullerDeathRecipient : virtual public hardware::hidl_death_recipient {
+ virtual void serviceDied(uint64_t cookie,
+ const wp<android::hidl::base::V1_0::IBase>& who) override {
+
+ // The HAL just died. Reset all handles to HAL services.
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+ deinitPowerStatsLocked();
+ }
+};
+
+static sp<SubsystemSleepStatePullerDeathRecipient> gDeathRecipient =
+ new SubsystemSleepStatePullerDeathRecipient();
+
+SubsystemSleepStatePuller::SubsystemSleepStatePuller() {}
+
+// The caller must be holding gPowerHalMutex.
+static bool checkResultLocked(const Return<void> &ret, const char* function) {
+ if (!ret.isOk()) {
+ ALOGE("%s failed: requested HAL service not available. Description: %s",
+ function, ret.description().c_str());
+ if (ret.isDeadObject()) {
+ deinitPowerStatsLocked();
+ }
+ return false;
+ }
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+// gPowerStatsHalV1_0 must not be null
+static bool initializePowerStats() {
+ using android::hardware::power::stats::V1_0::Status;
+
+ // Clear out previous content if we are re-initializing
+ gEntityNames.clear();
+ gStateNames.clear();
+
+ Return<void> ret;
+ ret = gPowerStatsHalV1_0->getPowerEntityInfo([](auto infos, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting power entity info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId to power entity name
+ for (auto info : infos) {
+ gEntityNames.emplace(info.powerEntityId, info.powerEntityName);
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
+ ret = gPowerStatsHalV1_0->getPowerEntityStateInfo({}, [](auto stateSpaces, auto status) {
+ if (status != Status::SUCCESS) {
+ ALOGE("Error getting state info");
+ return;
+ }
+
+ // construct lookup table of powerEntityId, powerEntityStateId to power entity state name
+ for (auto stateSpace : stateSpaces) {
+ std::unordered_map<uint32_t, std::string> stateNames = {};
+ for (auto state : stateSpace.states) {
+ stateNames.emplace(state.powerEntityStateId,
+ state.powerEntityStateName);
+ }
+ gStateNames.emplace(stateSpace.powerEntityId, stateNames);
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return false;
+ }
+
+ return (!gEntityNames.empty()) && (!gStateNames.empty());
+}
+
+// The caller must be holding gPowerHalMutex.
+static bool getPowerStatsHalLocked() {
+ if(gPowerStatsHalV1_0 == nullptr) {
+ gPowerStatsHalV1_0 = android::hardware::power::stats::V1_0::IPowerStats::getService();
+ if (gPowerStatsHalV1_0 == nullptr) {
+ ALOGE("Unable to get power.stats HAL service.");
+ return false;
+ }
+
+ // Link death recipient to power.stats service handle
+ hardware::Return<bool> linked = gPowerStatsHalV1_0->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power.stats HAL death: %s",
+ linked.description().c_str());
+ deinitPowerStatsLocked();
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power.stats HAL death notifications");
+ // We should still continue even though linking failed
+ }
+ return initializePowerStats();
+ }
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+static status_pull_atom_return_t getIPowerStatsDataLocked(int32_t atomTag,
+ pulled_stats_event_list* data) {
+ using android::hardware::power::stats::V1_0::Status;
+
+ if(!getPowerStatsHalLocked()) {
+ return STATS_PULL_SKIP;
+ }
+ // Get power entity state residency data
+ bool success = false;
+ Return<void> ret = gPowerStatsHalV1_0->getPowerEntityStateResidencyData(
+ {}, [&data, &success](auto results, auto status) {
+ if (status == Status::NOT_SUPPORTED) {
+ ALOGW("getPowerEntityStateResidencyData is not supported");
+ success = false;
+ return;
+ }
+ for (auto result : results) {
+ for (auto stateResidency : result.stateResidencyData) {
+ stats_event* event = add_stats_event_to_pull_data(data);
+ stats_event_set_atom_id(event, android::util::SUBSYSTEM_SLEEP_STATE);
+ stats_event_write_string8(event,
+ gEntityNames.at(result.powerEntityId).c_str());
+ stats_event_write_string8(event,
+ gStateNames.at(result.powerEntityId)
+ .at(stateResidency.powerEntityStateId)
+ .c_str());
+ stats_event_write_int64(event, stateResidency.totalStateEntryCount);
+ stats_event_write_int64(event, stateResidency.totalTimeInStateMs);
+ stats_event_build(event);
+ }
+ }
+ success = true;
+ });
+ // Intentionally not returning early here.
+ // bool success determines if this succeeded or not.
+ checkResultLocked(ret, __func__);
+ if (!success) {
+ return STATS_PULL_SKIP;
+ }
+ return STATS_PULL_SUCCESS;
+}
+
+// The caller must be holding gPowerHalMutex.
+static bool getPowerHalLocked() {
+ if(gPowerHalV1_0 == nullptr) {
+ gPowerHalV1_0 = android::hardware::power::V1_0::IPower::getService();
+ if(gPowerHalV1_0 == nullptr) {
+ ALOGE("Unable to get power HAL service.");
+ return false;
+ }
+ gPowerHalV1_1 = android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+
+ // Link death recipient to power service handle
+ hardware::Return<bool> linked = gPowerHalV1_0->linkToDeath(gDeathRecipient, 0);
+ if (!linked.isOk()) {
+ ALOGE("Transaction error in linking to power HAL death: %s",
+ linked.description().c_str());
+ gPowerHalV1_0 = nullptr;
+ return false;
+ } else if (!linked) {
+ ALOGW("Unable to link to power. death notifications");
+ // We should still continue even though linking failed
+ }
+ }
+ return true;
+}
+
+// The caller must be holding gPowerHalMutex.
+static status_pull_atom_return_t getIPowerDataLocked(int32_t atomTag,
+ pulled_stats_event_list* data) {
+ using android::hardware::power::V1_0::Status;
+
+ if(!getPowerHalLocked()) {
+ return STATS_PULL_SKIP;
+ }
+
+ Return<void> ret;
+ ret = gPowerHalV1_0->getPlatformLowPowerStats(
+ [&data](hidl_vec<PowerStatePlatformSleepState> states, Status status) {
+ if (status != Status::SUCCESS) return;
+
+ for (size_t i = 0; i < states.size(); i++) {
+ const PowerStatePlatformSleepState& state = states[i];
+ stats_event* event = add_stats_event_to_pull_data(data);
+ stats_event_set_atom_id(event, android::util::SUBSYSTEM_SLEEP_STATE);
+ stats_event_write_string8(event, state.name.c_str());
+ stats_event_write_string8(event, "");
+ stats_event_write_int64(event, state.totalTransitions);
+ stats_event_write_int64(event, state.residencyInMsecSinceBoot);
+ stats_event_build(event);
+
+ ALOGV("powerstate: %s, %lld, %lld, %d", state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ state.supportedOnlyInSuspend ? 1 : 0);
+ for (const auto& voter : state.voters) {
+ stats_event* event = add_stats_event_to_pull_data(data);
+ stats_event_set_atom_id(event, android::util::SUBSYSTEM_SLEEP_STATE);
+ stats_event_write_string8(event, state.name.c_str());
+ stats_event_write_string8(event, voter.name.c_str());
+ stats_event_write_int64(event, voter.totalNumberOfTimesVotedSinceBoot);
+ stats_event_write_int64(event, voter.totalTimeInMsecVotedForSinceBoot);
+ stats_event_build(event);
+
+ ALOGV("powerstatevoter: %s, %s, %lld, %lld", state.name.c_str(),
+ voter.name.c_str(),
+ (long long)voter.totalTimeInMsecVotedForSinceBoot,
+ (long long)voter.totalNumberOfTimesVotedSinceBoot);
+ }
+ }
+ });
+ if (!checkResultLocked(ret, __func__)) {
+ return STATS_PULL_SKIP;
+ }
+
+ // Trying to cast to IPower 1.1, this will succeed only for devices supporting 1.1
+ sp<android::hardware::power::V1_1::IPower> gPowerHal_1_1 =
+ android::hardware::power::V1_1::IPower::castFrom(gPowerHalV1_0);
+ if (gPowerHal_1_1 != nullptr) {
+ ret = gPowerHal_1_1->getSubsystemLowPowerStats(
+ [&data](hidl_vec<PowerStateSubsystem> subsystems, Status status) {
+ if (status != Status::SUCCESS) return;
+
+ if (subsystems.size() > 0) {
+ for (size_t i = 0; i < subsystems.size(); i++) {
+ const PowerStateSubsystem& subsystem = subsystems[i];
+ for (size_t j = 0; j < subsystem.states.size(); j++) {
+ const PowerStateSubsystemSleepState& state =
+ subsystem.states[j];
+ stats_event* event = add_stats_event_to_pull_data(data);
+ stats_event_set_atom_id(event,
+ android::util::SUBSYSTEM_SLEEP_STATE);
+ stats_event_write_string8(event, subsystem.name.c_str());
+ stats_event_write_string8(event, state.name.c_str());
+ stats_event_write_int64(event, state.totalTransitions);
+ stats_event_write_int64(event, state.residencyInMsecSinceBoot);
+ stats_event_build(event);
+
+ ALOGV("subsystemstate: %s, %s, %lld, %lld, %lld",
+ subsystem.name.c_str(), state.name.c_str(),
+ (long long)state.residencyInMsecSinceBoot,
+ (long long)state.totalTransitions,
+ (long long)state.lastEntryTimestampMs);
+ }
+ }
+ }
+ });
+ }
+ return STATS_PULL_SUCCESS;
+}
+
+// The caller must be holding gPowerHalMutex.
+std::function<status_pull_atom_return_t(int32_t atomTag, pulled_stats_event_list* data)>
+getPullerLocked() {
+ std::function<status_pull_atom_return_t(int32_t atomTag, pulled_stats_event_list * data)> ret =
+ {};
+
+ // First see if power.stats HAL is available. Fall back to power HAL if
+ // power.stats HAL is unavailable.
+ if(android::hardware::power::stats::V1_0::IPowerStats::getService() != nullptr) {
+ ALOGI("Using power.stats HAL");
+ ret = getIPowerStatsDataLocked;
+ } else if(android::hardware::power::V1_0::IPower::getService() != nullptr) {
+ ALOGI("Using power HAL");
+ ret = getIPowerDataLocked;
+ }
+
+ return ret;
+}
+
+status_pull_atom_return_t SubsystemSleepStatePuller::Pull(int32_t atomTag,
+ pulled_stats_event_list* data) {
+ std::lock_guard<std::mutex> lock(gPowerHalMutex);
+
+ if(!gPuller) {
+ gPuller = getPullerLocked();
+ }
+
+ if(gPuller) {
+ return gPuller(atomTag, data);
+ }
+
+ ALOGE("Unable to load Power Hal or power.stats HAL");
+ return STATS_PULL_SKIP;
+}
+
+} // namespace stats
+} // namespace server
+} // namespace android
diff --git a/cmds/statsd/src/external/SubsystemSleepStatePuller.h b/services/core/jni/stats/SubsystemSleepStatePuller.h
similarity index 71%
rename from cmds/statsd/src/external/SubsystemSleepStatePuller.h
rename to services/core/jni/stats/SubsystemSleepStatePuller.h
index 87f5f02..59dbbd2 100644
--- a/cmds/statsd/src/external/SubsystemSleepStatePuller.h
+++ b/services/core/jni/stats/SubsystemSleepStatePuller.h
@@ -16,24 +16,22 @@
#pragma once
-#include <utils/String16.h>
-#include "StatsPuller.h"
+#include <stats_event.h>
+#include <stats_pull_atom_callback.h>
namespace android {
-namespace os {
-namespace statsd {
+namespace server {
+namespace stats {
/**
* Reads hal for sleep states
*/
-class SubsystemSleepStatePuller : public StatsPuller {
+class SubsystemSleepStatePuller {
public:
SubsystemSleepStatePuller();
-
-private:
- bool PullInternal(vector<std::shared_ptr<LogEvent>>* data) override;
+ status_pull_atom_return_t Pull(int32_t atomTag, pulled_stats_event_list* data);
};
-} // namespace statsd
-} // namespace os
-} // namespace android
+} // namespace stats
+} // namespace server
+} // namespace android
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index ec3ef78..65cabad 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -15077,9 +15077,16 @@
return packages;
}
- private List<String> getDefaultCrossProfilePackages() {
- return Arrays.asList(mContext.getResources()
+ @Override
+ public List<String> getDefaultCrossProfilePackages() {
+ Set<String> crossProfilePackages = new HashSet<>();
+
+ Collections.addAll(crossProfilePackages, mContext.getResources()
.getStringArray(R.array.cross_profile_apps));
+ Collections.addAll(crossProfilePackages, mContext.getResources()
+ .getStringArray(R.array.vendor_cross_profile_apps));
+
+ return new ArrayList<>(crossProfilePackages);
}
private List<ActiveAdmin> getProfileOwnerAdminsForCurrentProfileGroup() {
diff --git a/services/incremental/BinderIncrementalService.cpp b/services/incremental/BinderIncrementalService.cpp
index f1b637f..91d0572 100644
--- a/services/incremental/BinderIncrementalService.cpp
+++ b/services/incremental/BinderIncrementalService.cpp
@@ -111,10 +111,9 @@
binder::Status BinderIncrementalService::createStorage(const std::string& path,
const DataLoaderParamsParcel& params,
int32_t createMode, int32_t* _aidl_return) {
- *_aidl_return =
- mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params),
- android::incremental::IncrementalService::CreateOptions(
- createMode));
+ *_aidl_return = mImpl.createStorage(path, const_cast<DataLoaderParamsParcel&&>(params),
+ android::incremental::IncrementalService::CreateOptions(
+ createMode));
return ok();
}
@@ -195,7 +194,7 @@
return ok();
}
- *_aidl_return = mImpl.makeFile(storageId, path, 0555, fileId, nfp);
+ *_aidl_return = mImpl.makeFile(storageId, path, 0777, fileId, nfp);
return ok();
}
binder::Status BinderIncrementalService::makeFileFromRange(int32_t storageId,
diff --git a/services/incremental/IncrementalService.cpp b/services/incremental/IncrementalService.cpp
index 414c66c..e4a37dde 100644
--- a/services/incremental/IncrementalService.cpp
+++ b/services/incremental/IncrementalService.cpp
@@ -30,7 +30,6 @@
#include <binder/BinderService.h>
#include <binder/ParcelFileDescriptor.h>
#include <binder/Status.h>
-
#include <openssl/sha.h>
#include <sys/stat.h>
#include <uuid/uuid.h>
@@ -612,13 +611,18 @@
if (!ifs) {
return -EINVAL;
}
- auto normSource = path::normalize(source);
std::unique_lock l(ifs->lock);
const auto storageInfo = ifs->storages.find(storage);
if (storageInfo == ifs->storages.end()) {
return -EINVAL;
}
+ std::string normSource;
+ if (path::isAbsolute(source)) {
+ normSource = path::normalize(source);
+ } else {
+ normSource = path::normalize(path::join(storageInfo->second.name, source));
+ }
if (!path::startsWith(normSource, storageInfo->second.name)) {
return -EINVAL;
}
@@ -673,7 +677,20 @@
int IncrementalService::makeFile(StorageId storage, std::string_view path, int mode, FileId id,
incfs::NewFileParams params) {
if (auto ifs = getIfs(storage)) {
- auto err = mIncFs->makeFile(ifs->control, path, mode, id, params);
+ const auto storageInfo = ifs->storages.find(storage);
+ if (storageInfo == ifs->storages.end()) {
+ return -EINVAL;
+ }
+ std::string normPath;
+ if (path::isAbsolute(path)) {
+ normPath = path::normalize(path);
+ } else {
+ normPath = path::normalize(path::join(storageInfo->second.name, path));
+ }
+ if (!path::startsWith(normPath, storageInfo->second.name)) {
+ return -EINVAL;
+ }
+ auto err = mIncFs->makeFile(ifs->control, normPath, mode, id, params);
if (err) {
return err;
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4f5c1ab..6ba4330 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -72,7 +72,6 @@
import android.util.EventLog;
import android.util.Slog;
import android.util.StatsLog;
-import android.view.WindowManager;
import android.view.contentcapture.ContentCaptureManager;
import com.android.internal.R;
@@ -343,6 +342,7 @@
private static final String START_SENSOR_SERVICE = "StartSensorService";
private static final String START_HIDL_SERVICES = "StartHidlServices";
+ private static final String START_BLOB_STORE_SERVICE = "startBlobStoreManagerService";
private static final String SYSPROP_START_COUNT = "sys.system_server.start_count";
private static final String SYSPROP_START_ELAPSED = "sys.system_server.start_elapsed";
@@ -350,6 +350,7 @@
private Future<?> mSensorServiceStart;
private Future<?> mZygotePreload;
+ private Future<?> mBlobStoreServiceStart;
/**
* Start the sensor service. This is a blocking call and can take time.
@@ -366,6 +367,12 @@
*/
private static native void initZygoteChildHeapProfiling();
+
+ /**
+ * Spawn a thread that monitors for fd leaks.
+ */
+ private static native void spawnFdLeakCheckThread();
+
/**
* The main entry point from zygote.
*/
@@ -500,6 +507,11 @@
initZygoteChildHeapProfiling();
}
+ // Debug builds - spawn a thread to monitor for fd leaks.
+ if (Build.IS_DEBUGGABLE) {
+ spawnFdLeakCheckThread();
+ }
+
// Check whether we failed to shut down last time we tried.
// This call may not return.
performPendingShutdown();
@@ -1785,6 +1797,13 @@
t.traceEnd();
}
+ mBlobStoreServiceStart = SystemServerInitThreadPool.submit(() -> {
+ final TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
+ traceLog.traceBegin(START_BLOB_STORE_SERVICE);
+ mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
+ traceLog.traceEnd();
+ }, START_BLOB_STORE_SERVICE);
+
// Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
t.traceBegin("StartDreamManager");
mSystemServiceManager.startService(DreamManagerService.class);
@@ -2029,10 +2048,6 @@
mSystemServiceManager.startService(ClipboardService.class);
t.traceEnd();
- t.traceBegin("StartBlobStoreManagerService");
- mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
- t.traceEnd();
-
t.traceBegin("AppServiceManager");
mSystemServiceManager.startService(AppBindingService.Lifecycle.class);
t.traceEnd();
@@ -2083,8 +2098,7 @@
// propagate to it.
final Configuration config = wm.computeNewConfiguration(DEFAULT_DISPLAY);
DisplayMetrics metrics = new DisplayMetrics();
- WindowManager w = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
- w.getDefaultDisplay().getMetrics(metrics);
+ context.getDisplay().getMetrics(metrics);
context.getResources().updateConfiguration(config, metrics);
// The system context's theme may be configuration-dependent.
@@ -2151,6 +2165,9 @@
mSystemServiceManager.startService(APP_SEARCH_MANAGER_SERVICE_CLASS);
t.traceEnd();
+ ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
+ START_BLOB_STORE_SERVICE);
+
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/people/java/com/android/server/people/data/DataManager.java b/services/people/java/com/android/server/people/data/DataManager.java
index 13cce41..4212072 100644
--- a/services/people/java/com/android/server/people/data/DataManager.java
+++ b/services/people/java/com/android/server/people/data/DataManager.java
@@ -373,7 +373,7 @@
@WorkerThread
void queryUsageStatsService(@UserIdInt int userId, long currentTime, long lastQueryTime) {
UsageEvents usageEvents = mUsageStatsManagerInternal.queryEventsForUser(
- userId, lastQueryTime, currentTime, false);
+ userId, lastQueryTime, currentTime, false, false);
if (usageEvents == null) {
return;
}
diff --git a/services/tests/servicestests/Android.bp b/services/tests/servicestests/Android.bp
index f990810..8381205 100644
--- a/services/tests/servicestests/Android.bp
+++ b/services/tests/servicestests/Android.bp
@@ -46,6 +46,7 @@
"service-appsearch",
"service-jobscheduler",
"service-permission",
+ "service-blobstore",
// TODO: remove once Android migrates to JUnit 4.12,
// which provides assertThrows
"testng",
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index b7c9001..d2ddff3 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -66,8 +66,6 @@
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.SUSPEND_APPS"/>
<uses-permission android:name="android.permission.CONTROL_KEYGUARD"/>
- <uses-permission android:name="android.permission.READ_COMPAT_CHANGE_CONFIG"/>
- <uses-permission android:name="android.permission.LOG_COMPAT_CHANGE"/>
<uses-permission android:name="android.permission.MANAGE_BIND_INSTANT_SERVICE"/>
<uses-permission android:name="android.permission.CONTROL_DISPLAY_COLOR_TRANSFORMS" />
<uses-permission android:name="android.permission.READ_DEVICE_CONFIG" />
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index a4ceadb..9053234 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -89,9 +89,12 @@
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent);
mEvents.add(0, event.copy());
- assertThat(rawEvent, lastEventMatcher);
+ // LastEvent may not match if we're clearing the state
+ if (mLastEvent != null) {
+ MotionEventMatcher lastEventMatcher = new MotionEventMatcher(mLastEvent);
+ assertThat(rawEvent, lastEventMatcher);
+ }
}
@Override
@@ -126,6 +129,31 @@
}
@Test
+ public void upEventWhenInTwoFingerMove_clearsState() {
+ goFromStateClearTo(STATE_MOVING_2FINGERS);
+
+ send(upEvent());
+ assertState(STATE_CLEAR);
+ }
+
+ @Test
+ public void clearEventsWhenInTwoFingerMove_clearsStateAndSendsUp() {
+ goFromStateClearTo(STATE_MOVING_2FINGERS);
+
+ // Clear last event so we don't try to match against anything when cleanup events are sent
+ // for the clear
+ mLastEvent = null;
+ mTouchExplorer.clearEvents(InputDevice.SOURCE_TOUCHSCREEN);
+ assertState(STATE_CLEAR);
+ List<MotionEvent> events = getCapturedEvents();
+ assertCapturedEvents(
+ MotionEvent.ACTION_DOWN,
+ MotionEvent.ACTION_POINTER_DOWN,
+ MotionEvent.ACTION_POINTER_UP,
+ MotionEvent.ACTION_UP);
+ }
+
+ @Test
public void testTwoFingersDrag_shouldDraggingAndActionDown() {
goFromStateClearTo(STATE_DRAGGING_2FINGERS);
@@ -268,6 +296,12 @@
DEFAULT_Y, 0));
}
+ private MotionEvent upEvent() {
+ MotionEvent event = downEvent();
+ event.setAction(MotionEvent.ACTION_UP);
+ return event;
+ }
+
private MotionEvent pointerDownEvent() {
final int secondPointerId = 0x0100;
final int action = MotionEvent.ACTION_POINTER_DOWN | secondPointerId;
diff --git a/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
new file mode 100644
index 0000000..ff728e7
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/blob/BlobStoreManagerServiceTest.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 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.blob;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.app.blob.BlobHandle;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.Message;
+import android.os.UserHandle;
+import android.platform.test.annotations.Presubmit;
+import android.util.ArrayMap;
+import android.util.LongSparseArray;
+
+import androidx.test.InstrumentationRegistry;
+import androidx.test.filters.SmallTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import com.android.server.blob.BlobStoreManagerService.Injector;
+import com.android.server.blob.BlobStoreManagerService.SessionStateChangeListener;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.io.File;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+@Presubmit
+public class BlobStoreManagerServiceTest {
+ private Context mContext;
+ private Handler mHandler;
+ private BlobStoreManagerService mService;
+
+ private LongSparseArray<BlobStoreSession> mUserSessions;
+ private ArrayMap<BlobHandle, BlobMetadata> mUserBlobs;
+
+ private SessionStateChangeListener mStateChangeListener;
+
+ private static final String TEST_PKG1 = "com.example1";
+ private static final String TEST_PKG2 = "com.example2";
+ private static final String TEST_PKG3 = "com.example3";
+
+ private static final int TEST_UID1 = 10001;
+ private static final int TEST_UID2 = 10002;
+ private static final int TEST_UID3 = 10003;
+
+ @Before
+ public void setUp() {
+ // Share classloader to allow package private access.
+ System.setProperty("dexmaker.share_classloader", "true");
+
+ mContext = InstrumentationRegistry.getTargetContext();
+ mHandler = new TestHandler(Looper.getMainLooper());
+ mService = new BlobStoreManagerService(mContext, new TestInjector());
+ mUserSessions = new LongSparseArray<>();
+ mUserBlobs = new ArrayMap<>();
+
+ mService.addUserSessionsForTest(mUserSessions, UserHandle.myUserId());
+ mService.addUserBlobsForTest(mUserBlobs, UserHandle.myUserId());
+
+ mStateChangeListener = mService.new SessionStateChangeListener();
+ }
+
+ @Test
+ public void testHandlePackageRemoved() throws Exception {
+ // Setup sessions
+ final File sessionFile1 = mock(File.class);
+ final long sessionId1 = 11;
+ final BlobStoreSession session1 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
+ sessionId1, sessionFile1);
+ mUserSessions.append(sessionId1, session1);
+
+ final File sessionFile2 = mock(File.class);
+ final long sessionId2 = 25;
+ final BlobStoreSession session2 = createBlobStoreSessionMock(TEST_PKG2, TEST_UID2,
+ sessionId2, sessionFile2);
+ mUserSessions.append(sessionId2, session2);
+
+ final File sessionFile3 = mock(File.class);
+ final long sessionId3 = 37;
+ final BlobStoreSession session3 = createBlobStoreSessionMock(TEST_PKG3, TEST_UID3,
+ sessionId3, sessionFile3);
+ mUserSessions.append(sessionId3, session3);
+
+ final File sessionFile4 = mock(File.class);
+ final long sessionId4 = 48;
+ final BlobStoreSession session4 = createBlobStoreSessionMock(TEST_PKG1, TEST_UID1,
+ sessionId4, sessionFile4);
+ mUserSessions.append(sessionId4, session4);
+
+ // Setup blobs
+ final File blobFile1 = mock(File.class);
+ final BlobHandle blobHandle1 = BlobHandle.createWithSha256("digest1".getBytes(),
+ "label1", System.currentTimeMillis(), "tag1");
+ final BlobMetadata blobMetadata1 = createBlobMetadataMock(blobFile1, true);
+ mUserBlobs.put(blobHandle1, blobMetadata1);
+
+ final File blobFile2 = mock(File.class);
+ final BlobHandle blobHandle2 = BlobHandle.createWithSha256("digest2".getBytes(),
+ "label2", System.currentTimeMillis(), "tag2");
+ final BlobMetadata blobMetadata2 = createBlobMetadataMock(blobFile2, false);
+ mUserBlobs.put(blobHandle2, blobMetadata2);
+
+ // Invoke test method
+ mService.handlePackageRemoved(TEST_PKG1, TEST_UID1);
+
+ // Verify sessions are removed
+ verify(sessionFile1).delete();
+ verify(sessionFile2, never()).delete();
+ verify(sessionFile3, never()).delete();
+ verify(sessionFile4).delete();
+
+ assertThat(mUserSessions.size()).isEqualTo(2);
+ assertThat(mUserSessions.get(sessionId1)).isNull();
+ assertThat(mUserSessions.get(sessionId2)).isNotNull();
+ assertThat(mUserSessions.get(sessionId3)).isNotNull();
+ assertThat(mUserSessions.get(sessionId4)).isNull();
+
+ // Verify blobs are removed
+ verify(blobMetadata1).removeCommitter(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata1).removeLeasee(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata2).removeCommitter(TEST_PKG1, TEST_UID1);
+ verify(blobMetadata2).removeLeasee(TEST_PKG1, TEST_UID1);
+
+ verify(blobFile1, never()).delete();
+ verify(blobFile2).delete();
+
+ assertThat(mUserBlobs.size()).isEqualTo(1);
+ assertThat(mUserBlobs.get(blobHandle1)).isNotNull();
+ assertThat(mUserBlobs.get(blobHandle2)).isNull();
+ }
+
+ private BlobStoreSession createBlobStoreSessionMock(String ownerPackageName, int ownerUid,
+ long sessionId, File sessionFile) {
+ final BlobStoreSession session = mock(BlobStoreSession.class);
+ when(session.getOwnerPackageName()).thenReturn(ownerPackageName);
+ when(session.getOwnerUid()).thenReturn(ownerUid);
+ when(session.getSessionId()).thenReturn(sessionId);
+ when(session.getSessionFile()).thenReturn(sessionFile);
+ return session;
+ }
+
+ private BlobMetadata createBlobMetadataMock(File blobFile, boolean hasLeases) {
+ final BlobMetadata blobMetadata = mock(BlobMetadata.class);
+ when(blobMetadata.getBlobFile()).thenReturn(blobFile);
+ when(blobMetadata.hasLeases()).thenReturn(hasLeases);
+ return blobMetadata;
+ }
+
+ private class TestHandler extends Handler {
+ TestHandler(Looper looper) {
+ super(looper);
+ }
+
+ @Override
+ public void dispatchMessage(Message msg) {
+ // Ignore all messages
+ }
+ }
+
+ private class TestInjector extends Injector {
+ @Override
+ public Handler initializeMessageHandler() {
+ return mHandler;
+ }
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index f7a9e54..b193a34 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -5817,6 +5817,7 @@
mContext.packageName = admin1.getPackageName();
setCrossProfileAppsList();
+ setVendorCrossProfileAppsList();
assertTrue(dpm.getAllCrossProfilePackages().isEmpty());
}
@@ -5827,6 +5828,7 @@
mContext.packageName = admin1.getPackageName();
setCrossProfileAppsList();
+ setVendorCrossProfileAppsList();
initializeDpms();
assertTrue(dpm.getAllCrossProfilePackages().isEmpty());
@@ -5839,9 +5841,11 @@
dpm.setCrossProfilePackages(admin1, packages);
setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
+ setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");
assertEquals(Sets.newSet(
- "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"),
+ "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE",
+ "TEST_VENDOR_DEFAULT_PACKAGE"),
dpm.getAllCrossProfilePackages());
}
@@ -5854,13 +5858,31 @@
dpm.setCrossProfilePackages(admin1, packages);
setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
+ setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");
initializeDpms();
assertEquals(Sets.newSet(
- "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE"),
+ "TEST_PACKAGE", "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE",
+ "TEST_VENDOR_DEFAULT_PACKAGE"),
dpm.getAllCrossProfilePackages());
}
+ public void testGetDefaultCrossProfilePackages_noPackagesSet_returnsEmpty() {
+ setCrossProfileAppsList();
+ setVendorCrossProfileAppsList();
+
+ assertThat(dpm.getDefaultCrossProfilePackages()).isEmpty();
+ }
+
+ public void testGetDefaultCrossProfilePackages_packagesSet_returnsCombinedSet() {
+ setCrossProfileAppsList("TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE");
+ setVendorCrossProfileAppsList("TEST_VENDOR_DEFAULT_PACKAGE");
+
+ assertThat(dpm.getDefaultCrossProfilePackages()).isEqualTo(Sets.newSet(
+ "TEST_DEFAULT_PACKAGE", "TEST_COMMON_PACKAGE", "TEST_VENDOR_DEFAULT_PACKAGE"
+ ));
+ }
+
public void testSetCommonCriteriaMode_asDeviceOwner() throws Exception {
setDeviceOwner();
@@ -5892,6 +5914,12 @@
.thenReturn(packages);
}
+ private void setVendorCrossProfileAppsList(String... packages) {
+ when(mContext.getResources()
+ .getStringArray(eq(R.array.vendor_cross_profile_apps)))
+ .thenReturn(packages);
+ }
+
// admin1 is the outgoing DPC, adminAnotherPakcage is the incoming one.
private void assertDeviceOwnershipRevertedWithFakeTransferMetadata() throws Exception {
writeFakeTransferMetadataFile(UserHandle.USER_SYSTEM,
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
index 271e8e2..1ff451b 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/LockSettingsServiceTestable.java
@@ -147,6 +147,12 @@
public RecoverableKeyStoreManager getRecoverableKeyStoreManager(KeyStore keyStore) {
return mRecoverableKeyStoreManager;
}
+
+ @Override
+ public ManagedProfilePasswordCache getManagedProfilePasswordCache() {
+ return mock(ManagedProfilePasswordCache.class);
+ }
+
}
public MockInjector mInjector;
diff --git a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
index 9f3d656..91da761 100644
--- a/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/people/data/DataManagerTest.java
@@ -332,7 +332,7 @@
events.add(e);
UsageEvents usageEvents = new UsageEvents(events, new String[]{});
when(mUsageStatsManagerInternal.queryEventsForUser(anyInt(), anyLong(), anyLong(),
- anyBoolean())).thenReturn(usageEvents);
+ anyBoolean(), anyBoolean())).thenReturn(usageEvents);
mDataManager.onUserUnlocked(USER_ID_PRIMARY);
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index d22502d..4532400 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -16,9 +16,6 @@
package com.android.server.wm;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
-import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
-
import static com.android.dx.mockito.inline.extended.ExtendedMockito.any;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
@@ -27,17 +24,14 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
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.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.when;
import android.app.Activity;
-import android.app.ActivityManager;
import android.app.PictureInPictureParams;
import android.app.servertransaction.ClientTransaction;
import android.app.servertransaction.EnterPipRequestedItem;
@@ -46,7 +40,6 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.view.IDisplayWindowListener;
-import android.view.WindowContainerTransaction;
import androidx.test.filters.MediumTest;
@@ -126,47 +119,6 @@
}
@Test
- public void testTaskTransaction() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
- WindowContainerTransaction t = new WindowContainerTransaction();
- Rect newBounds = new Rect(10, 10, 100, 100);
- t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
- mService.applyContainerTransaction(t);
- assertEquals(newBounds, task.getBounds());
- }
-
- @Test
- public void testStackTransaction() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- ActivityManager.StackInfo info =
- mService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
- WindowContainerTransaction t = new WindowContainerTransaction();
- assertEquals(stack.mRemoteToken, info.stackToken);
- Rect newBounds = new Rect(10, 10, 100, 100);
- t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
- mService.applyContainerTransaction(t);
- assertEquals(newBounds, stack.getBounds());
- }
-
- @Test
- public void testContainerChanges() {
- removeGlobalMinSizeRestriction();
- final ActivityStack stack = new StackBuilder(mRootWindowContainer)
- .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
- final Task task = stack.getTopMostTask();
- WindowContainerTransaction t = new WindowContainerTransaction();
- assertTrue(task.isFocusable());
- t.setFocusable(stack.mRemoteToken, false);
- mService.applyContainerTransaction(t);
- assertFalse(task.isFocusable());
- }
-
- @Test
public void testDisplayWindowListener() {
final ArrayList<Integer> added = new ArrayList<>();
final ArrayList<Integer> changed = new ArrayList<>();
diff --git a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
index 71390db..0f54895 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AnimatingActivityRegistryTest.java
@@ -21,6 +21,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
import static org.junit.Assert.assertFalse;
@@ -69,8 +70,10 @@
final AnimatingActivityRegistry registry =
activity1.getStack().getAnimatingActivityRegistry();
- activity1.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */);
- activity2.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */);
+ activity1.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
+ activity2.startAnimation(activity1.getPendingTransaction(), mAdapter, false /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
assertTrue(activity1.isAnimating(TRANSITION));
assertTrue(activity2.isAnimating(TRANSITION));
@@ -91,8 +94,10 @@
final AnimatingActivityRegistry registry =
window1.getStack().getAnimatingActivityRegistry();
- window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
- window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */);
+ window1.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
+ window2.startAnimation(window1.getPendingTransaction(), mAdapter, false /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
assertTrue(window1.isAnimating(TRANSITION));
assertTrue(window2.isAnimating(TRANSITION));
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
index b0f3b42..6e78a27 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppWindowTokenAnimationTests.java
@@ -20,6 +20,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.google.common.truth.Truth.assertThat;
@@ -70,7 +71,8 @@
public void clipAfterAnim_boundsLayerIsCreated() {
mActivity.mNeedsAnimationBoundsLayer = true;
- mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()),
eq(mActivity.mSurfaceAnimator.mLeash));
verify(mTransaction).reparent(eq(mActivity.mSurfaceAnimator.mLeash),
@@ -82,7 +84,8 @@
mActivity.mNeedsAnimationBoundsLayer = true;
mActivity.mNeedsZBoost = true;
- mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
verify(mTransaction).setLayer(eq(mActivity.mAnimationBoundsLayer),
intThat(layer -> layer >= ActivityRecord.Z_BOOST_BASE));
}
@@ -91,15 +94,18 @@
@FlakyTest(bugId = 131005232)
public void clipAfterAnim_boundsLayerIsDestroyed() {
mActivity.mNeedsAnimationBoundsLayer = true;
- mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash;
final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer;
final ArgumentCaptor<SurfaceAnimator.OnAnimationFinishedCallback> callbackCaptor =
ArgumentCaptor.forClass(
SurfaceAnimator.OnAnimationFinishedCallback.class);
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+ verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
+ callbackCaptor.capture());
- callbackCaptor.getValue().onAnimationFinished(mSpec);
+ callbackCaptor.getValue().onAnimationFinished(
+ ANIMATION_TYPE_APP_TRANSITION, mSpec);
verify(mTransaction).remove(eq(leash));
verify(mTransaction).remove(eq(animationBoundsLayer));
assertThat(mActivity.mNeedsAnimationBoundsLayer).isFalse();
@@ -108,7 +114,8 @@
@Test
public void clipAfterAnimCancelled_boundsLayerIsDestroyed() {
mActivity.mNeedsAnimationBoundsLayer = true;
- mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
final SurfaceControl leash = mActivity.mSurfaceAnimator.mLeash;
final SurfaceControl animationBoundsLayer = mActivity.mAnimationBoundsLayer;
@@ -123,7 +130,8 @@
public void clipNoneAnim_boundsLayerIsNotCreated() {
mActivity.mNeedsAnimationBoundsLayer = false;
- mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mActivity.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
verify(mTransaction).reparent(eq(mActivity.getSurfaceControl()),
eq(mActivity.mSurfaceAnimator.mLeash));
assertThat(mActivity.mAnimationBoundsLayer).isNull();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
index 7344fa4..77ceeed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DimmerTests.java
@@ -22,11 +22,13 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spy;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_DIMMER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.when;
@@ -37,6 +39,9 @@
import android.view.SurfaceControl;
import android.view.SurfaceSession;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -114,11 +119,11 @@
private static class SurfaceAnimatorStarterImpl implements Dimmer.SurfaceAnimatorStarter {
@Override
public void startAnimation(SurfaceAnimator surfaceAnimator, SurfaceControl.Transaction t,
- AnimationAdapter anim, boolean hidden,
- @Nullable Runnable animationFinishedCallback) {
- surfaceAnimator.mStaticAnimationFinishedCallback.run();
+ AnimationAdapter anim, boolean hidden, @AnimationType int type,
+ @Nullable OnAnimationFinishedCallback animationFinishedCallback) {
+ surfaceAnimator.mStaticAnimationFinishedCallback.onAnimationFinished(type, anim);
if (animationFinishedCallback != null) {
- animationFinishedCallback.run();
+ animationFinishedCallback.onAnimationFinished(type, anim);
}
}
}
@@ -224,7 +229,7 @@
mDimmer.updateDims(mTransaction, new Rect());
verify(mSurfaceAnimatorStarter).startAnimation(any(SurfaceAnimator.class), any(
SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
- isNull());
+ eq(ANIMATION_TYPE_DIMMER), isNull());
verify(mHost.getPendingTransaction()).remove(dimLayer);
}
@@ -282,7 +287,7 @@
mDimmer.updateDims(mTransaction, new Rect());
verify(mSurfaceAnimatorStarter, never()).startAnimation(any(SurfaceAnimator.class), any(
SurfaceControl.Transaction.class), any(AnimationAdapter.class), anyBoolean(),
- isNull());
+ eq(ANIMATION_TYPE_DIMMER), isNull());
verify(mTransaction).remove(dimLayer);
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
new file mode 100644
index 0000000..618e608
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+
+import static com.android.server.wm.DisplayArea.Type.ABOVE_TASKS;
+import static com.android.server.wm.DisplayArea.Type.ANY;
+import static com.android.server.wm.DisplayArea.Type.BELOW_TASKS;
+import static com.android.server.wm.DisplayArea.Type.checkChild;
+import static com.android.server.wm.DisplayArea.Type.checkSiblings;
+import static com.android.server.wm.DisplayArea.Type.typeOf;
+import static com.android.server.wm.testing.Assert.assertThrows;
+
+import static org.junit.Assert.assertEquals;
+import static org.mockito.Mockito.mock;
+
+import android.os.Binder;
+import android.platform.test.annotations.Presubmit;
+import android.view.SurfaceControl;
+
+import org.junit.Rule;
+import org.junit.Test;
+
+@Presubmit
+public class DisplayAreaTest {
+
+ @Rule
+ public SystemServicesTestRule mWmsRule = new SystemServicesTestRule();
+
+ @Test
+ public void testDisplayArea_positionChanged_throwsIfIncompatibleChild() {
+ WindowManagerService wms = mWmsRule.getWindowManagerService();
+ DisplayArea<WindowContainer> parent = new DisplayArea<>(wms, BELOW_TASKS, "Parent");
+ DisplayArea<WindowContainer> child = new DisplayArea<>(wms, ANY, "Child");
+
+ assertThrows(IllegalStateException.class, () -> parent.addChild(child, 0));
+ }
+
+ @Test
+ public void testDisplayArea_positionChanged_throwsIfIncompatibleSibling() {
+ WindowManagerService wms = mWmsRule.getWindowManagerService();
+ DisplayArea<WindowContainer> parent = new SurfacelessDisplayArea<>(wms, ANY, "Parent");
+ DisplayArea<WindowContainer> child1 = new DisplayArea<>(wms, ANY, "Child1");
+ DisplayArea<WindowContainer> child2 = new DisplayArea<>(wms, ANY, "Child2");
+
+ parent.addChild(child1, 0);
+ assertThrows(IllegalStateException.class, () -> parent.addChild(child2, 0));
+ }
+
+ @Test
+ public void testType_typeOf() {
+ WindowManagerService wms = mWmsRule.getWindowManagerService();
+
+ assertEquals(ABOVE_TASKS, typeOf(new DisplayArea<>(wms, ABOVE_TASKS, "test")));
+ assertEquals(ANY, typeOf(new DisplayArea<>(wms, ANY, "test")));
+ assertEquals(BELOW_TASKS, typeOf(new DisplayArea<>(wms, BELOW_TASKS, "test")));
+
+ assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_APPLICATION_OVERLAY)));
+ assertEquals(ABOVE_TASKS, typeOf(createWindowToken(TYPE_PRESENTATION)));
+ assertEquals(BELOW_TASKS, typeOf(createWindowToken(TYPE_WALLPAPER)));
+
+ assertThrows(IllegalArgumentException.class, () -> typeOf(mock(ActivityRecord.class)));
+ assertThrows(IllegalArgumentException.class, () -> typeOf(mock(WindowContainer.class)));
+ }
+
+ @Test
+ public void testType_checkSiblings() {
+ checkSiblings(BELOW_TASKS, BELOW_TASKS);
+ checkSiblings(BELOW_TASKS, ANY);
+ checkSiblings(BELOW_TASKS, ABOVE_TASKS);
+ checkSiblings(ANY, ABOVE_TASKS);
+ checkSiblings(ABOVE_TASKS, ABOVE_TASKS);
+
+ assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, BELOW_TASKS));
+ assertThrows(IllegalStateException.class, () -> checkSiblings(ABOVE_TASKS, ANY));
+ assertThrows(IllegalStateException.class, () -> checkSiblings(ANY, ANY));
+ assertThrows(IllegalStateException.class, () -> checkSiblings(ANY, BELOW_TASKS));
+ }
+
+ @Test
+ public void testType_checkChild() {
+ checkChild(ANY, ANY);
+ checkChild(ANY, ABOVE_TASKS);
+ checkChild(ANY, BELOW_TASKS);
+ checkChild(ABOVE_TASKS, ABOVE_TASKS);
+ checkChild(BELOW_TASKS, BELOW_TASKS);
+
+ assertThrows(IllegalStateException.class, () -> checkChild(ABOVE_TASKS, BELOW_TASKS));
+ assertThrows(IllegalStateException.class, () -> checkChild(ABOVE_TASKS, ANY));
+ assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ABOVE_TASKS));
+ assertThrows(IllegalStateException.class, () -> checkChild(BELOW_TASKS, ANY));
+ }
+
+ private WindowToken createWindowToken(int type) {
+ return new WindowToken(mWmsRule.getWindowManagerService(), new Binder(),
+ type, false /* persist */, null /* displayContent */,
+ false /* canManageTokens */);
+ }
+
+ private static class SurfacelessDisplayArea<T extends WindowContainer> extends DisplayArea<T> {
+
+ SurfacelessDisplayArea(WindowManagerService wms, Type type, String name) {
+ super(wms, type, name);
+ }
+
+ @Override
+ SurfaceControl.Builder makeChildSurface(WindowContainer child) {
+ return new MockSurfaceControlBuilder();
+ }
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 1637370..2ea00ce 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -139,11 +139,11 @@
mAppWindow,
mChildAppWindowAbove,
mDockedDividerWindow,
+ mImeWindow,
+ mImeDialogWindow,
mStatusBarWindow,
mNotificationShadeWindow,
- mNavBarWindow,
- mImeWindow,
- mImeDialogWindow));
+ mNavBarWindow));
}
@Test
@@ -232,11 +232,11 @@
mChildAppWindowAbove,
mDockedDividerWindow,
voiceInteractionWindow,
+ mImeWindow,
+ mImeDialogWindow,
mStatusBarWindow,
mNotificationShadeWindow,
- mNavBarWindow,
- mImeWindow,
- mImeDialogWindow));
+ mNavBarWindow));
}
@Test
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
index 5ba676d..9dbaa4c 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyLayoutTests.java
@@ -73,6 +73,9 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+
/**
* Tests for the {@link DisplayPolicy} class.
*
@@ -122,9 +125,13 @@
}
private void updateDisplayFrames() {
+ mFrames = createDisplayFrames();
+ }
+
+ private DisplayFrames createDisplayFrames() {
final Pair<DisplayInfo, WmDisplayCutout> info = displayInfoAndCutoutForRotation(mRotation,
mHasDisplayCutout);
- mFrames = new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
+ return new DisplayFrames(mDisplayContent.getDisplayId(), info.first, info.second);
}
@Test
@@ -824,6 +831,49 @@
assertThat(outDisplayCutout, is(new DisplayCutout.ParcelableWrapper()));
}
+ /**
+ * Verify that {@link DisplayPolicy#simulateLayoutDisplay} outputs the same display frames as
+ * {@link DisplayPolicy#beginLayoutLw}.
+ */
+ @Test
+ public void testSimulateLayoutDisplay() {
+ assertSimulateLayoutSameDisplayFrames();
+ setRotation(ROTATION_90);
+ assertSimulateLayoutSameDisplayFrames();
+ addDisplayCutout();
+ assertSimulateLayoutSameDisplayFrames();
+ }
+
+ private void assertSimulateLayoutSameDisplayFrames() {
+ final int uiMode = 0;
+ final String prefix = "";
+ final InsetsState simulatedInsetsState = new InsetsState();
+ final DisplayFrames simulatedDisplayFrames = createDisplayFrames();
+ mDisplayContent.mDisplayFrames = mFrames;
+ mDisplayPolicy.beginLayoutLw(mFrames, uiMode);
+ mDisplayContent.getInsetsStateController().onPostLayout();
+ mDisplayPolicy.simulateLayoutDisplay(simulatedDisplayFrames, simulatedInsetsState, uiMode);
+
+ final StringWriter realFramesDump = new StringWriter();
+ mFrames.dump(prefix, new PrintWriter(realFramesDump));
+ final StringWriter simulatedFramesDump = new StringWriter();
+ simulatedDisplayFrames.dump(prefix, new PrintWriter(simulatedFramesDump));
+
+ assertEquals(realFramesDump.toString(), simulatedFramesDump.toString());
+
+ final StringWriter realInsetsDump = new StringWriter();
+ final InsetsState realInsetsState = new InsetsState(
+ mDisplayContent.getInsetsStateController().getRawInsetsState());
+ // Exclude comparing IME insets because currently the simulated layout only focuses on the
+ // insets from status bar and navigation bar.
+ realInsetsState.removeSource(InsetsState.ITYPE_IME);
+ realInsetsState.dump(prefix, new PrintWriter(realInsetsDump));
+ final StringWriter simulatedInsetsDump = new StringWriter();
+ simulatedInsetsState.dump(prefix, new PrintWriter(simulatedInsetsDump));
+
+ assertEquals(realInsetsDump.toString(), simulatedInsetsDump.toString());
+ }
+
@Test
public void forceShowSystemBars_clearsSystemUIFlags() {
mDisplayPolicy.mLastSystemUiFlags |= SYSTEM_UI_FLAG_FULLSCREEN;
diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
index 945928d..7753a32 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RecentsAnimationControllerTest.java
@@ -37,6 +37,7 @@
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -103,14 +104,15 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
AnimationAdapter adapter = mController.addAnimation(activity.getTask(),
false /* isRecentTaskInvisible */);
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS,
+ mFinishedCallback);
// Remove the app window so that the animation target can not be created
activity.removeImmediately();
mController.startAnimation();
// Verify that the finish callback to reparent the leash is called
- verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_RECENTS), eq(adapter));
// Verify the animation canceled callback to the app was made
verify(mMockRunner).onAnimationCanceled(null /* taskSnapshot */);
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
@@ -122,7 +124,8 @@
WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
AnimationAdapter adapter = mController.addAnimation(activity.getTask(),
false /* isRecentTaskInvisible */);
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_RECENTS,
+ mFinishedCallback);
// Remove the app window so that the animation target can not be created
activity.removeImmediately();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
index a23425f..be25597 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RefreshRatePolicyTest.java
@@ -18,6 +18,8 @@
import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+
import static org.junit.Assert.assertEquals;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
@@ -108,7 +110,7 @@
overrideWindow.mAttrs.preferredDisplayModeId = LOW_MODE_ID;
overrideWindow.mActivityRecord.mSurfaceAnimator.startAnimation(
overrideWindow.getPendingTransaction(), mock(AnimationAdapter.class),
- false /* hidden */);
+ false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
mPolicy.addNonHighRefreshRatePackage("com.android.test");
assertEquals(0, mPolicy.getPreferredModeId(overrideWindow));
}
@@ -124,7 +126,7 @@
cameraUsingWindow.mActivityRecord.mSurfaceAnimator.startAnimation(
cameraUsingWindow.getPendingTransaction(), mock(AnimationAdapter.class),
- false /* hidden */);
+ false /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
assertEquals(0, mPolicy.getPreferredModeId(cameraUsingWindow));
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
index 1a57596..3a724a1 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RemoteAnimationControllerTest.java
@@ -25,6 +25,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyNoMoreInteractions;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
@@ -97,7 +99,8 @@
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
@@ -122,7 +125,8 @@
verify(mMockTransaction).setWindowCrop(mMockLeash, 100, 50);
finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+ eq(adapter));
} finally {
mDisplayContent.mOpeningApps.clear();
}
@@ -133,7 +137,8 @@
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
adapter.onAnimationCancelled(mMockLeash);
@@ -146,14 +151,16 @@
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mClock.fastForward(2500);
mHandler.timeAdvance();
verify(mMockRunner).onAnimationCancelled();
- verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+ eq(adapter));
}
@Test
@@ -164,7 +171,8 @@
"testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(
win.mActivityRecord, new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mClock.fastForward(2500);
@@ -176,7 +184,8 @@
mHandler.timeAdvance();
verify(mMockRunner).onAnimationCancelled();
- verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+ eq(adapter));
} finally {
mWm.setAnimationScale(2, 1.0f);
}
@@ -205,7 +214,8 @@
new Point(50, 100), new Rect(50, 100, 150, 150), null);
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win2.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
@@ -225,11 +235,13 @@
final WindowState win = createWindow(null /* parent */, TYPE_BASE_APPLICATION, "testWin");
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
win.mActivityRecord.removeImmediately();
mController.goodToGo();
verifyNoMoreInteractionsExceptAsBinder(mMockRunner);
- verify(mFinishedCallback).onAnimationFinished(eq(adapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION),
+ eq(adapter));
}
@Test
@@ -242,9 +254,10 @@
new Rect(0, 0, 200, 200));
assertNotNull(record.mThumbnailAdapter);
((AnimationAdapter) record.mAdapter)
- .startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ .startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION,
+ mFinishedCallback);
((AnimationAdapter) record.mThumbnailAdapter).startAnimation(mMockThumbnailLeash,
- mMockTransaction, mThumbnailFinishedCallback);
+ mMockTransaction, ANIMATION_TYPE_WINDOW_ANIMATION, mThumbnailFinishedCallback);
mController.goodToGo();
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
@@ -272,8 +285,10 @@
verify(mMockTransaction).setPosition(mMockThumbnailLeash, 0, 0);
finishedCaptor.getValue().onAnimationFinished();
- verify(mFinishedCallback).onAnimationFinished(eq(record.mAdapter));
- verify(mThumbnailFinishedCallback).onAnimationFinished(eq(record.mThumbnailAdapter));
+ verify(mFinishedCallback).onAnimationFinished(eq(ANIMATION_TYPE_WINDOW_ANIMATION),
+ eq(record.mAdapter));
+ verify(mThumbnailFinishedCallback).onAnimationFinished(
+ eq(ANIMATION_TYPE_WINDOW_ANIMATION), eq(record.mThumbnailAdapter));
} finally {
mDisplayContent.mChangingApps.clear();
}
@@ -290,7 +305,8 @@
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
@@ -318,7 +334,8 @@
try {
final AnimationAdapter adapter = mController.createRemoteAnimationRecord(win.mActivityRecord,
new Point(50, 100), new Rect(50, 100, 150, 150), null).mAdapter;
- adapter.startAnimation(mMockLeash, mMockTransaction, mFinishedCallback);
+ adapter.startAnimation(mMockLeash, mMockTransaction, ANIMATION_TYPE_APP_TRANSITION,
+ mFinishedCallback);
mController.goodToGo();
mWm.mAnimator.executeAfterPrepareSurfacesRunnables();
final ArgumentCaptor<RemoteAnimationTarget[]> appsCaptor =
diff --git a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
index 2894241..552c476 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SurfaceAnimatorTest.java
@@ -22,6 +22,8 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verifyZeroInteractions;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_RECENTS;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -39,6 +41,7 @@
import androidx.test.filters.SmallTest;
import com.android.server.wm.SurfaceAnimator.Animatable;
+import com.android.server.wm.SurfaceAnimator.AnimationType;
import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
import org.junit.After;
@@ -89,25 +92,30 @@
@Test
public void testRunAnimation() {
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_RECENTS);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
assertAnimating(mAnimatable);
verify(mTransaction).reparent(eq(mAnimatable.mSurface), eq(mAnimatable.mLeash));
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+ verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_RECENTS),
+ callbackCaptor.capture());
- callbackCaptor.getValue().onAnimationFinished(mSpec);
+ callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_RECENTS, mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_RECENTS, mAnimatable.mFinishedAnimationType);
verify(mTransaction).remove(eq(mAnimatable.mLeash));
// TODO: Verify reparenting once we use mPendingTransaction to reparent it back
}
@Test
public void testOverrideAnimation() {
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
final SurfaceControl firstLeash = mAnimatable.mLeash;
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec2, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
verify(mTransaction).remove(eq(firstLeash));
assertFalse(mAnimatable.mFinishedCallbackCalled);
@@ -115,34 +123,40 @@
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
assertAnimating(mAnimatable);
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+ verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
+ callbackCaptor.capture());
// First animation was finished, but this shouldn't cancel the second animation
- callbackCaptor.getValue().onAnimationFinished(mSpec);
+ callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec);
assertTrue(mAnimatable.mSurfaceAnimator.isAnimating());
// Second animation was finished
- verify(mSpec2).startAnimation(any(), any(), callbackCaptor.capture());
- callbackCaptor.getValue().onAnimationFinished(mSpec2);
+ verify(mSpec2).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
+ callbackCaptor.capture());
+ callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec2);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType);
}
@Test
public void testCancelAnimation() {
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
assertAnimating(mAnimatable);
mAnimatable.mSurfaceAnimator.cancelAnimation();
assertNotAnimating(mAnimatable);
verify(mSpec).onAnimationCancelled(any());
assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType);
verify(mTransaction).remove(eq(mAnimatable.mLeash));
}
@Test
public void testCancelWithNullFinishCallbackAnimation() {
SurfaceAnimator animator = new SurfaceAnimator(mAnimatable, null, mWm);
- animator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ animator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
assertTrue(animator.isAnimating());
assertNotNull(animator.getAnimation());
animator.cancelAnimation();
@@ -155,32 +169,37 @@
@Test
public void testDelayingAnimationStart() {
mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
verifyZeroInteractions(mSpec);
assertAnimating(mAnimatable);
assertTrue(mAnimatable.mSurfaceAnimator.isAnimationStartDelayed());
mAnimatable.mSurfaceAnimator.endDelayingAnimationStart();
- verify(mSpec).startAnimation(any(), any(), any());
+ verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION), any());
}
@Test
public void testDelayingAnimationStartAndCancelled() {
mAnimatable.mSurfaceAnimator.startDelayingAnimationStart();
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
mAnimatable.mSurfaceAnimator.cancelAnimation();
verifyZeroInteractions(mSpec);
assertNotAnimating(mAnimatable);
assertTrue(mAnimatable.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType);
verify(mTransaction).remove(eq(mAnimatable.mLeash));
}
@Test
public void testTransferAnimation() {
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
- verify(mSpec).startAnimation(any(), any(), callbackCaptor.capture());
+ verify(mSpec).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
+ callbackCaptor.capture());
final SurfaceControl leash = mAnimatable.mLeash;
mAnimatable2.mSurfaceAnimator.transferAnimation(mAnimatable.mSurfaceAnimator);
@@ -188,15 +207,17 @@
assertAnimating(mAnimatable2);
assertEquals(leash, mAnimatable2.mSurfaceAnimator.mLeash);
verify(mTransaction, never()).remove(eq(leash));
- callbackCaptor.getValue().onAnimationFinished(mSpec);
+ callbackCaptor.getValue().onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec);
assertNotAnimating(mAnimatable2);
assertTrue(mAnimatable2.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_APP_TRANSITION, mAnimatable.mFinishedAnimationType);
verify(mTransaction).remove(eq(leash));
}
@Test
public void testOnAnimationLeashLostWhenAnimatableParentSurfaceControlNull() {
- mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */);
+ mAnimatable.mSurfaceAnimator.startAnimation(mTransaction, mSpec, true /* hidden */,
+ ANIMATION_TYPE_APP_TRANSITION);
spyOn(mAnimatable);
// Verify onAnimationLeashLost will be called even animatable's parent surface control lost.
@@ -215,13 +236,14 @@
final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
// Finish the animation but then make sure we are deferring.
- onFinishedCallback.onAnimationFinished(mSpec);
+ onFinishedCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec);
assertAnimating(mDeferFinishAnimatable);
// Now end defer finishing.
mDeferFinishAnimatable.mEndDeferFinishCallback.run();
assertNotAnimating(mAnimatable2);
assertTrue(mDeferFinishAnimatable.mFinishedCallbackCalled);
+ assertEquals(ANIMATION_TYPE_APP_TRANSITION, mDeferFinishAnimatable.mFinishedAnimationType);
verify(mTransaction).remove(eq(mDeferFinishAnimatable.mLeash));
}
@@ -229,7 +251,7 @@
public void testDeferFinishDoNotFinishNextAnimation() {
// Start the first animation.
final OnAnimationFinishedCallback onFinishedCallback = startDeferFinishAnimatable(mSpec);
- onFinishedCallback.onAnimationFinished(mSpec);
+ onFinishedCallback.onAnimationFinished(ANIMATION_TYPE_APP_TRANSITION, mSpec);
// The callback is the resetAndInvokeFinish in {@link SurfaceAnimator#getFinishedCallback}.
final Runnable firstDeferFinishCallback = mDeferFinishAnimatable.mEndDeferFinishCallback;
@@ -247,11 +269,12 @@
private OnAnimationFinishedCallback startDeferFinishAnimatable(AnimationAdapter anim) {
mDeferFinishAnimatable.mSurfaceAnimator.startAnimation(mTransaction, anim,
- true /* hidden */);
+ true /* hidden */, ANIMATION_TYPE_APP_TRANSITION);
final ArgumentCaptor<OnAnimationFinishedCallback> callbackCaptor = ArgumentCaptor.forClass(
OnAnimationFinishedCallback.class);
assertAnimating(mDeferFinishAnimatable);
- verify(anim).startAnimation(any(), any(), callbackCaptor.capture());
+ verify(anim).startAnimation(any(), any(), eq(ANIMATION_TYPE_APP_TRANSITION),
+ callbackCaptor.capture());
return callbackCaptor.getValue();
}
@@ -274,6 +297,7 @@
final SurfaceAnimator mSurfaceAnimator;
SurfaceControl mLeash;
boolean mFinishedCallbackCalled;
+ @AnimationType int mFinishedAnimationType;
MyAnimatable(WindowManagerService wm, SurfaceSession session, Transaction transaction) {
mSession = session;
@@ -343,7 +367,11 @@
return 1;
}
- private final Runnable mFinishedCallback = () -> mFinishedCallbackCalled = true;
+ private final SurfaceAnimator.OnAnimationFinishedCallback mFinishedCallback = (
+ type, anim) -> {
+ mFinishedCallbackCalled = true;
+ mFinishedAnimationType = type;
+ };
}
private static class DeferFinishAnimatable extends MyAnimatable {
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 9e80cf2..078347e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2017 The Android Open Source Project
+ * Copyright (C) 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -16,45 +16,50 @@
package com.android.server.wm;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
+import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
+import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_SECONDARY;
+import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
-import static org.junit.Assert.assertFalse;
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
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.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
-import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.when;
-import android.graphics.Point;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+
+import android.app.ActivityManager.RunningTaskInfo;
+import android.app.ActivityManager.StackInfo;
+import android.content.res.Configuration;
import android.graphics.Rect;
-import android.platform.test.annotations.Presubmit;
import android.os.Binder;
import android.os.RemoteException;
+import android.platform.test.annotations.Presubmit;
+import android.view.Display;
import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
import android.view.SurfaceControl;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import android.view.WindowContainerTransaction;
import androidx.test.filters.SmallTest;
import org.junit.Test;
import org.junit.runner.RunWith;
+import java.util.ArrayList;
+import java.util.List;
+
/**
- * Test class for {@link TaskOrganizer}.
+ * Test class for {@link ITaskOrganizer} and {@link android.app.ITaskOrganizerController}.
*
* Build/Install/Run:
* atest WmTests:TaskOrganizerTests
@@ -67,7 +72,8 @@
final ITaskOrganizer organizer = mock(ITaskOrganizer.class);
when(organizer.asBinder()).thenReturn(new Binder());
- mWm.mAtmService.registerTaskOrganizer(organizer, windowingMode);
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(
+ organizer, windowingMode);
return organizer;
}
@@ -83,7 +89,7 @@
final ITaskOrganizer organizer = registerMockOrganizer();
task.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
task.removeImmediately();
verify(organizer).taskVanished(any());
@@ -97,10 +103,10 @@
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
task.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
task.setTaskOrganizer(organizer2);
verify(organizer).taskVanished(any());
- verify(organizer2).taskAppeared(any(), any());
+ verify(organizer2).taskAppeared(any());
}
@Test
@@ -111,10 +117,10 @@
final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_PINNED);
verify(organizer).taskVanished(any());
- verify(organizer2).taskAppeared(any(), any());
+ verify(organizer2).taskAppeared(any());
}
@Test
@@ -124,7 +130,7 @@
final ITaskOrganizer organizer = registerMockOrganizer();
stack.setTaskOrganizer(organizer);
- verify(organizer).taskAppeared(any(), any());
+ verify(organizer).taskAppeared(any());
assertTrue(stack.isControlledByTaskOrganizer());
stack.setTaskOrganizer(null);
@@ -140,9 +146,176 @@
final Task task = createTaskInStack(stack, 0 /* userId */);
final Task task2 = createTaskInStack(stack, 0 /* userId */);
stack.setWindowingMode(WINDOWING_MODE_PINNED);
- verify(organizer, times(1)).taskAppeared(any(), any());
+ verify(organizer, times(1)).taskAppeared(any());
stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
verify(organizer, times(1)).taskVanished(any());
}
+
+ @Test
+ public void testTaskTransaction() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final Task task = stack.getTopMostTask();
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ Rect newBounds = new Rect(10, 10, 100, 100);
+ t.setBounds(task.mRemoteToken, new Rect(10, 10, 100, 100));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertEquals(newBounds, task.getBounds());
+ }
+
+ @Test
+ public void testStackTransaction() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ StackInfo info =
+ mWm.mAtmService.getStackInfo(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD);
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ assertEquals(stack.mRemoteToken, info.stackToken);
+ Rect newBounds = new Rect(10, 10, 100, 100);
+ t.setBounds(info.stackToken, new Rect(10, 10, 100, 100));
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertEquals(newBounds, stack.getBounds());
+ }
+
+ @Test
+ public void testContainerChanges() {
+ removeGlobalMinSizeRestriction();
+ final ActivityStack stack = new ActivityTestsBase.StackBuilder(mWm.mRoot)
+ .setWindowingMode(WINDOWING_MODE_FREEFORM).build();
+ final Task task = stack.getTopMostTask();
+ WindowContainerTransaction t = new WindowContainerTransaction();
+ assertTrue(task.isFocusable());
+ t.setFocusable(stack.mRemoteToken, false);
+ mWm.mAtmService.mTaskOrganizerController.applyContainerTransaction(t);
+ assertFalse(task.isFocusable());
+ }
+
+ @Test
+ public void testCreateDeleteRootTasks() {
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ Display.DEFAULT_DISPLAY,
+ WINDOWING_MODE_SPLIT_SCREEN_PRIMARY);
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_PRIMARY,
+ info1.configuration.windowConfiguration.getWindowingMode());
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
+
+ RunningTaskInfo info2 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ Display.DEFAULT_DISPLAY,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY,
+ info2.configuration.windowConfiguration.getWindowingMode());
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info2.topActivityType);
+
+ DisplayContent dc = mWm.mRoot.getDisplayContent(Display.DEFAULT_DISPLAY);
+ List<TaskTile> infos = getTaskTiles(dc);
+ assertEquals(2, infos.size());
+
+ assertTrue(mWm.mAtmService.mTaskOrganizerController.deleteRootTask(info1.token));
+ infos = getTaskTiles(dc);
+ assertEquals(1, infos.size());
+ assertEquals(WINDOWING_MODE_SPLIT_SCREEN_SECONDARY, infos.get(0).getWindowingMode());
+ }
+
+ @Test
+ public void testTileAddRemoveChild() {
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+
+ final ActivityStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
+ tile1.addChild(stack, 0 /* index */);
+ assertEquals(info1.configuration.windowConfiguration.getWindowingMode(),
+ stack.getWindowingMode());
+
+ // Info should reflect new membership
+ List<TaskTile> tiles = getTaskTiles(mDisplayContent);
+ info1 = new RunningTaskInfo();
+ tiles.get(0).fillTaskInfo(info1);
+ assertEquals(ACTIVITY_TYPE_STANDARD, info1.topActivityType);
+
+ // Children inherit configuration
+ Rect newSize = new Rect(10, 10, 300, 300);
+ Configuration c = new Configuration(tile1.getRequestedOverrideConfiguration());
+ c.windowConfiguration.setBounds(newSize);
+ tile1.onRequestedOverrideConfigurationChanged(c);
+ assertEquals(newSize, stack.getBounds());
+
+ tile1.removeChild(stack);
+ assertEquals(mDisplayContent.getWindowingMode(), stack.getWindowingMode());
+ info1 = new RunningTaskInfo();
+ tiles = getTaskTiles(mDisplayContent);
+ tiles.get(0).fillTaskInfo(info1);
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, info1.topActivityType);
+ }
+
+ @Test
+ public void testTaskInfoCallback() {
+ final ArrayList<RunningTaskInfo> lastReportedTiles = new ArrayList<>();
+ final boolean[] called = {false};
+ ITaskOrganizer listener = new ITaskOrganizer.Stub() {
+ @Override
+ public void taskAppeared(RunningTaskInfo taskInfo) { }
+
+ @Override
+ public void taskVanished(IWindowContainer container) { }
+
+ @Override
+ public void transactionReady(int id, SurfaceControl.Transaction t) { }
+
+ @Override
+ public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException {
+ lastReportedTiles.add(info);
+ called[0] = true;
+ }
+ };
+ mWm.mAtmService.mTaskOrganizerController.registerTaskOrganizer(listener,
+ WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ RunningTaskInfo info1 = mWm.mAtmService.mTaskOrganizerController.createRootTask(
+ mDisplayContent.mDisplayId, WINDOWING_MODE_SPLIT_SCREEN_SECONDARY);
+ lastReportedTiles.clear();
+ called[0] = false;
+
+ final ActivityStack stack = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_STANDARD, mDisplayContent);
+ TaskTile tile1 = TaskTile.forToken(info1.token.asBinder());
+ tile1.addChild(stack, 0 /* index */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ final ActivityStack stack2 = createTaskStackOnDisplay(
+ WINDOWING_MODE_UNDEFINED, ACTIVITY_TYPE_HOME, mDisplayContent);
+ tile1.addChild(stack2, 0 /* index */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_HOME, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ mDisplayContent.positionStackAtTop(stack, false /* includingParents */);
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_STANDARD, lastReportedTiles.get(0).topActivityType);
+
+ lastReportedTiles.clear();
+ called[0] = false;
+ tile1.removeAllChildren();
+ assertTrue(called[0]);
+ assertEquals(ACTIVITY_TYPE_UNDEFINED, lastReportedTiles.get(0).topActivityType);
+ }
+
+ private List<TaskTile> getTaskTiles(DisplayContent dc) {
+ ArrayList<TaskTile> out = new ArrayList<>();
+ for (int i = dc.getStackCount() - 1; i >= 0; --i) {
+ final Task t = dc.getStackAt(i);
+ if (t instanceof TaskTile) {
+ out.add((TaskTile) t);
+ }
+ }
+ return out;
+ }
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
index 05d048d3..4a87701 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTests.java
@@ -34,6 +34,7 @@
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_APP_TRANSITION;
import static com.android.server.wm.WindowContainer.AnimationFlags.CHILDREN;
import static com.android.server.wm.WindowContainer.AnimationFlags.PARENTS;
import static com.android.server.wm.WindowContainer.AnimationFlags.TRANSITION;
@@ -61,6 +62,8 @@
import androidx.test.filters.SmallTest;
+import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
+
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
@@ -829,7 +832,8 @@
wc.getDisplayContent().mAppTransition.overridePendingAppTransitionRemote(adapter);
spyOn(wc);
doReturn(true).when(wc).okToAnimate();
- final Runnable onAnimationFinishedCallback = mock(Runnable.class);
+ final OnAnimationFinishedCallback onAnimationFinishedCallback =
+ mock(OnAnimationFinishedCallback.class);
// Make sure animating state is as expected after applied animation.
assertTrue(wc.applyAnimation(null, TRANSIT_TASK_OPEN, true, false,
@@ -837,16 +841,18 @@
assertEquals(wc.getTopMostActivity(), act);
assertTrue(wc.isAnimating());
assertTrue(act.isAnimating(PARENTS));
- verify(onAnimationFinishedCallback, times(0)).run();
+ verify(onAnimationFinishedCallback, times(0)).onAnimationFinished(
+ eq(ANIMATION_TYPE_APP_TRANSITION), any());
// Make sure animation finish callback will be received and reset animating state after
// animation finish.
wc.getDisplayContent().mAppTransition.goodToGo(TRANSIT_TASK_OPEN, act,
mDisplayContent.mOpeningApps);
- verify(wc).onAnimationFinished();
+ verify(wc).onAnimationFinished(eq(ANIMATION_TYPE_APP_TRANSITION), any());
assertFalse(wc.isAnimating());
assertFalse(act.isAnimating(PARENTS));
- verify(onAnimationFinishedCallback, times(1)).run();
+ verify(onAnimationFinishedCallback, times(1)).onAnimationFinished(
+ eq(ANIMATION_TYPE_APP_TRANSITION), any());
}
/* Used so we can gain access to some protected members of the {@link WindowContainer} class */
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 8e362ae..1ca2e318 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -40,6 +40,7 @@
import static org.mockito.Mockito.mock;
import android.content.Context;
+import android.content.Intent;
import android.util.Log;
import android.view.Display;
import android.view.DisplayInfo;
@@ -340,6 +341,7 @@
.setWindowingMode(windowingMode)
.setActivityType(activityType)
.setCreateActivity(false)
+ .setIntent(new Intent())
.build();
}
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/testing/Assert.java b/services/tests/wmtests/src/com/android/server/wm/testing/Assert.java
new file mode 100644
index 0000000..1e98277
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/testing/Assert.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.testing;
+
+/**
+ * Assertions for WM tests.
+ */
+public class Assert {
+
+ /**
+ * Runs {@code r} and asserts that an exception of type {@code expectedThrowable} is thrown.
+ * @param expectedThrowable the type of throwable that is expected to be thrown
+ * @param r the {@link Runnable} which is run and expected to throw.
+ * @throws AssertionError if {@code r} does not throw, or throws a runnable that is not an
+ * instance of {@code expectedThrowable}.
+ */
+ // TODO: remove once Android migrates to JUnit 4.13, which provides assertThrows
+ public static void assertThrows(Class<? extends Throwable> expectedThrowable, Runnable r) {
+ try {
+ r.run();
+ } catch (Throwable t) {
+ if (expectedThrowable.isInstance(t)) {
+ return;
+ } else if (t instanceof Exception) {
+ throw new AssertionError("Expected " + expectedThrowable
+ + ", but got " + t.getClass(), t);
+ } else {
+ // Re-throw Errors and other non-Exception throwables.
+ throw t;
+ }
+ }
+ throw new AssertionError("Expected " + expectedThrowable + ", but nothing was thrown");
+ }
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/testing/AssertTest.java b/services/tests/wmtests/src/com/android/server/wm/testing/AssertTest.java
new file mode 100644
index 0000000..df12761
--- /dev/null
+++ b/services/tests/wmtests/src/com/android/server/wm/testing/AssertTest.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.testing;
+
+import static com.android.server.wm.testing.Assert.assertThrows;
+
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+public class AssertTest {
+
+ @Rule
+ public ExpectedException mExpectedException = ExpectedException.none();
+
+ @Test
+ public void assertThrows_runsRunnable() {
+ boolean[] ran = new boolean[] { false };
+ assertThrows(TestException.class, () -> {
+ ran[0] = true;
+ throw new TestException();
+ });
+ assertTrue(ran[0]);
+ }
+
+ @Test
+ public void assertThrows_failsIfNothingThrown() {
+ mExpectedException.expect(AssertionError.class);
+ assertThrows(TestException.class, () -> {
+ });
+ }
+
+ @Test
+ public void assertThrows_failsIfWrongExceptionThrown() {
+ mExpectedException.expect(AssertionError.class);
+ assertThrows(TestException.class, () -> {
+ throw new RuntimeException();
+ });
+ }
+
+ @Test
+ public void assertThrows_succeedsIfGivenExceptionThrown() {
+ assertThrows(TestException.class, () -> {
+ throw new TestException();
+ });
+ }
+
+ @Test
+ public void assertThrows_succeedsIfSubExceptionThrown() {
+ assertThrows(RuntimeException.class, () -> {
+ throw new TestException();
+ });
+ }
+
+ @Test
+ public void assertThrows_rethrowsUnexpectedErrors() {
+ mExpectedException.expect(TestError.class);
+ assertThrows(TestException.class, () -> {
+ throw new TestError();
+ });
+ }
+
+ static class TestException extends RuntimeException {
+ }
+
+ static class TestError extends Error {
+ }
+
+}
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 14852d0..48b6e2a 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -2117,9 +2117,9 @@
@Override
public UsageEvents queryEventsForUser(int userId, long beginTime, long endTime,
- boolean shouldObfuscateInstantApps) {
+ boolean obfuscateInstantApps, boolean hideShortcutInvocationEvents) {
return UsageStatsService.this.queryEvents(
- userId, beginTime, endTime, shouldObfuscateInstantApps, false);
+ userId, beginTime, endTime, obfuscateInstantApps, hideShortcutInvocationEvents);
}
@Override
diff --git a/telephony/java/android/telephony/BarringInfo.java b/telephony/java/android/telephony/BarringInfo.java
index 5419c3c..9baa66f 100644
--- a/telephony/java/android/telephony/BarringInfo.java
+++ b/telephony/java/android/telephony/BarringInfo.java
@@ -238,6 +238,12 @@
}
}
+ private static final BarringServiceInfo BARRING_SERVICE_INFO_UNKNOWN =
+ new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_UNKNOWN);
+
+ private static final BarringServiceInfo BARRING_SERVICE_INFO_UNBARRED =
+ new BarringServiceInfo(BarringServiceInfo.BARRING_TYPE_NONE);
+
private CellIdentity mCellIdentity;
// A SparseArray potentially mapping each BarringService type to a BarringServiceInfo config
@@ -298,17 +304,6 @@
}
/**
- * Return whether a service is currently barred based on the BarringInfo
- *
- * @param service the service to be checked.
- * @return true if the service is currently being barred, otherwise false
- */
- public boolean isServiceBarred(@BarringServiceType int service) {
- BarringServiceInfo bsi = mBarringServiceInfos.get(service);
- return bsi != null && (bsi.isBarred());
- }
-
- /**
* Get the BarringServiceInfo for a specified service.
*
* @return a BarringServiceInfo struct describing the current barring status for a service
@@ -319,9 +314,8 @@
// type as UNKNOWN; if the modem reports barring info but doesn't report for a particular
// service then we can safely assume that the service isn't barred (for instance because
// that particular service isn't applicable to the current RAN).
- return (bsi != null) ? bsi : new BarringServiceInfo(
- mBarringServiceInfos.size() > 0 ? BarringServiceInfo.BARRING_TYPE_NONE :
- BarringServiceInfo.BARRING_TYPE_UNKNOWN);
+ return (bsi != null) ? bsi : mBarringServiceInfos.size() > 0
+ ? BARRING_SERVICE_INFO_UNBARRED : BARRING_SERVICE_INFO_UNKNOWN;
}
/** @hide */
diff --git a/telephony/java/android/telephony/PreciseDataConnectionState.java b/telephony/java/android/telephony/PreciseDataConnectionState.java
index 094b8b0..54c22ae 100644
--- a/telephony/java/android/telephony/PreciseDataConnectionState.java
+++ b/telephony/java/android/telephony/PreciseDataConnectionState.java
@@ -135,11 +135,12 @@
}
/**
- * To check the SDK version for {@code PreciseDataConnectionState#getDataConnectionState}.
+ * Used for checking if the SDK version for
+ * {@code PreciseDataConnectionState#getDataConnectionState} is above Q.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
- private static final long GET_DATA_CONNECTION_STATE_CODE_CHANGE = 147600208L;
+ private static final long GET_DATA_CONNECTION_STATE_R_VERSION = 148535736L;
/**
* Returns the state of data connection that supported the apn types returned by
@@ -152,7 +153,7 @@
@SystemApi
public @DataState int getDataConnectionState() {
if (mState == TelephonyManager.DATA_DISCONNECTING
- && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_CODE_CHANGE)) {
+ && !Compatibility.isChangeEnabled(GET_DATA_CONNECTION_STATE_R_VERSION)) {
return TelephonyManager.DATA_CONNECTED;
}
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 5b09cd9..a5a1ebc 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -1925,6 +1925,8 @@
/**
* Get the network registration state for the transport type and network domain.
+ * If multiple domains are in the input bitmask, only the first one from
+ * networkRegistrationInfo.getDomain() will be returned.
*
* @param domain The network {@link NetworkRegistrationInfo.Domain domain}
* @param transportType The transport type
@@ -2072,11 +2074,18 @@
public boolean isIwlanPreferred() {
return mIsIwlanPreferred;
}
- /**
- * @return {@code true}Returns True whenever the modem is searching for service.
- * To check both CS and PS domain
- */
+ /**
+ * This indicates whether the device is searching for service.
+ *
+ * This API reports the modem searching status for
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WWAN} (cellular) service in either
+ * {@link NetworkRegistrationInfo#DOMAIN_CS} or {@link NetworkRegistrationInfo#DOMAIN_PS}.
+ * This API will not report searching status for
+ * {@link AccessNetworkConstants#TRANSPORT_TYPE_WLAN}.
+ *
+ * @return {@code true} whenever the modem is searching for service.
+ */
public boolean isSearching() {
NetworkRegistrationInfo psRegState = getNetworkRegistrationInfo(
NetworkRegistrationInfo.DOMAIN_PS, AccessNetworkConstants.TRANSPORT_TYPE_WWAN);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 26dc5f0..6723522 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -5562,11 +5562,11 @@
public static final int DATA_DISCONNECTING = 4;
/**
- * To check the SDK version for {@link TelephonyManager#getDataState}.
+ * Used for checking if the SDK version for {@link TelephonyManager#getDataState} is above Q.
*/
@ChangeId
@EnabledAfter(targetSdkVersion = Build.VERSION_CODES.Q)
- private static final long GET_DATA_STATE_CODE_CHANGE = 147600208L;
+ private static final long GET_DATA_STATE_R_VERSION = 148534348L;
/**
* Returns a constant indicating the current data connection state
@@ -5586,7 +5586,7 @@
int state = telephony.getDataStateForSubId(
getSubId(SubscriptionManager.getActiveDataSubscriptionId()));
if (state == TelephonyManager.DATA_DISCONNECTING
- && !Compatibility.isChangeEnabled(GET_DATA_STATE_CODE_CHANGE)) {
+ && !Compatibility.isChangeEnabled(GET_DATA_STATE_R_VERSION)) {
return TelephonyManager.DATA_CONNECTED;
}
diff --git a/test-mock/src/android/test/mock/MockContext.java b/test-mock/src/android/test/mock/MockContext.java
index 36074ed..359c448 100644
--- a/test-mock/src/android/test/mock/MockContext.java
+++ b/test-mock/src/android/test/mock/MockContext.java
@@ -812,7 +812,7 @@
}
@Override
- public @NonNull Context createWindowContext(int type) {
+ public @NonNull Context createWindowContext(int type, Bundle options) {
throw new UnsupportedOperationException();
}
diff --git a/test-runner/src/android/test/TouchUtils.java b/test-runner/src/android/test/TouchUtils.java
index 28dc7b2..bb4e00b 100644
--- a/test-runner/src/android/test/TouchUtils.java
+++ b/test-runner/src/android/test/TouchUtils.java
@@ -222,7 +222,8 @@
*/
public static void dragViewToBottom(InstrumentationTestCase test, Activity activity, View v,
int stepCount) {
- int screenHeight = activity.getWindowManager().getDefaultDisplay().getHeight();
+ int screenHeight =
+ activity.getWindowManager().getCurrentWindowMetrics().getSize().getHeight();
int[] xy = new int[2];
v.getLocationOnScreen(xy);
diff --git a/tests/GamePerformance/src/android/gameperformance/BaseTest.java b/tests/GamePerformance/src/android/gameperformance/BaseTest.java
index b0640b44..e705756 100644
--- a/tests/GamePerformance/src/android/gameperformance/BaseTest.java
+++ b/tests/GamePerformance/src/android/gameperformance/BaseTest.java
@@ -21,7 +21,6 @@
import android.annotation.NonNull;
import android.content.Context;
import android.util.Log;
-import android.view.WindowManager;
/**
* Base class for a test that performs bisection to determine maximum
@@ -55,9 +54,7 @@
public BaseTest(@NonNull GamePerformanceActivity activity) {
mActivity = activity;
- final WindowManager windowManager =
- (WindowManager)getContext().getSystemService(Context.WINDOW_SERVICE);
- mRefreshRate = windowManager.getDefaultDisplay().getRefreshRate();
+ mRefreshRate = activity.getDisplay().getRefreshRate();
}
@NonNull
diff --git a/tests/GamePerformance/src/android/gameperformance/CustomControlView.java b/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
index 219085a..e63736b 100644
--- a/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
+++ b/tests/GamePerformance/src/android/gameperformance/CustomControlView.java
@@ -25,18 +25,16 @@
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
+import android.graphics.Point;
import android.graphics.drawable.AnimationDrawable;
-import android.util.Log;
-import android.view.WindowManager;
import android.widget.AbsoluteLayout;
import android.widget.ImageView;
-import android.widget.RelativeLayout;
/**
* View that holds requested number of UI controls as ImageView with an infinite animation.
*/
public class CustomControlView extends AbsoluteLayout {
- private final static int CONTROL_DIMENTION = 48;
+ private final static int CONTROL_DIMENSION = 48;
private final int mPerRowControlCount;
private List<Long> mFrameTimes = new ArrayList<>();
@@ -44,8 +42,9 @@
public CustomControlView(@NonNull Context context) {
super(context);
- final WindowManager windowManager = (WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
- mPerRowControlCount = windowManager.getDefaultDisplay().getWidth() / CONTROL_DIMENTION;
+ final Point size = new Point();
+ context.getDisplay().getSize(size);
+ mPerRowControlCount = size.x / CONTROL_DIMENSION;
}
/**
@@ -76,11 +75,11 @@
for (int i = 0; i < controlCount; ++i) {
final ImageView image = (i == 0) ?
new ReferenceImageView(activity) : new ImageView(activity);
- final int x = (i % mPerRowControlCount) * CONTROL_DIMENTION;
- final int y = (i / mPerRowControlCount) * CONTROL_DIMENTION;
+ final int x = (i % mPerRowControlCount) * CONTROL_DIMENSION;
+ final int y = (i / mPerRowControlCount) * CONTROL_DIMENSION;
final AbsoluteLayout.LayoutParams layoutParams =
new AbsoluteLayout.LayoutParams(
- CONTROL_DIMENTION, CONTROL_DIMENTION, x, y);
+ CONTROL_DIMENSION, CONTROL_DIMENSION, x, y);
image.setLayoutParams(layoutParams);
image.setBackgroundResource(R.drawable.animation);
final AnimationDrawable animation =
diff --git a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
index 0f4c668..6d8c43c 100644
--- a/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
+++ b/tests/HwAccelerationTest/src/com/android/test/hwui/TextureViewActivity.java
@@ -122,7 +122,7 @@
if (info.facing == Camera.CameraInfo.CAMERA_FACING_BACK) break;
}
- int rotation = getWindowManager().getDefaultDisplay().getRotation();
+ int rotation = getDisplay().getRotation();
int degrees = 0;
switch (rotation) {
diff --git a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
index b863713..e255ce2 100644
--- a/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
+++ b/tests/MirrorSurfaceTest/src/com/google/android/test/mirrorsurface/MirrorSurfaceActivity.java
@@ -16,6 +16,7 @@
package com.google.android.test.mirrorsurface;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;
import android.app.Activity;
import android.graphics.Canvas;
@@ -26,7 +27,7 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.RemoteException;
-import android.util.DisplayMetrics;
+import android.util.Size;
import android.view.Gravity;
import android.view.IWindowManager;
import android.view.MotionEvent;
@@ -48,6 +49,8 @@
private static final int MOVE_FRAME_AMOUNT = 20;
private IWindowManager mIWm;
+ // An instance of WindowManager that is adjusted for adding windows with type
+ // TYPE_APPLICATION_OVERLAY.
private WindowManager mWm;
private SurfaceControl mSurfaceControl = new SurfaceControl();
@@ -57,7 +60,7 @@
private View mOverlayView;
private View mArrowOverlay;
- private Rect mDisplayBounds = new Rect();
+ private Rect mWindowBounds = new Rect();
private EditText mScaleText;
private EditText mDisplayFrameText;
@@ -83,21 +86,21 @@
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mirror_surface);
- mWm = (WindowManager) getSystemService(WINDOW_SERVICE);
+ mWm = createWindowContext(TYPE_APPLICATION_OVERLAY, null /* options */)
+ .getSystemService(WindowManager.class);
mIWm = WindowManagerGlobal.getWindowManagerService();
- DisplayMetrics displayMetrics = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
- mDisplayBounds.set(0, 0, displayMetrics.widthPixels, displayMetrics.heightPixels);
+ Size windowSize = mWm.getCurrentWindowMetrics().getSize();
+ mWindowBounds.set(0, 0, windowSize.getWidth(), windowSize.getHeight());
mScaleText = findViewById(R.id.scale);
mDisplayFrameText = findViewById(R.id.displayFrame);
mSourcePositionText = findViewById(R.id.sourcePosition);
- mCurrFrame.set(0, 0, mDisplayBounds.width() / 2, mDisplayBounds.height() / 2);
+ mCurrFrame.set(0, 0, mWindowBounds.width() / 2, mWindowBounds.height() / 2);
mCurrScale = DEFAULT_SCALE;
- mDisplayId = getWindowManager().getDefaultDisplay().getDisplayId();
+ mDisplayId = getDisplay().getDisplayId();
updateEditTexts();
findViewById(R.id.mirror_button).setOnClickListener(view -> {
@@ -194,8 +197,8 @@
private void createMirrorOverlay() {
mOverlayView = new LinearLayout(this);
- WindowManager.LayoutParams params = new WindowManager.LayoutParams(mDisplayBounds.width(),
- mDisplayBounds.height(),
+ WindowManager.LayoutParams params = new WindowManager.LayoutParams(mWindowBounds.width(),
+ mWindowBounds.height(),
WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY,
WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
@@ -290,7 +293,7 @@
private void updateMirror(Rect displayFrame, float scale) {
if (displayFrame.isEmpty()) {
- Rect bounds = mDisplayBounds;
+ Rect bounds = mWindowBounds;
int defaultCropW = Math.round(bounds.width() / 2);
int defaultCropH = Math.round(bounds.height() / 2);
displayFrame.set(0, 0, defaultCropW, defaultCropH);
diff --git a/tests/PlatformCompatGating/Android.bp b/tests/PlatformCompatGating/Android.bp
index 609896e..5e9ef8e 100644
--- a/tests/PlatformCompatGating/Android.bp
+++ b/tests/PlatformCompatGating/Android.bp
@@ -18,6 +18,7 @@
name: "PlatformCompatGating",
// Only compile source java files in this apk.
srcs: ["src/**/*.java"],
+ certificate: "platform",
libs: [
"android.test.runner",
"android.test.base",
diff --git a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
index c00aa2a..932ec64 100644
--- a/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
+++ b/tests/PlatformCompatGating/test-rules/src/android/compat/testing/PlatformCompatChangeRule.java
@@ -16,9 +16,7 @@
package android.compat.testing;
-import android.Manifest;
import android.app.Instrumentation;
-import android.app.UiAutomation;
import android.compat.Compatibility;
import android.compat.Compatibility.ChangeConfig;
import android.content.Context;
@@ -85,16 +83,12 @@
@Override
public void evaluate() throws Throwable {
Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
- UiAutomation uiAutomation = instrumentation.getUiAutomation();
String packageName = instrumentation.getTargetContext().getPackageName();
IPlatformCompat platformCompat = IPlatformCompat.Stub
.asInterface(ServiceManager.getService(Context.PLATFORM_COMPAT_SERVICE));
if (platformCompat == null) {
throw new IllegalStateException("Could not get IPlatformCompat service!");
}
- uiAutomation.adoptShellPermissionIdentity(
- Manifest.permission.READ_COMPAT_CHANGE_CONFIG,
- Manifest.permission.OVERRIDE_COMPAT_CHANGE_CONFIG);
Compatibility.setOverrides(mConfig);
try {
platformCompat.setOverridesForTest(new CompatibilityChangeConfig(mConfig),
@@ -107,7 +101,6 @@
} catch (RemoteException e) {
throw new RuntimeException("Could not call IPlatformCompat binder method!", e);
} finally {
- uiAutomation.dropShellPermissionIdentity();
Compatibility.clearOverrides();
}
}
diff --git a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
index 4771b6c..e0a9668 100644
--- a/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
+++ b/tests/SurfaceComposition/src/android/surfacecomposition/SurfaceCompositionMeasuringActivity.java
@@ -23,7 +23,6 @@
import android.app.Activity;
import android.app.ActivityManager;
import android.app.ActivityManager.MemoryInfo;
-import android.content.Context;
import android.content.pm.PackageManager;
import android.graphics.Color;
import android.graphics.PixelFormat;
@@ -531,8 +530,7 @@
}
private void detectRefreshRate() {
- WindowManager wm = (WindowManager)getSystemService(Context.WINDOW_SERVICE);
- mRefreshRate = wm.getDefaultDisplay().getRefreshRate();
+ mRefreshRate = getDisplay().getRefreshRate();
if (mRefreshRate < MIN_REFRESH_RATE_SUPPORTED)
throw new RuntimeException("Unsupported display refresh rate: " + mRefreshRate);
mTargetFPS = mRefreshRate - 2.0f;
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index bc8d3c3..3fb0050 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -25,6 +25,7 @@
import android.content.Intent;
import android.graphics.Rect;
import android.os.Bundle;
+import android.os.RemoteException;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
import android.view.SurfaceControl;
@@ -47,13 +48,16 @@
class Organizer extends ITaskOrganizer.Stub {
@Override
- public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
- mView.reparentTask(wc);
+ public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+ mView.reparentTask(ti.token);
}
public void taskVanished(IWindowContainer wc) {
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
+ @Override
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
}
Organizer mOrganizer = new Organizer();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index fc1be28..8f3cb34 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -21,18 +21,14 @@
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.Service;
-import android.app.WindowConfiguration;
-import android.content.Context;
import android.content.Intent;
import android.graphics.Rect;
import android.os.IBinder;
import android.view.ITaskOrganizer;
import android.view.IWindowContainer;
-import android.view.WindowContainerTransaction;
import android.view.SurfaceControl;
-import android.view.SurfaceHolder;
-import android.view.SurfaceView;
import android.view.ViewGroup;
+import android.view.WindowContainerTransaction;
import android.view.WindowManager;
import android.widget.FrameLayout;
@@ -43,13 +39,13 @@
TaskView mTaskView;
class Organizer extends ITaskOrganizer.Stub {
- public void taskAppeared(IWindowContainer wc, ActivityManager.RunningTaskInfo ti) {
- mTaskView.reparentTask(wc);
+ public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+ mTaskView.reparentTask(ti.token);
final WindowContainerTransaction wct = new WindowContainerTransaction();
- wct.scheduleFinishEnterPip(wc, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
+ wct.scheduleFinishEnterPip(ti.token, new Rect(0, 0, PIP_WIDTH, PIP_HEIGHT));
try {
- ActivityTaskManager.getService().applyContainerTransaction(wct);
+ ActivityTaskManager.getTaskOrganizerController().applyContainerTransaction(wct);
} catch (Exception e) {
}
}
@@ -57,6 +53,8 @@
}
public void transactionReady(int id, SurfaceControl.Transaction t) {
}
+ public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
+ }
}
Organizer mOrganizer = new Organizer();
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
index ff73340..9f32bb8 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskView.java
@@ -44,7 +44,7 @@
@Override
public void surfaceCreated(SurfaceHolder holder) {
try {
- ActivityTaskManager.getService().registerTaskOrganizer(mTaskOrganizer,
+ ActivityTaskManager.getTaskOrganizerController().registerTaskOrganizer(mTaskOrganizer,
mWindowingMode);
} catch (Exception e) {
}
diff --git a/tests/net/TEST_MAPPING b/tests/net/TEST_MAPPING
index a7853b6..005cbe9 100644
--- a/tests/net/TEST_MAPPING
+++ b/tests/net/TEST_MAPPING
@@ -1,7 +1,12 @@
{
- "postsubmit": [
+ "presubmit": [
{
"name": "FrameworksNetIntegrationTests"
}
+ ],
+ "postsubmit": [
+ {
+ "name": "FrameworksNetDeflakeTest"
+ }
]
}
\ No newline at end of file
diff --git a/tests/net/common/java/android/net/NetworkScoreTest.kt b/tests/net/common/java/android/net/NetworkScoreTest.kt
index 30836b7..a63d58d 100644
--- a/tests/net/common/java/android/net/NetworkScoreTest.kt
+++ b/tests/net/common/java/android/net/NetworkScoreTest.kt
@@ -16,7 +16,7 @@
package android.net
-import android.os.Parcelable
+import android.net.NetworkScore.Metrics.BANDWIDTH_UNKNOWN
import androidx.test.filters.SmallTest
import androidx.test.runner.AndroidJUnit4
import com.android.testutils.assertParcelSane
@@ -28,77 +28,49 @@
import org.junit.runner.RunWith
private const val TEST_SCORE = 80
-private const val KEY_DEFAULT_CAPABILITIES = "DEFAULT_CAPABILITIES"
@RunWith(AndroidJUnit4::class)
@SmallTest
class NetworkScoreTest {
@Test
fun testParcelNetworkScore() {
- val networkScore = NetworkScore()
val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- assertParcelSane(networkScore, 1)
- }
+ val builder = NetworkScore.Builder().setLegacyScore(TEST_SCORE)
+ assertEquals(TEST_SCORE, builder.build().getLegacyScore())
+ assertParcelSane(builder.build(), 7)
- @Test
- fun testNullKeyAndValue() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putIntExtension(null, TEST_SCORE)
- assertEquals(TEST_SCORE, networkScore.getIntExtension(null))
- networkScore.putExtension(null, defaultCap)
- assertEquals(defaultCap, networkScore.getExtension(null))
- networkScore.putExtension(null, null)
- val result: Parcelable? = networkScore.getExtension(null)
- assertEquals(null, result)
- }
+ builder.addPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+ .addPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION)
+ .setLinkLayerMetrics(NetworkScore.Metrics(44 /* latency */,
+ 380 /* downlinkBandwidth */, BANDWIDTH_UNKNOWN /* uplinkBandwidth */))
+ .setEndToEndMetrics(NetworkScore.Metrics(11 /* latency */,
+ BANDWIDTH_UNKNOWN /* downlinkBandwidth */, 100_000 /* uplinkBandwidth */))
+ .setRange(NetworkScore.RANGE_MEDIUM)
+ assertParcelSane(builder.build(), 7)
+ builder.clearPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI)
+ val ns = builder.build()
+ assertParcelSane(ns, 7)
+ assertFalse(ns.hasPolicy(NetworkScore.POLICY_IGNORE_ON_WIFI))
+ assertTrue(ns.hasPolicy(NetworkScore.POLICY_DEFAULT_SUBSCRIPTION))
- @Test
- fun testRemoveExtension() {
- val networkScore = NetworkScore()
- val defaultCap = NetworkCapabilities()
- networkScore.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- networkScore.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertEquals(defaultCap, networkScore.getExtension(KEY_DEFAULT_CAPABILITIES))
- assertEquals(TEST_SCORE, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
- networkScore.removeExtension(KEY_DEFAULT_CAPABILITIES)
- networkScore.removeExtension(NetworkScore.LEGACY_SCORE)
- val result: Parcelable? = networkScore.getExtension(KEY_DEFAULT_CAPABILITIES)
- assertEquals(null, result)
- assertEquals(0, networkScore.getIntExtension(NetworkScore.LEGACY_SCORE))
+ val exitingNs = ns.withExiting(true)
+ assertNotEquals(ns.isExiting, exitingNs.isExiting)
+ assertNotEquals(ns, exitingNs)
+ assertParcelSane(exitingNs, 7)
}
@Test
fun testEqualsNetworkScore() {
- val ns1 = NetworkScore()
- val ns2 = NetworkScore()
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
+ val builder1 = NetworkScore.Builder()
+ val builder2 = NetworkScore.Builder()
+ assertTrue(builder1.build().equals(builder2.build()))
+ assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
- ns1.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(NetworkScore.LEGACY_SCORE, TEST_SCORE)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- val defaultCap = NetworkCapabilities()
- ns1.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putExtension(KEY_DEFAULT_CAPABILITIES, defaultCap)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
-
- ns1.putIntExtension(null, 10)
- assertFalse(ns1.equals(ns2))
- assertNotEquals(ns1.hashCode(), ns2.hashCode())
- ns2.putIntExtension(null, 10)
- assertTrue(ns1.equals(ns2))
- assertEquals(ns1.hashCode(), ns2.hashCode())
+ builder1.setLegacyScore(TEST_SCORE)
+ assertFalse(builder1.build().equals(builder2.build()))
+ assertNotEquals(builder1.hashCode(), builder2.hashCode())
+ builder2.setLegacyScore(TEST_SCORE)
+ assertTrue(builder1.build().equals(builder2.build()))
+ assertEquals(builder1.build().hashCode(), builder2.build().hashCode())
}
}
diff --git a/tests/net/deflake/Android.bp b/tests/net/deflake/Android.bp
index 1c48c74..b1b0171 100644
--- a/tests/net/deflake/Android.bp
+++ b/tests/net/deflake/Android.bp
@@ -26,4 +26,5 @@
"net-host-tests-utils",
],
data: [":FrameworksNetTests"],
-}
\ No newline at end of file
+ test_suites: ["device-tests"],
+}
diff --git a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
index a35fb40..7ae9e95 100644
--- a/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
+++ b/tests/net/integration/util/com/android/server/NetworkAgentWrapper.java
@@ -40,6 +40,7 @@
import android.net.NetworkCapabilities;
import android.net.NetworkInfo;
import android.net.NetworkProvider;
+import android.net.NetworkScore;
import android.net.NetworkSpecifier;
import android.net.SocketKeepalive;
import android.net.UidRange;
@@ -155,9 +156,13 @@
}
}
+ private NetworkScore makeNetworkScore(final int legacyScore) {
+ return new NetworkScore.Builder().setLegacyScore(legacyScore).build();
+ }
+
public void adjustScore(int change) {
mScore += change;
- mNetworkAgent.sendNetworkScore(mScore);
+ mNetworkAgent.sendNetworkScore(makeNetworkScore(mScore));
}
public int getScore() {
diff --git a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
index 7ab4b56..2d5df4f 100644
--- a/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
+++ b/tests/net/java/android/net/ConnectivityDiagnosticsManagerTest.java
@@ -27,12 +27,18 @@
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import android.content.Context;
import android.os.PersistableBundle;
+import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -52,15 +58,27 @@
private static final Executor INLINE_EXECUTOR = x -> x.run();
+ @Mock private Context mContext;
+ @Mock private IConnectivityManager mService;
@Mock private ConnectivityDiagnosticsCallback mCb;
private ConnectivityDiagnosticsBinder mBinder;
+ private ConnectivityDiagnosticsManager mManager;
@Before
public void setUp() {
+ mContext = mock(Context.class);
+ mService = mock(IConnectivityManager.class);
mCb = mock(ConnectivityDiagnosticsCallback.class);
mBinder = new ConnectivityDiagnosticsBinder(mCb, INLINE_EXECUTOR);
+ mManager = new ConnectivityDiagnosticsManager(mContext, mService);
+ }
+
+ @After
+ public void tearDown() {
+ // clear ConnectivityDiagnosticsManager callbacks map
+ ConnectivityDiagnosticsManager.sCallbacks.clear();
}
private ConnectivityReport createSampleConnectivityReport() {
@@ -245,4 +263,53 @@
// latch without waiting.
verify(mCb).onNetworkConnectivityReported(eq(n), eq(connectivity));
}
+
+ @Test
+ public void testRegisterConnectivityDiagnosticsCallback() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+
+ mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
+
+ verify(mService).registerConnectivityDiagnosticsCallback(
+ any(ConnectivityDiagnosticsBinder.class), eq(request));
+ assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
+ }
+
+ @Test
+ public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+
+ mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
+
+ try {
+ mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
+ fail("Duplicate callback registration should fail");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testUnregisterConnectivityDiagnosticsCallback() throws Exception {
+ final NetworkRequest request = new NetworkRequest.Builder().build();
+ mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
+
+ mManager.unregisterConnectivityDiagnosticsCallback(mCb);
+
+ verify(mService).unregisterConnectivityDiagnosticsCallback(
+ any(ConnectivityDiagnosticsBinder.class));
+ assertFalse(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
+
+ // verify that re-registering is successful
+ mManager.registerConnectivityDiagnosticsCallback(request, INLINE_EXECUTOR, mCb);
+ verify(mService, times(2)).registerConnectivityDiagnosticsCallback(
+ any(ConnectivityDiagnosticsBinder.class), eq(request));
+ assertTrue(ConnectivityDiagnosticsManager.sCallbacks.containsKey(mCb));
+ }
+
+ @Test
+ public void testUnregisterUnknownConnectivityDiagnosticsCallback() throws Exception {
+ mManager.unregisterConnectivityDiagnosticsCallback(mCb);
+
+ verifyNoMoreInteractions(mService);
+ }
}
diff --git a/tests/net/java/com/android/server/ConnectivityServiceTest.java b/tests/net/java/com/android/server/ConnectivityServiceTest.java
index a0a1352..5592cd7 100644
--- a/tests/net/java/com/android/server/ConnectivityServiceTest.java
+++ b/tests/net/java/com/android/server/ConnectivityServiceTest.java
@@ -139,6 +139,7 @@
import android.net.ConnectivityManager.PacketKeepaliveCallback;
import android.net.ConnectivityManager.TooManyRequestsException;
import android.net.ConnectivityThread;
+import android.net.IConnectivityDiagnosticsCallback;
import android.net.IDnsResolver;
import android.net.IIpConnectivityMetrics;
import android.net.INetd;
@@ -180,6 +181,7 @@
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.HandlerThread;
+import android.os.IBinder;
import android.os.INetworkManagementService;
import android.os.Looper;
import android.os.Parcel;
@@ -210,6 +212,7 @@
import com.android.internal.util.WakeupMessage;
import com.android.internal.util.test.BroadcastInterceptingContext;
import com.android.internal.util.test.FakeSettingsProvider;
+import com.android.server.ConnectivityService.ConnectivityDiagnosticsCallbackInfo;
import com.android.server.connectivity.ConnectivityConstants;
import com.android.server.connectivity.DefaultNetworkMetrics;
import com.android.server.connectivity.IpConnectivityMetrics;
@@ -322,6 +325,8 @@
@Mock UserManager mUserManager;
@Mock NotificationManager mNotificationManager;
@Mock AlarmManager mAlarmManager;
+ @Mock IConnectivityDiagnosticsCallback mConnectivityDiagnosticsCallback;
+ @Mock IBinder mIBinder;
private ArgumentCaptor<ResolverParamsParcel> mResolverParamsParcelCaptor =
ArgumentCaptor.forClass(ResolverParamsParcel.class);
@@ -6355,4 +6360,70 @@
UserHandle.getAppId(uid));
return packageInfo;
}
+
+ @Test
+ public void testRegisterConnectivityDiagnosticsCallbackInvalidRequest() throws Exception {
+ final NetworkRequest request =
+ new NetworkRequest(
+ new NetworkCapabilities(), TYPE_ETHERNET, 0, NetworkRequest.Type.NONE);
+ try {
+ mService.registerConnectivityDiagnosticsCallback(
+ mConnectivityDiagnosticsCallback, request);
+ fail("registerConnectivityDiagnosticsCallback should throw on invalid NetworkRequest");
+ } catch (IllegalArgumentException expected) {
+ }
+ }
+
+ @Test
+ public void testRegisterUnregisterConnectivityDiagnosticsCallback() throws Exception {
+ final NetworkRequest wifiRequest =
+ new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
+
+ when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
+
+ mService.registerConnectivityDiagnosticsCallback(
+ mConnectivityDiagnosticsCallback, wifiRequest);
+
+ verify(mIBinder, timeout(TIMEOUT_MS))
+ .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ assertTrue(
+ mService.mConnectivityDiagnosticsCallbacks.containsKey(
+ mConnectivityDiagnosticsCallback));
+
+ mService.unregisterConnectivityDiagnosticsCallback(mConnectivityDiagnosticsCallback);
+ verify(mIBinder, timeout(TIMEOUT_MS))
+ .unlinkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ assertFalse(
+ mService.mConnectivityDiagnosticsCallbacks.containsKey(
+ mConnectivityDiagnosticsCallback));
+ verify(mConnectivityDiagnosticsCallback, atLeastOnce()).asBinder();
+ }
+
+ @Test
+ public void testRegisterDuplicateConnectivityDiagnosticsCallback() throws Exception {
+ final NetworkRequest wifiRequest =
+ new NetworkRequest.Builder().addTransportType(TRANSPORT_WIFI).build();
+ when(mConnectivityDiagnosticsCallback.asBinder()).thenReturn(mIBinder);
+
+ mService.registerConnectivityDiagnosticsCallback(
+ mConnectivityDiagnosticsCallback, wifiRequest);
+
+ verify(mIBinder, timeout(TIMEOUT_MS))
+ .linkToDeath(any(ConnectivityDiagnosticsCallbackInfo.class), anyInt());
+ verify(mConnectivityDiagnosticsCallback).asBinder();
+ assertTrue(
+ mService.mConnectivityDiagnosticsCallbacks.containsKey(
+ mConnectivityDiagnosticsCallback));
+
+ // Register the same callback again
+ mService.registerConnectivityDiagnosticsCallback(
+ mConnectivityDiagnosticsCallback, wifiRequest);
+
+ // Block until all other events are done processing.
+ HandlerUtilsKt.waitForIdle(mCsHandlerThread, TIMEOUT_MS);
+
+ assertTrue(
+ mService.mConnectivityDiagnosticsCallbacks.containsKey(
+ mConnectivityDiagnosticsCallback));
+ }
}
diff --git a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
index e863266..25e9057 100644
--- a/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
+++ b/tests/net/java/com/android/server/connectivity/LingerMonitorTest.java
@@ -353,8 +353,7 @@
NetworkCapabilities caps = new NetworkCapabilities();
caps.addCapability(0);
caps.addTransportType(transport);
- NetworkScore ns = new NetworkScore();
- ns.putIntExtension(NetworkScore.LEGACY_SCORE, 50);
+ NetworkScore ns = new NetworkScore.Builder().setLegacyScore(50).build();
NetworkAgentInfo nai = new NetworkAgentInfo(null, null, new Network(netId), info, null,
caps, ns, mCtx, null, null /* config */, mConnService, mNetd, mDnsResolver, mNMS,
NetworkProvider.ID_NONE);
diff --git a/tools/hiddenapi/Android.bp b/tools/hiddenapi/Android.bp
new file mode 100644
index 0000000..e0eb06cb
--- /dev/null
+++ b/tools/hiddenapi/Android.bp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+python_binary_host {
+ name: "merge_csv",
+ main: "merge_csv.py",
+ srcs: ["merge_csv.py"],
+ version: {
+ py2: {
+ enabled: false,
+ },
+ py3: {
+ enabled: true,
+ embedded_launcher: true
+ },
+ },
+}
diff --git a/tools/hiddenapi/merge_csv.py b/tools/hiddenapi/merge_csv.py
index 48c0755..9661927 100755
--- a/tools/hiddenapi/merge_csv.py
+++ b/tools/hiddenapi/merge_csv.py
@@ -21,20 +21,19 @@
import sys
csv_readers = [
- csv.DictReader(open(csv_file, 'rb'), delimiter=',', quotechar='|')
+ csv.DictReader(open(csv_file, 'r'), delimiter=',', quotechar='|')
for csv_file in sys.argv[1:]
]
# Build union of all columns from source files:
headers = set()
for reader in csv_readers:
- headers = headers.union(reader.fieldnames)
+ headers = headers.union(reader.fieldnames)
# Concatenate all files to output:
-out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', fieldnames = sorted(headers))
+out = csv.DictWriter(sys.stdout, delimiter=',', quotechar='|', quoting=csv.QUOTE_MINIMAL,
+ dialect='unix', fieldnames=sorted(headers))
out.writeheader()
for reader in csv_readers:
- for row in reader:
- out.writerow(row)
-
-
+ for row in reader:
+ out.writerow(row)
diff --git a/tools/stats_log_api_gen/java_writer_q.cpp b/tools/stats_log_api_gen/java_writer_q.cpp
index 1259a68..a68c3a2 100644
--- a/tools/stats_log_api_gen/java_writer_q.cpp
+++ b/tools/stats_log_api_gen/java_writer_q.cpp
@@ -577,6 +577,50 @@
}
}
+// This method is called in main.cpp to generate StatsLog for modules that's compatible with
+// Q at compile-time.
+int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
+ const AtomDecl &attributionDecl, const string& moduleName,
+ const string& javaClass, const string& javaPackage,
+ const bool supportWorkSource) {
+ // Print prelude
+ fprintf(out, "// This file is autogenerated\n");
+ fprintf(out, "\n");
+ fprintf(out, "package %s;\n", javaPackage.c_str());
+ fprintf(out, "\n");
+ fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
+ fprintf(out, "\n");
+ fprintf(out, "import android.util.StatsLog;\n");
+ fprintf(out, "import android.os.SystemClock;\n");
+ fprintf(out, "\n");
+ fprintf(out, "\n");
+ fprintf(out, "/**\n");
+ fprintf(out, " * Utility class for logging statistics events.\n");
+ fprintf(out, " */\n");
+ fprintf(out, "public class %s {\n", javaClass.c_str());
+
+ write_java_q_logging_constants(out, " ");
+
+ write_java_atom_codes(out, atoms, moduleName);
+
+ write_java_enum_values(out, atoms, moduleName);
+
+ int errors = 0;
+ // Print write methods
+ fprintf(out, " // Write methods\n");
+ errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
+ moduleName, " ");
+ errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
+ moduleName);
+ if (supportWorkSource) {
+ errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
+ }
+
+ fprintf(out, "}\n");
+
+ return errors;
+}
+
#if defined(STATS_SCHEMA_LEGACY)
static void write_java_method(
FILE* out,
@@ -639,48 +683,6 @@
return 0;
}
-
-int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
- const AtomDecl &attributionDecl, const string& moduleName,
- const string& javaClass, const string& javaPackage,
- const bool supportWorkSource) {
- // Print prelude
- fprintf(out, "// This file is autogenerated\n");
- fprintf(out, "\n");
- fprintf(out, "package %s;\n", javaPackage.c_str());
- fprintf(out, "\n");
- fprintf(out, "import static java.nio.charset.StandardCharsets.UTF_8;\n");
- fprintf(out, "\n");
- fprintf(out, "import android.util.StatsLog;\n");
- fprintf(out, "import android.os.SystemClock;\n");
- fprintf(out, "\n");
- fprintf(out, "\n");
- fprintf(out, "/**\n");
- fprintf(out, " * Utility class for logging statistics events.\n");
- fprintf(out, " */\n");
- fprintf(out, "public class %s {\n", javaClass.c_str());
-
- write_java_q_logging_constants(out, " ");
-
- write_java_atom_codes(out, atoms, moduleName);
-
- write_java_enum_values(out, atoms, moduleName);
-
- int errors = 0;
- // Print write methods
- fprintf(out, " // Write methods\n");
- errors += write_java_methods_q_schema(out, atoms.signatures_to_modules, attributionDecl,
- moduleName, " ");
- errors += write_java_non_chained_methods(out, atoms.non_chained_signatures_to_modules,
- moduleName);
- if (supportWorkSource) {
- errors += write_java_work_source_methods(out, atoms.signatures_to_modules, moduleName);
- }
-
- fprintf(out, "}\n");
-
- return errors;
-}
#endif
} // namespace stats_log_api_gen
diff --git a/tools/stats_log_api_gen/java_writer_q.h b/tools/stats_log_api_gen/java_writer_q.h
index 36df1d8..7d734df 100644
--- a/tools/stats_log_api_gen/java_writer_q.h
+++ b/tools/stats_log_api_gen/java_writer_q.h
@@ -45,13 +45,13 @@
const int requiredHelpers,
const string& indent);
-#if defined(STATS_SCHEMA_LEGACY)
-int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
- const bool supportWorkSource);
-
int write_stats_log_java_q_for_module(FILE* out, const Atoms& atoms,
const AtomDecl &attributionDecl, const string& moduleName, const string& javaClass,
const string& javaPackage, const bool supportWorkSource);
+
+#if defined(STATS_SCHEMA_LEGACY)
+int write_stats_log_java_q(FILE* out, const Atoms& atoms, const AtomDecl &attributionDecl,
+ const bool supportWorkSource);
#endif
} // namespace stats_log_api_gen
} // namespace android
diff --git a/tools/stats_log_api_gen/main.cpp b/tools/stats_log_api_gen/main.cpp
index 6089532..ddbf22c 100644
--- a/tools/stats_log_api_gen/main.cpp
+++ b/tools/stats_log_api_gen/main.cpp
@@ -511,8 +511,10 @@
fprintf(stderr, " --javaClass CLASS the class name of the java class.\n");
fprintf(stderr, " Optional for Java with module.\n");
fprintf(stderr, " Default is \"StatsLogInternal\"\n");
- fprintf(stderr, " --supportQ Include support for Android Q.\n");
+ fprintf(stderr, " --supportQ Include runtime support for Android Q.\n");
fprintf(stderr, " --worksource Include support for logging WorkSource objects.\n");
+ fprintf(stderr, " --compileQ Include compile-time support for Android Q "
+ "(Java only).\n");
}
/**
@@ -536,6 +538,7 @@
string javaClass = DEFAULT_JAVA_CLASS;
bool supportQ = false;
bool supportWorkSource = false;
+ bool compileQ = false;
int index = 1;
while (index < argc) {
@@ -630,6 +633,8 @@
supportQ = true;
} else if (0 == strcmp("--worksource", argv[index])) {
supportWorkSource = true;
+ } else if (0 == strcmp("--compileQ", argv[index])) {
+ compileQ = true;
}
index++;
@@ -645,12 +650,18 @@
return 1;
}
- if (DEFAULT_MODULE_NAME == moduleName && supportQ) {
+ if (DEFAULT_MODULE_NAME == moduleName && (supportQ || compileQ)) {
// Support for Q schema is not needed for default module.
fprintf(stderr, "%s cannot support Q schema\n", moduleName.c_str());
return 1;
}
+ if (supportQ && compileQ) {
+ // Runtime Q support is redundant if compile-time Q support is required.
+ fprintf(stderr, "Cannot specify compileQ and supportQ simultaneously.\n");
+ return 1;
+ }
+
// Collate the parameters
Atoms atoms;
int errorCount = collate_atoms(Atom::descriptor(), &atoms);
@@ -748,9 +759,15 @@
javaClass = "StatsLogInternal";
javaPackage = "android.util";
}
- errorCount = android::stats_log_api_gen::write_stats_log_java(
- out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
- supportWorkSource);
+ if (compileQ) {
+ errorCount = android::stats_log_api_gen::write_stats_log_java_q_for_module(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage,
+ supportWorkSource);
+ } else {
+ errorCount = android::stats_log_api_gen::write_stats_log_java(
+ out, atoms, attributionDecl, moduleName, javaClass, javaPackage, supportQ,
+ supportWorkSource);
+ }
#endif
fclose(out);
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index 0ef224a..8d95cb0 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -373,6 +373,7 @@
* ECDHE_ECDSA
* ECDHE_RSA
* </pre>
+ * @hide
*/
public static class SuiteBCipher {
private SuiteBCipher() { }
@@ -715,8 +716,8 @@
public BitSet allowedGroupManagementCiphers;
/**
* The set of SuiteB ciphers supported by this configuration.
- * To be used for WPA3-Enterprise mode.
- * See {@link SuiteBCipher} for descriptions of the values.
+ * To be used for WPA3-Enterprise mode. Set automatically by the framework based on the
+ * certificate type that is used in this configuration.
*/
@NonNull
public BitSet allowedSuiteBCiphers;
@@ -1929,54 +1930,38 @@
private NetworkSelectionStatus mNetworkSelectionStatus = new NetworkSelectionStatus();
/**
- * @hide
* This class is intended to store extra failure reason information for the most recent
* connection attempt, so that it may be surfaced to the settings UI
+ * @hide
*/
- @SystemApi
+ // TODO(b/148626966): called by SUW via reflection, remove once SUW is updated
public static class RecentFailure {
private RecentFailure() {}
- /** @hide */
- @Retention(RetentionPolicy.SOURCE)
- @IntDef(value = {NONE, STATUS_AP_UNABLE_TO_HANDLE_NEW_STA})
- public @interface AssociationStatus {}
-
- /**
- * No recent failure, or no specific reason given for the recent connection failure
- */
- public static final int NONE = 0;
- /**
- * Connection to this network recently failed due to Association Rejection Status 17
- * (AP is full)
- */
- public static final int STATUS_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
/**
* Association Rejection Status code (NONE for success/non-association-rejection-fail)
*/
- @AssociationStatus
- private int mAssociationStatus = NONE;
+ @RecentFailureReason
+ private int mAssociationStatus = RECENT_FAILURE_NONE;
/**
* @param status the association status code for the recent failure
- * @hide
*/
- public void setAssociationStatus(@AssociationStatus int status) {
+ public void setAssociationStatus(@RecentFailureReason int status) {
mAssociationStatus = status;
}
/**
* Sets the RecentFailure to NONE
- * @hide
*/
public void clear() {
- mAssociationStatus = NONE;
+ mAssociationStatus = RECENT_FAILURE_NONE;
}
/**
- * Get the recent failure code. One of {@link #NONE} or
- * {@link #STATUS_AP_UNABLE_TO_HANDLE_NEW_STA}.
+ * Get the recent failure code. One of {@link #RECENT_FAILURE_NONE} or
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}.
*/
- @AssociationStatus
+ @RecentFailureReason
public int getAssociationStatus() {
return mAssociationStatus;
}
@@ -1986,10 +1971,47 @@
* RecentFailure member
* @hide
*/
+ // TODO(b/148626966): called by SUW via reflection, once SUW is updated, make private and
+ // rename to mRecentFailure
@NonNull
- @SystemApi
public final RecentFailure recentFailure = new RecentFailure();
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = "RECENT_FAILURE_", value = {
+ RECENT_FAILURE_NONE,
+ RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA})
+ public @interface RecentFailureReason {}
+
+ /**
+ * No recent failure, or no specific reason given for the recent connection failure
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_NONE = 0;
+ /**
+ * Connection to this network recently failed due to Association Rejection Status 17
+ * (AP is full)
+ * @hide
+ */
+ @SystemApi
+ public static final int RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA = 17;
+
+ /**
+ * Get the failure reason for the most recent connection attempt, or
+ * {@link #RECENT_FAILURE_NONE} if there was no failure.
+ *
+ * Failure reasons include:
+ * {@link #RECENT_FAILURE_AP_UNABLE_TO_HANDLE_NEW_STA}
+ *
+ * @hide
+ */
+ @RecentFailureReason
+ @SystemApi
+ public int getRecentFailureReason() {
+ return recentFailure.getAssociationStatus();
+ }
+
/**
* Get the network selection status.
* @hide
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index 6f01350..8250a95 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -836,6 +836,8 @@
* Enable/Disable wifi scanning.
*
* @param enable set to true to enable scanning, set to false to disable all types of scanning.
+ *
+ * @see WifiManager#ACTION_WIFI_SCAN_AVAILABLE
* {@hide}
*/
@SystemApi
diff --git a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
index 3a0d080..756d679 100644
--- a/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
+++ b/wifi/java/android/net/wifi/hotspot2/PasspointConfiguration.java
@@ -19,6 +19,7 @@
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
import static android.net.wifi.WifiConfiguration.MeteredOverride;
+import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.net.wifi.hotspot2.pps.Credential;
@@ -895,4 +896,18 @@
public boolean isOsuProvisioned() {
return getUpdateIdentifier() != Integer.MIN_VALUE;
}
+
+ /**
+ * Get a unique identifier for a PasspointConfiguration object.
+ *
+ * @return A unique identifier
+ * @throws IllegalStateException if Credential or HomeSP nodes are not initialized
+ */
+ public @NonNull String getUniqueId() throws IllegalStateException {
+ if (mCredential == null || mHomeSp == null || TextUtils.isEmpty(mHomeSp.getFqdn())) {
+ throw new IllegalStateException("Credential or HomeSP are not initialized");
+ }
+
+ return mHomeSp.getFqdn();
+ }
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
index 9562f95..36c7213 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pConfig.java
@@ -137,12 +137,12 @@
/** @hide */
@UnsupportedAppUsage
- public int netId = WifiP2pGroup.PERSISTENT_NET_ID;
+ public int netId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
/**
* Get the network ID of this P2P configuration.
- * @return either a non-negative network ID, or one of {@link WifiP2pGroup#PERSISTENT_NET_ID} or
- * {@link WifiP2pGroup#TEMPORARY_NET_ID}.
+ * @return either a non-negative network ID, or one of
+ * {@link WifiP2pGroup#NETWORK_ID_PERSISTENT} or {@link WifiP2pGroup#NETWORK_ID_TEMPORARY}.
*/
public int getNetworkId() {
return netId;
@@ -280,7 +280,7 @@
private String mPassphrase = "";
private int mGroupOperatingBand = GROUP_OWNER_BAND_AUTO;
private int mGroupOperatingFrequency = GROUP_OWNER_BAND_AUTO;
- private int mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ private int mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
/**
* Specify the peer's MAC address. If not set, the device will
@@ -460,9 +460,9 @@
*/
public @NonNull Builder enablePersistentMode(boolean persistent) {
if (persistent) {
- mNetId = WifiP2pGroup.PERSISTENT_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_PERSISTENT;
} else {
- mNetId = WifiP2pGroup.TEMPORARY_NET_ID;
+ mNetId = WifiP2pGroup.NETWORK_ID_TEMPORARY;
}
return this;
}
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
index 21f6704..e497b22 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pGroup.java
@@ -41,7 +41,15 @@
* The temporary network id.
* @see #getNetworkId()
*/
- public static final int TEMPORARY_NET_ID = -1;
+ public static final int NETWORK_ID_TEMPORARY = -1;
+
+ /**
+ * The temporary network id.
+ *
+ * @hide
+ */
+ @UnsupportedAppUsage
+ public static final int TEMPORARY_NET_ID = NETWORK_ID_TEMPORARY;
/**
* The persistent network id.
@@ -49,7 +57,7 @@
* Otherwise, create a new persistent profile.
* @see #getNetworkId()
*/
- public static final int PERSISTENT_NET_ID = -2;
+ public static final int NETWORK_ID_PERSISTENT = -2;
/** The network name */
private String mNetworkName;
@@ -130,13 +138,13 @@
mPassphrase = match.group(4);
mOwner = new WifiP2pDevice(match.group(5));
if (match.group(6) != null) {
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
} else {
- mNetId = TEMPORARY_NET_ID;
+ mNetId = NETWORK_ID_TEMPORARY;
}
} else if (tokens[0].equals("P2P-INVITATION-RECEIVED")) {
String sa = null;
- mNetId = PERSISTENT_NET_ID;
+ mNetId = NETWORK_ID_PERSISTENT;
for (String token : tokens) {
String[] nameValue = token.split("=");
if (nameValue.length != 2) continue;
diff --git a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
index 3459c94..0fe0675 100644
--- a/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
+++ b/wifi/java/android/net/wifi/p2p/WifiP2pManager.java
@@ -1293,7 +1293,7 @@
@RequiresPermission(android.Manifest.permission.ACCESS_FINE_LOCATION)
public void createGroup(Channel c, ActionListener listener) {
checkChannel(c);
- c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.PERSISTENT_NET_ID,
+ c.mAsyncChannel.sendMessage(CREATE_GROUP, WifiP2pGroup.NETWORK_ID_PERSISTENT,
c.putListener(listener));
}
diff --git a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
index 654154d..e78c5bf 100644
--- a/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
+++ b/wifi/tests/src/android/net/wifi/hotspot2/PasspointConfigurationTest.java
@@ -18,6 +18,7 @@
import static android.net.wifi.WifiConfiguration.METERED_OVERRIDE_NONE;
+import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
@@ -364,4 +365,54 @@
assertTrue(config.validateForR2());
assertTrue(config.isOsuProvisioned());
}
+
+ /**
+ * Verify that the unique identifier generated is correct.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueId() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ String uniqueId;
+ uniqueId = config.getUniqueId();
+ assertEquals(uniqueId, config.getHomeSp().getFqdn());
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if HomeSP is not initialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdExceptionWithEmptyHomeSp() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setHomeSp(null);
+ boolean exceptionCaught = false;
+ try {
+ String uniqueId = config.getUniqueId();
+ } catch (IllegalStateException e) {
+ exceptionCaught = true;
+ }
+ assertTrue(exceptionCaught);
+ }
+
+ /**
+ * Verify that the unique identifier API generates an exception if Credential is not
+ * initialized.
+ *
+ * @throws Exception
+ */
+ @Test
+ public void validateUniqueIdExceptionWithEmptyCredential() throws Exception {
+ PasspointConfiguration config = PasspointTestUtils.createConfig();
+ config.setCredential(null);
+ boolean exceptionCaught = false;
+ try {
+ String uniqueId = config.getUniqueId();
+ } catch (IllegalStateException e) {
+ exceptionCaught = true;
+ }
+ assertTrue(exceptionCaught);
+ }
}