Merge "Tweak buffer size for APK checksumming."
diff --git a/core/api/current.txt b/core/api/current.txt
index a0a46a2..82e2c21 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -1194,6 +1194,7 @@
field public static final int requiredFeature = 16844116; // 0x1010554
field public static final int requiredForAllUsers = 16843728; // 0x10103d0
field public static final int requiredNotFeature = 16844117; // 0x1010555
+ field public static final int requiredSplitTypes;
field public static final int requiresFadingEdge = 16843685; // 0x10103a5
field public static final int requiresSmallestWidthDp = 16843620; // 0x1010364
field public static final int resizeClip = 16843983; // 0x10104cf
@@ -1329,6 +1330,7 @@
field public static final int splitMotionEvents = 16843503; // 0x10102ef
field public static final int splitName = 16844105; // 0x1010549
field public static final int splitTrack = 16843852; // 0x101044c
+ field public static final int splitTypes;
field public static final int spotShadowAlpha = 16843967; // 0x10104bf
field public static final int src = 16843033; // 0x1010119
field public static final int ssp = 16843747; // 0x10103e3
diff --git a/core/java/android/content/pm/parsing/ApkLite.java b/core/java/android/content/pm/parsing/ApkLite.java
index 024c18c..49d4137 100644
--- a/core/java/android/content/pm/parsing/ApkLite.java
+++ b/core/java/android/content/pm/parsing/ApkLite.java
@@ -19,12 +19,15 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
import android.content.pm.SigningDetails;
import android.content.pm.VerifierInfo;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import java.util.List;
+import java.util.Set;
/**
* Lightweight parsed details about a single APK file.
@@ -44,6 +47,10 @@
private final @Nullable String mUsesSplitName;
/** Name of the split APK that this APK is a configuration for */
private final @Nullable String mConfigForSplit;
+ /** Indicate the types of the required split are necessary for this package to run */
+ private final @Nullable Set<String> mRequiredSplitTypes;
+ /** Split types of this APK */
+ private final @Nullable Set<String> mSplitTypes;
/** Major version number of this package */
private final int mVersionCodeMajor;
@@ -105,9 +112,9 @@
/**
* Indicate the policy to deal with user data when rollback is committed
*
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE}
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE}
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN}
*/
private final int mRollbackDataPolicy;
@@ -118,14 +125,17 @@
boolean debuggable, boolean profileableByShell, boolean multiArch, boolean use32bitAbi,
boolean useEmbeddedDex, boolean extractNativeLibs, boolean isolatedSplits,
String targetPackageName, boolean overlayIsStatic, int overlayPriority,
- int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy) {
+ int minSdkVersion, int targetSdkVersion, int rollbackDataPolicy,
+ Set<String> requiredSplitTypes, Set<String> splitTypes) {
mPath = path;
mPackageName = packageName;
mSplitName = splitName;
+ mSplitTypes = splitTypes;
mFeatureSplit = isFeatureSplit;
mConfigForSplit = configForSplit;
mUsesSplitName = usesSplitName;
- mSplitRequired = isSplitRequired;
+ mRequiredSplitTypes = requiredSplitTypes;
+ mSplitRequired = (isSplitRequired || hasAnyRequiredSplitTypes());
mVersionCode = versionCode;
mVersionCodeMajor = versionCodeMajor;
mRevisionCode = revisionCode;
@@ -156,9 +166,16 @@
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
}
+ /**
+ * Return if requiredSplitTypes presents.
+ */
+ private boolean hasAnyRequiredSplitTypes() {
+ return !CollectionUtils.isEmpty(mRequiredSplitTypes);
+ }
- // Code below generated by codegen v1.0.22.
+
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -212,6 +229,22 @@
}
/**
+ * Indicate the types of the required split are necessary for this package to run
+ */
+ @DataClass.Generated.Member
+ public @Nullable Set<String> getRequiredSplitTypes() {
+ return mRequiredSplitTypes;
+ }
+
+ /**
+ * Split types of this APK
+ */
+ @DataClass.Generated.Member
+ public @Nullable Set<String> getSplitTypes() {
+ return mSplitTypes;
+ }
+
+ /**
* Major version number of this package
*/
@DataClass.Generated.Member
@@ -388,9 +421,9 @@
/**
* Indicate the policy to deal with user data when rollback is committed
*
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RESTORE}
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#WIPE}
- * @see {@link android.content.pm.PackageManager.RollbackDataPolicy#RETAIN}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RESTORE}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_WIPE}
+ * @see {@link PackageManager#ROLLBACK_DATA_POLICY_RETAIN}
*/
@DataClass.Generated.Member
public int getRollbackDataPolicy() {
@@ -398,10 +431,10 @@
}
@DataClass.Generated(
- time = 1616985847981L,
- codegenVersion = "1.0.22",
+ time = 1628562554893L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/ApkLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final int mRollbackDataPolicy\npublic long getLongVersionCode()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.Nullable java.lang.String mSplitName\nprivate final @android.annotation.Nullable java.lang.String mUsesSplitName\nprivate final @android.annotation.Nullable java.lang.String mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mRevisionCode\nprivate final int mInstallLocation\nprivate final int mMinSdkVersion\nprivate final int mTargetSdkVersion\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.NonNull android.content.pm.SigningDetails mSigningDetails\nprivate final boolean mFeatureSplit\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mProfileableByShell\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mUseEmbeddedDex\nprivate final @android.annotation.Nullable java.lang.String mTargetPackageName\nprivate final boolean mOverlayIsStatic\nprivate final int mOverlayPriority\nprivate final int mRollbackDataPolicy\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass ApkLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
index f727a48..d3b6f2b 100644
--- a/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkLiteParseUtils.java
@@ -38,6 +38,7 @@
import android.os.Trace;
import android.text.TextUtils;
import android.util.ArrayMap;
+import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Pair;
import android.util.Slog;
@@ -58,6 +59,7 @@
import java.util.Comparator;
import java.util.List;
import java.util.Objects;
+import java.util.Set;
/** @hide */
public class ApkLiteParseUtils {
@@ -104,8 +106,11 @@
final ApkLite baseApk = result.getResult();
final String packagePath = packageFile.getAbsolutePath();
return input.success(
- new PackageLite(packagePath, baseApk.getPath(), baseApk, null,
- null, null, null, null, null, baseApk.getTargetSdkVersion()));
+ new PackageLite(packagePath, baseApk.getPath(), baseApk, null /* splitNames */,
+ null /* isFeatureSplits */, null /* usesSplitNames */,
+ null /* configForSplit */, null /* splitApkPaths */,
+ null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
+ null /* requiredSplitTypes */, null /* splitTypes */));
} finally {
Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
}
@@ -209,6 +214,8 @@
final int size = ArrayUtils.size(splitApks);
String[] splitNames = null;
+ Set<String>[] requiredSplitTypes = null;
+ Set<String>[] splitTypes = null;
boolean[] isFeatureSplits = null;
String[] usesSplitNames = null;
String[] configForSplits = null;
@@ -216,6 +223,8 @@
int[] splitRevisionCodes = null;
if (size > 0) {
splitNames = new String[size];
+ requiredSplitTypes = new Set[size];
+ splitTypes = new Set[size];
isFeatureSplits = new boolean[size];
usesSplitNames = new String[size];
configForSplits = new String[size];
@@ -227,6 +236,8 @@
for (int i = 0; i < size; i++) {
final ApkLite apk = splitApks.get(splitNames[i]);
+ requiredSplitTypes[i] = apk.getRequiredSplitTypes();
+ splitTypes[i] = apk.getSplitTypes();
usesSplitNames[i] = apk.getUsesSplitName();
isFeatureSplits[i] = apk.isFeatureSplit();
configForSplits[i] = apk.getConfigForSplit();
@@ -242,7 +253,7 @@
return input.success(
new PackageLite(codePath, baseCodePath, baseApk, splitNames, isFeatureSplits,
usesSplitNames, configForSplits, splitCodePaths, splitRevisionCodes,
- baseApk.getTargetSdkVersion()));
+ baseApk.getTargetSdkVersion(), requiredSplitTypes, splitTypes));
}
/**
@@ -345,9 +356,15 @@
if (result.isError()) {
return input.error(result);
}
-
Pair<String, String> packageSplit = result.getResult();
+ final ParseResult<Pair<Set<String>, Set<String>>> requiredSplitTypesResult =
+ parseRequiredSplitTypes(input, parser);
+ if (requiredSplitTypesResult.isError()) {
+ return input.error(result);
+ }
+ Pair<Set<String>, Set<String>> requiredSplitTypes = requiredSplitTypesResult.getResult();
+
int installLocation = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE,
"installLocation", PARSE_DEFAULT_INSTALL_LOCATION);
int versionCode = parser.getAttributeIntValue(ANDROID_RES_NAMESPACE, "versionCode", 0);
@@ -522,7 +539,7 @@
coreApp, debuggable, profilableByShell, multiArch, use32bitAbi,
useEmbeddedDex, extractNativeLibs, isolatedSplits, targetPackage,
overlayIsStatic, overlayPriority, minSdkVersion, targetSdkVersion,
- rollbackDataPolicy));
+ rollbackDataPolicy, requiredSplitTypes.first, requiredSplitTypes.second));
}
public static ParseResult<Pair<String, String>> parsePackageSplitNames(ParseInput input,
@@ -567,6 +584,54 @@
(splitName != null) ? splitName.intern() : splitName));
}
+ /**
+ * Utility method that parses attributes android:requiredSplitTypes and android:splitTypes.
+ */
+ public static ParseResult<Pair<Set<String>, Set<String>>> parseRequiredSplitTypes(
+ ParseInput input, XmlResourceParser parser) {
+ Set<String> requiredSplitTypes = null;
+ Set<String> splitTypes = null;
+ String value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "requiredSplitTypes");
+ if (!TextUtils.isEmpty(value)) {
+ final ParseResult<Set<String>> result = separateAndValidateSplitTypes(input, value);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ requiredSplitTypes = result.getResult();
+ }
+
+ value = parser.getAttributeValue(ANDROID_RES_NAMESPACE, "splitTypes");
+ if (!TextUtils.isEmpty(value)) {
+ final ParseResult<Set<String>> result = separateAndValidateSplitTypes(input, value);
+ if (result.isError()) {
+ return input.error(result);
+ }
+ splitTypes = result.getResult();
+ }
+
+ return input.success(Pair.create(requiredSplitTypes, splitTypes));
+ }
+
+ private static ParseResult<Set<String>> separateAndValidateSplitTypes(ParseInput input,
+ String values) {
+ final Set<String> ret = new ArraySet<>();
+ for (String value : values.trim().split(",")) {
+ final String type = value.trim();
+ // Using requireFilename as true because it limits length of the name to the
+ // {@link #MAX_FILE_NAME_SIZE}.
+ final ParseResult<?> nameResult = validateName(input, type,
+ false /* requireSeparator */, true /* requireFilename */);
+ if (nameResult.isError()) {
+ return input.error(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
+ "Invalid manifest split types: " + nameResult.getErrorMessage());
+ }
+ if (!ret.add(type)) {
+ Slog.w(TAG, type + " was defined multiple times");
+ }
+ }
+ return input.success(ret);
+ }
+
public static VerifierInfo parseVerifier(AttributeSet attrs) {
String packageName = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "name");
String encodedPublicKey = attrs.getAttributeValue(ANDROID_RES_NAMESPACE, "publicKey");
diff --git a/core/java/android/content/pm/parsing/PackageLite.java b/core/java/android/content/pm/parsing/PackageLite.java
index 9172555..5f5e812 100644
--- a/core/java/android/content/pm/parsing/PackageLite.java
+++ b/core/java/android/content/pm/parsing/PackageLite.java
@@ -22,11 +22,13 @@
import android.content.pm.VerifierInfo;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.DataClass;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
+import java.util.Set;
/**
* Lightweight parsed details about a single package.
@@ -52,6 +54,12 @@
/** Dependencies of any split APKs, ordered by parsed splitName */
private final @Nullable String[] mUsesSplitNames;
private final @Nullable String[] mConfigForSplit;
+ /** Indicate the types of the required split are necessary for base APK to run */
+ private final @Nullable Set<String> mBaseRequiredSplitTypes;
+ /** Indicate the types of the required split are necessary for split APKs to run */
+ private final @Nullable Set<String>[] mRequiredSplitTypes;
+ /** Split type of any split APKs, ordered by parsed splitName */
+ private final @Nullable Set<String>[] mSplitTypes;
/** Major and minor version number of this package */
private final int mVersionCodeMajor;
private final int mVersionCode;
@@ -101,7 +109,7 @@
public PackageLite(String path, String baseApkPath, ApkLite baseApk,
String[] splitNames, boolean[] isFeatureSplits, String[] usesSplitNames,
String[] configForSplit, String[] splitApkPaths, int[] splitRevisionCodes,
- int targetSdk) {
+ int targetSdk, Set<String>[] requiredSplitTypes, Set<String>[] splitTypes) {
// The following paths may be different from the path in ApkLite because we
// move or rename the APK files. Use parameters to indicate the correct paths.
mPath = path;
@@ -119,9 +127,12 @@
mExtractNativeLibs = baseApk.isExtractNativeLibs();
mIsolatedSplits = baseApk.isIsolatedSplits();
mUseEmbeddedDex = baseApk.isUseEmbeddedDex();
- mSplitRequired = baseApk.isSplitRequired();
+ mBaseRequiredSplitTypes = baseApk.getRequiredSplitTypes();
+ mRequiredSplitTypes = requiredSplitTypes;
+ mSplitRequired = (baseApk.isSplitRequired() || hasAnyRequiredSplitTypes());
mProfileableByShell = baseApk.isProfileableByShell();
mSplitNames = splitNames;
+ mSplitTypes = splitTypes;
mIsFeatureSplits = isFeatureSplits;
mUsesSplitNames = usesSplitNames;
mConfigForSplit = configForSplit;
@@ -150,9 +161,19 @@
return PackageInfo.composeLongVersionCode(mVersionCodeMajor, mVersionCode);
}
+ /**
+ * Return if requiredSplitTypes presents in the package.
+ */
+ private boolean hasAnyRequiredSplitTypes() {
+ if (!CollectionUtils.isEmpty(mBaseRequiredSplitTypes)) {
+ return true;
+ }
+ return ArrayUtils.find(mRequiredSplitTypes, r -> !CollectionUtils.isEmpty(r)) != null;
+ }
- // Code below generated by codegen v1.0.22.
+
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -221,6 +242,30 @@
}
/**
+ * Indicate the types of the required split are necessary for base APK to run
+ */
+ @DataClass.Generated.Member
+ public @Nullable Set<String> getBaseRequiredSplitTypes() {
+ return mBaseRequiredSplitTypes;
+ }
+
+ /**
+ * Indicate the types of the required split are necessary for split APKs to run
+ */
+ @DataClass.Generated.Member
+ public @Nullable Set<String>[] getRequiredSplitTypes() {
+ return mRequiredSplitTypes;
+ }
+
+ /**
+ * Split type of any split APKs, ordered by parsed splitName
+ */
+ @DataClass.Generated.Member
+ public @Nullable Set<String>[] getSplitTypes() {
+ return mSplitTypes;
+ }
+
+ /**
* Major and minor version number of this package
*/
@DataClass.Generated.Member
@@ -357,10 +402,10 @@
}
@DataClass.Generated(
- time = 1615914120261L,
- codegenVersion = "1.0.22",
+ time = 1628562559343L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/content/pm/parsing/PackageLite.java",
- inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
+ inputSignatures = "private final @android.annotation.NonNull java.lang.String mPackageName\nprivate final @android.annotation.NonNull java.lang.String mPath\nprivate final @android.annotation.NonNull java.lang.String mBaseApkPath\nprivate final @android.annotation.Nullable java.lang.String[] mSplitApkPaths\nprivate final @android.annotation.Nullable java.lang.String[] mSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mUsesSplitNames\nprivate final @android.annotation.Nullable java.lang.String[] mConfigForSplit\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String> mBaseRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mRequiredSplitTypes\nprivate final @android.annotation.Nullable java.util.Set<java.lang.String>[] mSplitTypes\nprivate final int mVersionCodeMajor\nprivate final int mVersionCode\nprivate final int mTargetSdk\nprivate final int mBaseRevisionCode\nprivate final @android.annotation.Nullable int[] mSplitRevisionCodes\nprivate final int mInstallLocation\nprivate final @android.annotation.NonNull android.content.pm.VerifierInfo[] mVerifiers\nprivate final @android.annotation.Nullable boolean[] mIsFeatureSplits\nprivate final boolean mIsolatedSplits\nprivate final boolean mSplitRequired\nprivate final boolean mCoreApp\nprivate final boolean mDebuggable\nprivate final boolean mMultiArch\nprivate final boolean mUse32bitAbi\nprivate final boolean mExtractNativeLibs\nprivate final boolean mProfileableByShell\nprivate final boolean mUseEmbeddedDex\npublic java.util.List<java.lang.String> getAllApkPaths()\npublic long getLongVersionCode()\nprivate boolean hasAnyRequiredSplitTypes()\nclass PackageLite extends java.lang.Object implements []\n@com.android.internal.util.DataClass(genConstructor=false, genConstDefs=false)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/android/content/pm/parsing/ParsingPackageUtils.java b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
index 80befcd..b9348a1 100644
--- a/core/java/android/content/pm/parsing/ParsingPackageUtils.java
+++ b/core/java/android/content/pm/parsing/ParsingPackageUtils.java
@@ -234,7 +234,7 @@
* For those names would be used as a part of the file name. Limits size to 223 and reserves 32
* for the OS.
*/
- private static final int MAX_FILE_NAME_SIZE = 223;
+ static final int MAX_FILE_NAME_SIZE = 223;
/**
* @see #parseDefault(ParseInput, File, int, List, boolean)
diff --git a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
index fc728a2..4708f3e 100644
--- a/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraDeviceImpl.java
@@ -104,6 +104,9 @@
private SparseArray<CaptureCallbackHolder> mCaptureCallbackMap =
new SparseArray<CaptureCallbackHolder>();
+ /** map request IDs which have batchedOutputs to requestCount*/
+ private HashMap<Integer, Integer> mBatchOutputMap = new HashMap<>();
+
private int mRepeatingRequestId = REQUEST_ID_NONE;
// Latest repeating request list's types
private int[] mRepeatingRequestTypes;
@@ -973,6 +976,7 @@
mConfiguredInput = new SimpleEntry<Integer, InputConfiguration>(REQUEST_ID_NONE, null);
mIdle = true;
mCaptureCallbackMap = new SparseArray<CaptureCallbackHolder>();
+ mBatchOutputMap = new HashMap<>();
mFrameNumberTracker = new FrameNumberTracker();
mCurrentSession.closeWithoutDraining();
@@ -1179,6 +1183,41 @@
return requestTypes;
}
+ private boolean hasBatchedOutputs(List<CaptureRequest> requestList) {
+ boolean hasBatchedOutputs = true;
+ for (int i = 0; i < requestList.size(); i++) {
+ CaptureRequest request = requestList.get(i);
+ if (!request.isPartOfCRequestList()) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ if (i == 0) {
+ Collection<Surface> targets = request.getTargets();
+ if (targets.size() != 2) {
+ hasBatchedOutputs = false;
+ break;
+ }
+ }
+ }
+ return hasBatchedOutputs;
+ }
+
+ private void updateTracker(int requestId, long frameNumber,
+ int requestType, CaptureResult result, boolean isPartialResult) {
+ int requestCount = 1;
+ // If the request has batchedOutputs update each frame within the batch.
+ if (mBatchOutputMap.containsKey(requestId)) {
+ requestCount = mBatchOutputMap.get(requestId);
+ for (int i = 0; i < requestCount; i++) {
+ mFrameNumberTracker.updateTracker(frameNumber - (requestCount - 1 - i),
+ result, isPartialResult, requestType);
+ }
+ } else {
+ mFrameNumberTracker.updateTracker(frameNumber, result,
+ isPartialResult, requestType);
+ }
+ }
+
private int submitCaptureRequest(List<CaptureRequest> requestList, CaptureCallback callback,
Executor executor, boolean repeating) throws CameraAccessException {
@@ -1224,6 +1263,14 @@
request.recoverStreamIdToSurface();
}
+ // If the request has batched outputs, then store the
+ // requestCount and requestId in the map.
+ boolean hasBatchedOutputs = hasBatchedOutputs(requestList);
+ if (hasBatchedOutputs) {
+ int requestCount = requestList.size();
+ mBatchOutputMap.put(requestInfo.getRequestId(), requestCount);
+ }
+
if (callback != null) {
mCaptureCallbackMap.put(requestInfo.getRequestId(),
new CaptureCallbackHolder(
@@ -1839,8 +1886,18 @@
if (DEBUG) {
Log.v(TAG, String.format("got error frame %d", frameNumber));
}
- mFrameNumberTracker.updateTracker(frameNumber,
- /*error*/true, request.getRequestType());
+
+ // Update FrameNumberTracker for every frame during HFR mode.
+ if (mBatchOutputMap.containsKey(requestId)) {
+ for (int i = 0; i < mBatchOutputMap.get(requestId); i++) {
+ mFrameNumberTracker.updateTracker(frameNumber - (subsequenceId - i),
+ /*error*/true, request.getRequestType());
+ }
+ } else {
+ mFrameNumberTracker.updateTracker(frameNumber,
+ /*error*/true, request.getRequestType());
+ }
+
checkAndFireSequenceComplete();
// Dispatch the failure callback
@@ -2023,7 +2080,6 @@
public void onResultReceived(CameraMetadataNative result,
CaptureResultExtras resultExtras, PhysicalCaptureResultInfo physicalResults[])
throws RemoteException {
-
int requestId = resultExtras.getRequestId();
long frameNumber = resultExtras.getFrameNumber();
@@ -2064,8 +2120,8 @@
+ frameNumber);
}
- mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
- requestType);
+ updateTracker(requestId, frameNumber, requestType, /*result*/null,
+ isPartialResult);
return;
}
@@ -2077,8 +2133,9 @@
+ frameNumber);
}
- mFrameNumberTracker.updateTracker(frameNumber, /*result*/null, isPartialResult,
- requestType);
+ updateTracker(requestId, frameNumber, requestType, /*result*/null,
+ isPartialResult);
+
return;
}
@@ -2184,9 +2241,7 @@
Binder.restoreCallingIdentity(ident);
}
- // Collect the partials for a total result; or mark the frame as totally completed
- mFrameNumberTracker.updateTracker(frameNumber, finalResult, isPartialResult,
- requestType);
+ updateTracker(requestId, frameNumber, requestType, finalResult, isPartialResult);
// Fire onCaptureSequenceCompleted
if (!isPartialResult) {
diff --git a/core/java/android/inputmethodservice/RemoteInputConnection.java b/core/java/android/inputmethodservice/RemoteInputConnection.java
index ec5bcf1..464b421 100644
--- a/core/java/android/inputmethodservice/RemoteInputConnection.java
+++ b/core/java/android/inputmethodservice/RemoteInputConnection.java
@@ -34,7 +34,7 @@
import android.view.inputmethod.SurroundingText;
import com.android.internal.inputmethod.CancellationGroup;
-import com.android.internal.inputmethod.Completable;
+import com.android.internal.inputmethod.CompletableFutureUtil;
import com.android.internal.inputmethod.IInputContextInvoker;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputConnectionProtoDumper;
@@ -42,6 +42,7 @@
import com.android.internal.view.IInputMethod;
import java.lang.ref.WeakReference;
+import java.util.concurrent.CompletableFuture;
/**
* Takes care of remote method invocations of {@link InputConnection} in the IME side.
@@ -96,8 +97,8 @@
return null;
}
- final Completable.CharSequence value = mInvoker.getTextAfterCursor(length, flags);
- final CharSequence result = Completable.getResultOrNull(
+ final CompletableFuture<CharSequence> value = mInvoker.getTextAfterCursor(length, flags);
+ final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getTextAfterCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -120,8 +121,8 @@
return null;
}
- final Completable.CharSequence value = mInvoker.getTextBeforeCursor(length, flags);
- final CharSequence result = Completable.getResultOrNull(
+ final CompletableFuture<CharSequence> value = mInvoker.getTextBeforeCursor(length, flags);
+ final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getTextBeforeCursor()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -144,8 +145,8 @@
// This method is not implemented.
return null;
}
- final Completable.CharSequence value = mInvoker.getSelectedText(flags);
- final CharSequence result = Completable.getResultOrNull(
+ final CompletableFuture<CharSequence> value = mInvoker.getSelectedText(flags);
+ final CharSequence result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getSelectedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -181,9 +182,9 @@
// This method is not implemented.
return null;
}
- final Completable.SurroundingText value = mInvoker.getSurroundingText(beforeLength,
+ final CompletableFuture<SurroundingText> value = mInvoker.getSurroundingText(beforeLength,
afterLength, flags);
- final SurroundingText result = Completable.getResultOrNull(
+ final SurroundingText result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getSurroundingText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -202,8 +203,8 @@
return 0;
}
- final Completable.Int value = mInvoker.getCursorCapsMode(reqModes);
- final int result = Completable.getResultOrZero(
+ final CompletableFuture<Integer> value = mInvoker.getCursorCapsMode(reqModes);
+ final int result = CompletableFutureUtil.getResultOrZero(
value, TAG, "getCursorCapsMode()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -222,8 +223,8 @@
return null;
}
- final Completable.ExtractedText value = mInvoker.getExtractedText(request, flags);
- final ExtractedText result = Completable.getResultOrNull(
+ final CompletableFuture<ExtractedText> value = mInvoker.getExtractedText(request, flags);
+ final ExtractedText result = CompletableFutureUtil.getResultOrNull(
value, TAG, "getExtractedText()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
final InputMethodServiceInternal inputMethodService = mInputMethodService.get();
@@ -371,8 +372,8 @@
// This method is not implemented.
return false;
}
- final Completable.Boolean value = mInvoker.requestCursorUpdates(cursorUpdateMode);
- return Completable.getResultOrFalse(value, TAG, "requestCursorUpdates()",
+ final CompletableFuture<Boolean> value = mInvoker.requestCursorUpdates(cursorUpdateMode);
+ return CompletableFutureUtil.getResultOrFalse(value, TAG, "requestCursorUpdates()",
mCancellationGroup, MAX_WAIT_TIME_MILLIS);
}
@@ -407,8 +408,9 @@
inputMethodService.exposeContent(inputContentInfo, this);
}
- final Completable.Boolean value = mInvoker.commitContent(inputContentInfo, flags, opts);
- return Completable.getResultOrFalse(
+ final CompletableFuture<Boolean> value =
+ mInvoker.commitContent(inputContentInfo, flags, opts);
+ return CompletableFutureUtil.getResultOrFalse(
value, TAG, "commitContent()", mCancellationGroup, MAX_WAIT_TIME_MILLIS);
}
diff --git a/core/java/com/android/internal/inputmethod/CallbackUtils.java b/core/java/com/android/internal/inputmethod/CallbackUtils.java
deleted file mode 100644
index aca761d..0000000
--- a/core/java/com/android/internal/inputmethod/CallbackUtils.java
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.annotation.NonNull;
-import android.os.RemoteException;
-
-import java.util.function.BooleanSupplier;
-import java.util.function.IntSupplier;
-import java.util.function.Supplier;
-
-/**
- * Defines a set of helper methods to callback corresponding results in {@link ResultCallbacks}.
- */
-public final class CallbackUtils {
-
- /**
- * Not intended to be instantiated.
- */
- private CallbackUtils() {
- }
-
- /**
- * A utility method using given {@link IBooleanResultCallback} to callback the result.
- *
- * @param callback {@link IBooleanResultCallback} to be called back.
- * @param resultSupplier the supplier from which the result is provided.
- */
- public static void onResult(@NonNull IBooleanResultCallback callback,
- @NonNull BooleanSupplier resultSupplier) {
- boolean result = false;
- Throwable exception = null;
-
- try {
- result = resultSupplier.getAsBoolean();
- } catch (Throwable throwable) {
- exception = throwable;
- }
-
- try {
- if (exception != null) {
- callback.onError(ThrowableHolder.of(exception));
- return;
- }
- callback.onResult(result);
- } catch (RemoteException ignored) { }
- }
-
- /**
- * A utility method using given {@link IIntResultCallback} to callback the result.
- *
- * @param callback {@link IIntResultCallback} to be called back.
- * @param resultSupplier the supplier from which the result is provided.
- */
- public static void onResult(@NonNull IIntResultCallback callback,
- @NonNull IntSupplier resultSupplier) {
- int result = 0;
- Throwable exception = null;
-
- try {
- result = resultSupplier.getAsInt();
- } catch (Throwable throwable) {
- exception = throwable;
- }
-
- try {
- if (exception != null) {
- callback.onError(ThrowableHolder.of(exception));
- return;
- }
- callback.onResult(result);
- } catch (RemoteException ignored) { }
- }
-
- /**
- * A utility method using given {@link IVoidResultCallback} to callback the result.
- *
- * @param callback {@link IVoidResultCallback} to be called back.
- * @param runnable to execute the given method
- */
- public static void onResult(@NonNull IVoidResultCallback callback,
- @NonNull Runnable runnable) {
- Throwable exception = null;
-
- try {
- runnable.run();
- } catch (Throwable throwable) {
- exception = throwable;
- }
-
- try {
- if (exception != null) {
- callback.onError(ThrowableHolder.of(exception));
- return;
- }
- callback.onResult();
- } catch (RemoteException ignored) { }
- }
-
- /**
- * A utility method using given {@link IInputContentUriTokenResultCallback} to callback the
- * result.
- *
- * @param callback {@link IInputContentUriTokenResultCallback} to be called back.
- * @param resultSupplier the supplier from which the result is provided.
- */
- public static void onResult(@NonNull IInputContentUriTokenResultCallback callback,
- @NonNull Supplier<IInputContentUriToken> resultSupplier) {
- IInputContentUriToken result = null;
- Throwable exception = null;
-
- try {
- result = resultSupplier.get();
- } catch (Throwable throwable) {
- exception = throwable;
- }
-
- try {
- if (exception != null) {
- callback.onError(ThrowableHolder.of(exception));
- return;
- }
- callback.onResult(result);
- } catch (RemoteException ignored) { }
- }
-}
diff --git a/core/java/com/android/internal/inputmethod/CancellationGroup.java b/core/java/com/android/internal/inputmethod/CancellationGroup.java
index aef9e3b..3b2e1cd 100644
--- a/core/java/com/android/internal/inputmethod/CancellationGroup.java
+++ b/core/java/com/android/internal/inputmethod/CancellationGroup.java
@@ -23,49 +23,66 @@
import com.android.internal.annotations.GuardedBy;
import java.util.ArrayList;
-import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.CompletableFuture;
/**
* A utility class, which works as both a factory class of a cancellation signal to cancel
* all the completable objects.
+ *
+ * <p>TODO: Make this lock-free.</p>
*/
public final class CancellationGroup {
private final Object mLock = new Object();
/**
- * List of {@link CountDownLatch}, which can be used to propagate {@link #cancelAll()} to
+ * List of {@link CompletableFuture}, which can be used to propagate {@link #cancelAll()} to
* completable objects.
*
* <p>This will be lazily instantiated to avoid unnecessary object allocations.</p>
*/
@Nullable
@GuardedBy("mLock")
- private ArrayList<CountDownLatch> mLatchList = null;
+ private ArrayList<CompletableFuture<?>> mFutureList = null;
@GuardedBy("mLock")
private boolean mCanceled = false;
+ /**
+ * Tries to register the given {@link CompletableFuture} into the callback list if this
+ * {@link CancellationGroup} is not yet cancelled.
+ *
+ * <p>If this {@link CancellationGroup} is already cancelled, then this method will immediately
+ * call {@link CompletableFuture#cancel(boolean)} then return {@code false}.</p>
+ *
+ * <p>When this method returns {@code true}, call {@link #unregisterFuture(CompletableFuture)}
+ * to remove the unnecessary object reference.</p>
+ *
+ * @param future {@link CompletableFuture} to be added to the cancellation callback list.
+ * @return {@code true} if the given {@code future} is added to the callback list.
+ * {@code false} otherwise.
+ */
@AnyThread
- boolean registerLatch(@NonNull CountDownLatch latch) {
+ boolean tryRegisterFutureOrCancelImmediately(@NonNull CompletableFuture<?> future) {
synchronized (mLock) {
if (mCanceled) {
+ future.cancel(false);
return false;
}
- if (mLatchList == null) {
+ if (mFutureList == null) {
// Set the initial capacity to 1 with an assumption that usually there is up to 1
// on-going operation.
- mLatchList = new ArrayList<>(1);
+ mFutureList = new ArrayList<>(1);
}
- mLatchList.add(latch);
+ mFutureList.add(future);
return true;
}
}
@AnyThread
- void unregisterLatch(@NonNull CountDownLatch latch) {
+ void unregisterFuture(@NonNull CompletableFuture<?> future) {
synchronized (mLock) {
- if (mLatchList != null) {
- mLatchList.remove(latch);
+ if (mFutureList != null) {
+ mFutureList.remove(future);
}
}
}
@@ -80,10 +97,10 @@
synchronized (mLock) {
if (!mCanceled) {
mCanceled = true;
- if (mLatchList != null) {
- mLatchList.forEach(CountDownLatch::countDown);
- mLatchList.clear();
- mLatchList = null;
+ if (mFutureList != null) {
+ mFutureList.forEach(future -> future.cancel(false));
+ mFutureList.clear();
+ mFutureList = null;
}
}
}
diff --git a/core/java/com/android/internal/inputmethod/Completable.java b/core/java/com/android/internal/inputmethod/Completable.java
deleted file mode 100644
index 132272c..0000000
--- a/core/java/com/android/internal/inputmethod/Completable.java
+++ /dev/null
@@ -1,558 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import static java.lang.annotation.RetentionPolicy.SOURCE;
-
-import android.annotation.AnyThread;
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.util.Log;
-
-import com.android.internal.annotations.GuardedBy;
-
-import java.lang.annotation.Retention;
-import java.util.concurrent.CountDownLatch;
-import java.util.concurrent.TimeUnit;
-
-/**
- * An class to consolidate completable object types supported by
- * {@link CancellationGroup}.
- */
-public final class Completable {
-
- /**
- * Not intended to be instantiated.
- */
- private Completable() {
- }
-
- /**
- * Base class of all the completable types supported by {@link CancellationGroup}.
- */
- protected static class ValueBase {
- /**
- * {@link CountDownLatch} to be signaled to unblock
- * {@link #await(int, TimeUnit, CancellationGroup)}.
- */
- private final CountDownLatch mLatch = new CountDownLatch(1);
-
- /**
- * Lock {@link Object} to guard complete operations within this class.
- */
- protected final Object mStateLock = new Object();
-
- /**
- * Indicates the completion state of this object.
- */
- @GuardedBy("mStateLock")
- @CompletionState
- protected int mState = CompletionState.NOT_COMPLETED;
-
- /**
- * {@link Throwable} message passed to {@link #onError(ThrowableHolder)}.
- *
- * <p>This is not {@code null} only when {@link #mState} is
- * {@link CompletionState#COMPLETED_WITH_ERROR}.</p>
- */
- @GuardedBy("mStateLock")
- @Nullable
- protected String mMessage = null;
-
- @Retention(SOURCE)
- @IntDef({
- CompletionState.NOT_COMPLETED,
- CompletionState.COMPLETED_WITH_VALUE,
- CompletionState.COMPLETED_WITH_ERROR})
- protected @interface CompletionState {
- /**
- * This object is not completed yet.
- */
- int NOT_COMPLETED = 0;
- /**
- * This object is already completed with a value.
- */
- int COMPLETED_WITH_VALUE = 1;
- /**
- * This object is already completed with an error.
- */
- int COMPLETED_WITH_ERROR = 2;
- }
-
- /**
- * Converts the given {@link CompletionState} into a human-readable string.
- *
- * @param state {@link CompletionState} to be converted.
- * @return a human-readable {@link String} for the given {@code state}.
- */
- @AnyThread
- protected static String stateToString(@CompletionState int state) {
- switch (state) {
- case CompletionState.NOT_COMPLETED:
- return "NOT_COMPLETED";
- case CompletionState.COMPLETED_WITH_VALUE:
- return "COMPLETED_WITH_VALUE";
- case CompletionState.COMPLETED_WITH_ERROR:
- return "COMPLETED_WITH_ERROR";
- default:
- return "Unknown(value=" + state + ")";
- }
- }
-
- /**
- * @return {@code true} if {@link #onComplete()} gets called and {@link #mState} is
- * {@link CompletionState#COMPLETED_WITH_VALUE}.
- */
- @AnyThread
- public boolean hasValue() {
- synchronized (mStateLock) {
- return mState == CompletionState.COMPLETED_WITH_VALUE;
- }
- }
-
- /**
- * Provides the base implementation of {@code getValue()} for derived classes.
- *
- * <p>Must be called after acquiring {@link #mStateLock}.</p>
- *
- * @throws RuntimeException when {@link #mState} is
- * {@link CompletionState#COMPLETED_WITH_ERROR}.
- * @throws UnsupportedOperationException when {@link #mState} is not
- * {@link CompletionState#COMPLETED_WITH_VALUE} and
- * {@link CompletionState#COMPLETED_WITH_ERROR}.
- */
- @GuardedBy("mStateLock")
- protected void enforceGetValueLocked() {
- switch (mState) {
- case CompletionState.NOT_COMPLETED:
- throw new UnsupportedOperationException(
- "getValue() is allowed only if hasValue() returns true");
- case CompletionState.COMPLETED_WITH_VALUE:
- return;
- case CompletionState.COMPLETED_WITH_ERROR:
- throw new RuntimeException(mMessage);
- default:
- throw new UnsupportedOperationException(
- "getValue() is not allowed on state=" + stateToString(mState));
- }
- }
-
- /**
- * Called by subclasses to signale {@link #mLatch}.
- */
- @AnyThread
- protected void onComplete() {
- mLatch.countDown();
- }
-
- /**
- * Notify when exception happened.
- *
- * @param throwableHolder contains the {@link Throwable} object when exception happened.
- */
- @AnyThread
- protected void onError(ThrowableHolder throwableHolder) {
- synchronized (mStateLock) {
- switch (mState) {
- case CompletionState.NOT_COMPLETED:
- mMessage = throwableHolder.getMessage();
- mState = CompletionState.COMPLETED_WITH_ERROR;
- break;
- default:
- throw new UnsupportedOperationException(
- "onError() is not allowed on state=" + stateToString(mState));
- }
- }
- onComplete();
- }
-
- /**
- * Blocks the calling thread until at least one of the following conditions is met.
- *
- * <p>
- * <ol>
- * <li>This object becomes ready to return the value.</li>
- * <li>{@link CancellationGroup#cancelAll()} gets called.</li>
- * <li>The given timeout period has passed.</li>
- * </ol>
- * </p>
- *
- * <p>The caller can distinguish the case 1 and case 2 by calling {@link #hasValue()}.
- * Note that the return value of {@link #hasValue()} can change from {@code false} to
- * {@code true} at any time, even after this methods finishes with returning
- * {@code true}.</p>
- *
- * @param timeout length of the timeout.
- * @param timeUnit unit of {@code timeout}.
- * @param cancellationGroup {@link CancellationGroup} to cancel completable objects.
- * @return {@code false} if and only if the given timeout period has passed. Otherwise
- * {@code true}.
- */
- @AnyThread
- public boolean await(int timeout, @NonNull TimeUnit timeUnit,
- @Nullable CancellationGroup cancellationGroup) {
- if (cancellationGroup == null) {
- return awaitInner(timeout, timeUnit);
- }
-
- if (!cancellationGroup.registerLatch(mLatch)) {
- // Already canceled when this method gets called.
- return false;
- }
- try {
- return awaitInner(timeout, timeUnit);
- } finally {
- cancellationGroup.unregisterLatch(mLatch);
- }
- }
-
- private boolean awaitInner(int timeout, @NonNull TimeUnit timeUnit) {
- try {
- return mLatch.await(timeout, timeUnit);
- } catch (InterruptedException e) {
- return true;
- }
- }
-
- /**
- * Blocks the calling thread until this object becomes ready to return the value, even if
- * {@link InterruptedException} is thrown.
- */
- @AnyThread
- public void await() {
- boolean interrupted = false;
- while (true) {
- try {
- mLatch.await();
- break;
- } catch (InterruptedException ignored) {
- interrupted = true;
- }
- }
-
- if (interrupted) {
- // Try to preserve the interrupt bit on this thread.
- Thread.currentThread().interrupt();
- }
- }
- }
-
- /**
- * Completable object of integer primitive.
- */
- public static final class Int extends ValueBase {
- @GuardedBy("mStateLock")
- private int mValue = 0;
-
- /**
- * Notify when a value is set to this completable object.
- *
- * @param value value to be set.
- */
- @AnyThread
- void onComplete(int value) {
- synchronized (mStateLock) {
- switch (mState) {
- case CompletionState.NOT_COMPLETED:
- mValue = value;
- mState = CompletionState.COMPLETED_WITH_VALUE;
- break;
- default:
- throw new UnsupportedOperationException(
- "onComplete() is not allowed on state=" + stateToString(mState));
- }
- }
- onComplete();
- }
-
- /**
- * @return value associated with this object.
- * @throws RuntimeException when called while {@link #onError} happened.
- * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
- * {@code false}.
- */
- @AnyThread
- public int getValue() {
- synchronized (mStateLock) {
- enforceGetValueLocked();
- return mValue;
- }
- }
- }
-
- /**
- * Completable object of {@link java.lang.Void}.
- */
- public static final class Void extends ValueBase {
- /**
- * Notify when this completable object callback.
- */
- @AnyThread
- @Override
- protected void onComplete() {
- synchronized (mStateLock) {
- switch (mState) {
- case CompletionState.NOT_COMPLETED:
- mState = CompletionState.COMPLETED_WITH_VALUE;
- break;
- default:
- throw new UnsupportedOperationException(
- "onComplete() is not allowed on state=" + stateToString(mState));
- }
- }
- super.onComplete();
- }
-
- /**
- * @throws RuntimeException when called while {@link #onError} happened.
- * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
- * {@code false}.
- */
- @AnyThread
- public void getValue() {
- synchronized (mStateLock) {
- enforceGetValueLocked();
- }
- }
- }
-
- /**
- * Base class of completable object types.
- *
- * @param <T> type associated with this completable object.
- */
- public static class Values<T> extends ValueBase {
- @GuardedBy("mStateLock")
- @Nullable
- private T mValue = null;
-
- /**
- * Notify when a value is set to this completable value object.
- *
- * @param value value to be set.
- */
- @AnyThread
- void onComplete(@Nullable T value) {
- synchronized (mStateLock) {
- switch (mState) {
- case CompletionState.NOT_COMPLETED:
- mValue = value;
- mState = CompletionState.COMPLETED_WITH_VALUE;
- break;
- default:
- throw new UnsupportedOperationException(
- "onComplete() is not allowed on state=" + stateToString(mState));
- }
- }
- onComplete();
- }
-
- /**
- * @return value associated with this object.
- * @throws RuntimeException when called while {@link #onError} happened
- * @throws UnsupportedOperationException when called while {@link #hasValue()} returns
- * {@code false}.
- */
- @AnyThread
- @Nullable
- public T getValue() {
- synchronized (mStateLock) {
- enforceGetValueLocked();
- return mValue;
- }
- }
- }
-
- /**
- * @return an instance of {@link Completable.Int}.
- */
- public static Completable.Int createInt() {
- return new Completable.Int();
- }
-
- /**
- * @return an instance of {@link Completable.Boolean}.
- */
- public static Completable.Boolean createBoolean() {
- return new Completable.Boolean();
- }
-
- /**
- * @return an instance of {@link Completable.CharSequence}.
- */
- public static Completable.CharSequence createCharSequence() {
- return new Completable.CharSequence();
- }
-
- /**
- * @return an instance of {@link Completable.ExtractedText}.
- */
- public static Completable.ExtractedText createExtractedText() {
- return new Completable.ExtractedText();
- }
-
- /**
- * @return an instance of {@link Completable.SurroundingText}.
- */
- public static Completable.SurroundingText createSurroundingText() {
- return new Completable.SurroundingText();
- }
-
- /**
- * @return an instance of {@link Completable.IInputContentUriToken}.
- */
- public static Completable.IInputContentUriToken createIInputContentUriToken() {
- return new Completable.IInputContentUriToken();
- }
-
- /**
- * @return an instance of {@link Completable.Void}.
- */
- public static Completable.Void createVoid() {
- return new Completable.Void();
- }
-
- /**
- * Completable object of {@link java.lang.Boolean}.
- */
- public static final class Boolean extends Values<java.lang.Boolean> { }
-
- /**
- * Completable object of {@link java.lang.CharSequence}.
- */
- public static final class CharSequence extends Values<java.lang.CharSequence> { }
-
- /**
- * Completable object of {@link android.view.inputmethod.ExtractedText}.
- */
- public static final class ExtractedText
- extends Values<android.view.inputmethod.ExtractedText> { }
-
- /**
- * Completable object of {@link android.view.inputmethod.SurroundingText}.
- */
- public static final class SurroundingText
- extends Values<android.view.inputmethod.SurroundingText> { }
-
- /**
- * Completable object of {@link IInputContentUriToken>}.
- */
- public static final class IInputContentUriToken
- extends Values<com.android.internal.inputmethod.IInputContentUriToken> { }
-
- /**
- * Await the result by the {@link Completable.Values}.
- *
- * @return the result once {@link ValueBase#onComplete()}.
- */
- @AnyThread
- @Nullable
- public static <T> T getResult(@NonNull Completable.Values<T> value) {
- value.await();
- return value.getValue();
- }
-
- /**
- * Await the int result by the {@link Completable.Int}.
- *
- * @return the result once {@link ValueBase#onComplete()}.
- */
- @AnyThread
- public static int getIntResult(@NonNull Completable.Int value) {
- value.await();
- return value.getValue();
- }
-
- /**
- * Await the result by the {@link Completable.Void}.
- *
- * Check the result once {@link ValueBase#onComplete()}
- */
- @AnyThread
- public static void getResult(@NonNull Completable.Void value) {
- value.await();
- value.getValue();
- }
-
- /**
- * Await the result by the {@link Completable.Boolean}, and log it if there is no result after
- * given timeout.
- *
- * @return the result once {@link ValueBase#onComplete()}
- */
- @AnyThread
- public static boolean getResultOrFalse(@NonNull Completable.Boolean value, String tag,
- @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
- int maxWaitTime) {
- final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
- if (value.hasValue()) {
- return value.getValue();
- }
- logInternal(tag, methodName, timedOut, maxWaitTime, 0);
- return false;
- }
-
- /**
- * Await the result by the {@link Completable.Int}, and log it if there is no result after
- * given timeout.
- *
- * @return the result once {@link ValueBase#onComplete()}
- */
- @AnyThread
- public static int getResultOrZero(@NonNull Completable.Int value, String tag,
- @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
- int maxWaitTime) {
- final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
- if (value.hasValue()) {
- return value.getValue();
- }
- logInternal(tag, methodName, timedOut, maxWaitTime, 0);
- return 0;
- }
-
- /**
- * Await the result by the {@link Completable.Values}, and log it if there is no result after
- * given timeout.
- *
- * @return the result once {@link ValueBase#onComplete()}
- */
- @AnyThread
- @Nullable
- public static <T> T getResultOrNull(@NonNull Completable.Values<T> value, String tag,
- @NonNull String methodName, @Nullable CancellationGroup cancellationGroup,
- int maxWaitTime) {
- final boolean timedOut = value.await(maxWaitTime, TimeUnit.MILLISECONDS, cancellationGroup);
- if (value.hasValue()) {
- return value.getValue();
- }
- logInternal(tag, methodName, timedOut, maxWaitTime, null);
- return null;
- }
-
- @AnyThread
- private static void logInternal(String tag, @Nullable String methodName, boolean timedOut,
- int maxWaitTime, @Nullable Object defaultValue) {
- if (timedOut) {
- Log.w(tag, methodName + " didn't respond in " + maxWaitTime + " msec."
- + " Returning default: " + defaultValue);
- } else {
- Log.w(tag, methodName + " was canceled before complete. Returning default: "
- + defaultValue);
- }
- }
-}
diff --git a/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java b/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java
new file mode 100644
index 0000000..ec10e01
--- /dev/null
+++ b/core/java/com/android/internal/inputmethod/CompletableFutureUtil.java
@@ -0,0 +1,253 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod;
+
+import android.annotation.AnyThread;
+import android.annotation.DurationMillisLong;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.util.Log;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.CompletionException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.TimeoutException;
+
+/**
+ * A set of helper methods to retrieve result values from {@link CompletableFuture}.
+ */
+public final class CompletableFutureUtil {
+ /**
+ * Not intended to be instantiated.
+ */
+ private CompletableFutureUtil() {
+ }
+
+ @AnyThread
+ @Nullable
+ private static <T> T getValueOrRethrowErrorInternal(@NonNull CompletableFuture<T> future) {
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return future.get();
+ } catch (ExecutionException e) {
+ final Throwable cause = e.getCause();
+ throw new RuntimeException(cause.getMessage(), cause.getCause());
+ } catch (InterruptedException e) {
+ interrupted = true;
+ }
+ }
+ } finally {
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ @AnyThread
+ @Nullable
+ private static <T> T getValueOrNullInternal(@NonNull CompletableFuture<T> future,
+ @Nullable String tag, @Nullable String methodName,
+ @DurationMillisLong long timeoutMillis, @Nullable CancellationGroup cancellationGroup) {
+ // We intentionally do not use CompletableFuture.anyOf() to avoid additional object
+ // allocations.
+ final boolean needsToUnregister = cancellationGroup != null
+ && cancellationGroup.tryRegisterFutureOrCancelImmediately(future);
+ boolean interrupted = false;
+ try {
+ while (true) {
+ try {
+ return future.get(timeoutMillis, TimeUnit.MILLISECONDS);
+ } catch (CompletionException e) {
+ if (e.getCause() instanceof CancellationException) {
+ logCancellationInternal(tag, methodName);
+ return null;
+ }
+ logErrorInternal(tag, methodName, e.getMessage());
+ return null;
+ } catch (CancellationException e) {
+ logCancellationInternal(tag, methodName);
+ return null;
+ } catch (InterruptedException e) {
+ interrupted = true;
+ } catch (TimeoutException e) {
+ logTimeoutInternal(tag, methodName, timeoutMillis);
+ return null;
+ } catch (Throwable e) {
+ logErrorInternal(tag, methodName, e.getMessage());
+ return null;
+ }
+ }
+ } finally {
+ if (needsToUnregister) {
+ cancellationGroup.unregisterFuture(future);
+ }
+ if (interrupted) {
+ Thread.currentThread().interrupt();
+ }
+ }
+ }
+
+ @AnyThread
+ private static void logTimeoutInternal(@Nullable String tag, @Nullable String methodName,
+ @DurationMillisLong long timeout) {
+ if (tag == null || methodName == null) {
+ return;
+ }
+ Log.w(tag, methodName + " didn't respond in " + timeout + " msec.");
+ }
+
+ @AnyThread
+ private static void logErrorInternal(@Nullable String tag, @Nullable String methodName,
+ @Nullable String errorString) {
+ if (tag == null || methodName == null) {
+ return;
+ }
+ Log.w(tag, methodName + " was failed with an exception=" + errorString);
+ }
+
+ @AnyThread
+ private static void logCancellationInternal(@Nullable String tag, @Nullable String methodName) {
+ if (tag == null || methodName == null) {
+ return;
+ }
+ Log.w(tag, methodName + " was cancelled.");
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<T>}.
+ *
+ * <p>This method may throw exception is the task is completed with an error.</p>
+ *
+ * @param future the object to extract the result from.
+ * @param <T> type of the result.
+ * @return the result.
+ */
+ @AnyThread
+ @Nullable
+ public static <T> T getResult(@NonNull CompletableFuture<T> future) {
+ return getValueOrRethrowErrorInternal(future);
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<Boolean>}.
+ *
+ * <p>This method may throw exception is the task is completed with an error.</p>
+ *
+ * @param future the object to extract the result from.
+ * @return the result.
+ */
+ @AnyThread
+ public static boolean getBooleanResult(@NonNull CompletableFuture<Boolean> future) {
+ return getValueOrRethrowErrorInternal(future);
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<Integer>}.
+ *
+ * <p>This method may throw exception is the task is completed with an error.</p>
+ *
+ * @param future the object to extract the result from.
+ * @return the result.
+ */
+ @AnyThread
+ public static int getIntegerResult(@NonNull CompletableFuture<Integer> future) {
+ return getValueOrRethrowErrorInternal(future);
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<Boolean>}.
+ *
+ * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+ *
+ * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+ * will be cancelled permanently. You have to duplicate the {@link CompletableFuture} if you
+ * want to avoid this side-effect.</p>
+ *
+ * @param future the object to extract the result from.
+ * @param tag tag name for logging. Pass {@code null} to disable logging.
+ * @param methodName method name for logging. Pass {@code null} to disable logging.
+ * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+ * object. Can be {@code null}.
+ * @param timeoutMillis length of the timeout in millisecond.
+ * @return the result if it is completed within the given timeout. {@code false} otherwise.
+ */
+ @AnyThread
+ public static boolean getResultOrFalse(@NonNull CompletableFuture<Boolean> future,
+ @Nullable String tag, @Nullable String methodName,
+ @Nullable CancellationGroup cancellationGroup,
+ @DurationMillisLong long timeoutMillis) {
+ final Boolean obj = getValueOrNullInternal(future, tag, methodName, timeoutMillis,
+ cancellationGroup);
+ return obj != null ? obj : false;
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<Integer>}.
+ *
+ * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+ *
+ * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+ * will be cancelled permanently. You have to duplicate the {@link CompletableFuture} if you
+ * want to avoid this side-effect.</p>
+ *
+ * @param future the object to extract the result from.
+ * @param tag tag name for logging. Pass {@code null} to disable logging.
+ * @param methodName method name for logging. Pass {@code null} to disable logging.
+ * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+ * object. Can be {@code null}.
+ * @param timeoutMillis length of the timeout in millisecond.
+ * @return the result if it is completed within the given timeout. {@code 0} otherwise.
+ */
+ @AnyThread
+ public static int getResultOrZero(@NonNull CompletableFuture<Integer> future,
+ @Nullable String tag, @Nullable String methodName,
+ @Nullable CancellationGroup cancellationGroup, @DurationMillisLong long timeoutMillis) {
+ final Integer obj = getValueOrNullInternal(future, tag, methodName, timeoutMillis,
+ cancellationGroup);
+ return obj != null ? obj : 0;
+ }
+
+ /**
+ * Return the result of the given {@link CompletableFuture<T>}.
+ *
+ * <p>This method is agnostic to {@link Thread#interrupt()}.</p>
+ *
+ * <p>CAVEAT: when {@code cancellationGroup} is specified and it is signalled, {@code future}
+ * will be cancelled permanently. You have to duplicate the {@link CompletableFuture} if you
+ * want to avoid this side-effect.</p>
+ *
+ * @param future the object to extract the result from.
+ * @param tag tag name for logging. Pass {@code null} to disable logging.
+ * @param methodName method name for logging. Pass {@code null} to disable logging.
+ * @param cancellationGroup an optional {@link CancellationGroup} to cancel {@code future}
+ * object. Can be {@code null}.
+ * @param timeoutMillis length of the timeout in millisecond.
+ * @param <T> Type of the result.
+ * @return the result if it is completed within the given timeout. {@code null} otherwise.
+ */
+ @AnyThread
+ @Nullable
+ public static <T> T getResultOrNull(@NonNull CompletableFuture<T> future, @Nullable String tag,
+ @Nullable String methodName, @Nullable CancellationGroup cancellationGroup,
+ @DurationMillisLong long timeoutMillis) {
+ return getValueOrNullInternal(future, tag, methodName, timeoutMillis, cancellationGroup);
+ }
+}
diff --git a/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl b/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl
deleted file mode 100644
index 6daeb3f..0000000
--- a/core/java/com/android/internal/inputmethod/IBooleanResultCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IBooleanResultCallback {
- void onResult(boolean result);
- void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl b/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl
deleted file mode 100644
index da56fd0..0000000
--- a/core/java/com/android/internal/inputmethod/ICharSequenceResultCallback.aidl
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-oneway interface ICharSequenceResultCallback {
- void onResult(in CharSequence result);
-}
diff --git a/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl b/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl
deleted file mode 100644
index b603f6a..0000000
--- a/core/java/com/android/internal/inputmethod/IExtractedTextResultCallback.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.view.inputmethod.ExtractedText;
-
-oneway interface IExtractedTextResultCallback {
- void onResult(in ExtractedText result);
-}
diff --git a/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl b/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
deleted file mode 100644
index 779acb5..0000000
--- a/core/java/com/android/internal/inputmethod/IInputContentUriTokenResultCallback.aidl
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IInputContentUriTokenResultCallback {
- void onResult(in IInputContentUriToken result);
- void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
index 977f9a5..0cbdc13 100644
--- a/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
+++ b/core/java/com/android/internal/inputmethod/IInputContextInvoker.java
@@ -23,16 +23,19 @@
import android.view.KeyEvent;
import android.view.inputmethod.CompletionInfo;
import android.view.inputmethod.CorrectionInfo;
+import android.view.inputmethod.ExtractedText;
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
+import android.view.inputmethod.SurroundingText;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;
import java.util.Objects;
/**
* A stateless wrapper of {@link com.android.internal.view.IInputContext} to encapsulate boilerplate
- * code around {@link Completable} and {@link RemoteException}.
+ * code around {@link AndroidFuture} and {@link RemoteException}.
*/
public final class IInputContextInvoker {
@@ -60,19 +63,19 @@
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
- * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.CharSequence getTextAfterCursor(int length, int flags) {
- final Completable.CharSequence value = Completable.createCharSequence();
+ public AndroidFuture<CharSequence> getTextAfterCursor(int length, int flags) {
+ final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
- mIInputContext.getTextAfterCursor(length, flags, ResultCallbacks.of(value));
+ mIInputContext.getTextAfterCursor(length, flags, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
@@ -80,38 +83,38 @@
*
* @param length {@code length} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
- * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.CharSequence getTextBeforeCursor(int length, int flags) {
- final Completable.CharSequence value = Completable.createCharSequence();
+ public AndroidFuture<CharSequence> getTextBeforeCursor(int length, int flags) {
+ final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
- mIInputContext.getTextBeforeCursor(length, flags, ResultCallbacks.of(value));
+ mIInputContext.getTextBeforeCursor(length, flags, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
* Invokes {@link IInputContext#getSelectedText(int, ICharSequenceResultCallback)}.
*
* @param flags {@code flags} parameter to be passed.
- * @return {@link Completable.CharSequence} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<CharSequence>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.CharSequence getSelectedText(int flags) {
- final Completable.CharSequence value = Completable.createCharSequence();
+ public AndroidFuture<CharSequence> getSelectedText(int flags) {
+ final AndroidFuture<CharSequence> future = new AndroidFuture<>();
try {
- mIInputContext.getSelectedText(flags, ResultCallbacks.of(value));
+ mIInputContext.getSelectedText(flags, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
@@ -121,40 +124,39 @@
* @param beforeLength {@code beforeLength} parameter to be passed.
* @param afterLength {@code afterLength} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
- * @return {@link Completable.SurroundingText} that can be used to retrieve the invocation
- * result. {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<SurroundingText>} that can be used to retrieve the
+ * invocation result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.SurroundingText getSurroundingText(int beforeLength, int afterLength,
+ public AndroidFuture<SurroundingText> getSurroundingText(int beforeLength, int afterLength,
int flags) {
- final Completable.SurroundingText value = Completable.createSurroundingText();
+ final AndroidFuture<SurroundingText> future = new AndroidFuture<>();
try {
- mIInputContext.getSurroundingText(beforeLength, afterLength, flags,
- ResultCallbacks.of(value));
+ mIInputContext.getSurroundingText(beforeLength, afterLength, flags, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
* Invokes {@link IInputContext#getCursorCapsMode(int, IIntResultCallback)}.
*
* @param reqModes {@code reqModes} parameter to be passed.
- * @return {@link Completable.Int} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<Integer>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.Int getCursorCapsMode(int reqModes) {
- final Completable.Int value = Completable.createInt();
+ public AndroidFuture<Integer> getCursorCapsMode(int reqModes) {
+ final AndroidFuture<Integer> future = new AndroidFuture<>();
try {
- mIInputContext.getCursorCapsMode(reqModes, ResultCallbacks.of(value));
+ mIInputContext.getCursorCapsMode(reqModes, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
@@ -163,19 +165,20 @@
*
* @param request {@code request} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
- * @return {@link Completable.ExtractedText} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<ExtractedText>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.ExtractedText getExtractedText(ExtractedTextRequest request, int flags) {
- final Completable.ExtractedText value = Completable.createExtractedText();
+ public AndroidFuture<ExtractedText> getExtractedText(ExtractedTextRequest request,
+ int flags) {
+ final AndroidFuture<ExtractedText> future = new AndroidFuture<>();
try {
- mIInputContext.getExtractedText(request, flags, ResultCallbacks.of(value));
+ mIInputContext.getExtractedText(request, flags, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
@@ -474,19 +477,19 @@
* Invokes {@link IInputContext#requestCursorUpdates(int, IIntResultCallback)}.
*
* @param cursorUpdateMode {@code cursorUpdateMode} parameter to be passed.
- * @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.Boolean requestCursorUpdates(int cursorUpdateMode) {
- final Completable.Boolean value = Completable.createBoolean();
+ public AndroidFuture<Boolean> requestCursorUpdates(int cursorUpdateMode) {
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- mIInputContext.requestCursorUpdates(cursorUpdateMode, ResultCallbacks.of(value));
+ mIInputContext.requestCursorUpdates(cursorUpdateMode, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
@@ -496,20 +499,20 @@
* @param inputContentInfo {@code inputContentInfo} parameter to be passed.
* @param flags {@code flags} parameter to be passed.
* @param opts {@code opts} parameter to be passed.
- * @return {@link Completable.Boolean} that can be used to retrieve the invocation result.
- * {@link RemoteException} will be treated as an error.
+ * @return {@link AndroidFuture<Boolean>} that can be used to retrieve the invocation
+ * result. {@link RemoteException} will be treated as an error.
*/
@AnyThread
@NonNull
- public Completable.Boolean commitContent(InputContentInfo inputContentInfo, int flags,
+ public AndroidFuture<Boolean> commitContent(InputContentInfo inputContentInfo, int flags,
Bundle opts) {
- final Completable.Boolean value = Completable.createBoolean();
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
try {
- mIInputContext.commitContent(inputContentInfo, flags, opts, ResultCallbacks.of(value));
+ mIInputContext.commitContent(inputContentInfo, flags, opts, future);
} catch (RemoteException e) {
- value.onError(ThrowableHolder.of(e));
+ future.completeExceptionally(e);
}
- return value;
+ return future;
}
/**
diff --git a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
index 36943e3..9d0f209 100644
--- a/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
+++ b/core/java/com/android/internal/inputmethod/IInputMethodPrivilegedOperations.aidl
@@ -19,10 +19,7 @@
import android.net.Uri;
import android.view.inputmethod.InputMethodSubtype;
-import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
-import com.android.internal.inputmethod.IVoidResultCallback;
+import com.android.internal.infra.AndroidFuture;
/**
* Defines priviledged operations that only the current IME is allowed to call.
@@ -32,17 +29,17 @@
void setImeWindowStatusAsync(int vis, int backDisposition);
void reportStartInputAsync(in IBinder startInputToken);
void createInputContentUriToken(in Uri contentUri, in String packageName,
- in IInputContentUriTokenResultCallback resultCallback);
+ in AndroidFuture future /* T=IBinder */);
void reportFullscreenModeAsync(boolean fullscreen);
- void setInputMethod(String id, in IVoidResultCallback resultCallback);
+ void setInputMethod(String id, in AndroidFuture future /* T=Void */);
void setInputMethodAndSubtype(String id, in InputMethodSubtype subtype,
- in IVoidResultCallback resultCallback);
- void hideMySoftInput(int flags, in IVoidResultCallback resultCallback);
- void showMySoftInput(int flags, in IVoidResultCallback resultCallback);
+ in AndroidFuture future /* T=Void */);
+ void hideMySoftInput(int flags, in AndroidFuture future /* T=Void */);
+ void showMySoftInput(int flags, in AndroidFuture future /* T=Void */);
void updateStatusIconAsync(String packageName, int iconId);
- void switchToPreviousInputMethod(in IBooleanResultCallback resultCallback);
- void switchToNextInputMethod(boolean onlyCurrentIme, in IBooleanResultCallback resultCallback);
- void shouldOfferSwitchingToNextInputMethod(in IBooleanResultCallback resultCallback);
+ void switchToPreviousInputMethod(in AndroidFuture future /* T=Boolean */);
+ void switchToNextInputMethod(boolean onlyCurrentIme, in AndroidFuture future /* T=Boolean */);
+ void shouldOfferSwitchingToNextInputMethod(in AndroidFuture future /* T=Boolean */);
void notifyUserActionAsync();
void applyImeVisibilityAsync(IBinder showOrHideInputToken, boolean setVisible);
}
diff --git a/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl b/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl
deleted file mode 100644
index 6c4f3d5..0000000
--- a/core/java/com/android/internal/inputmethod/ISurroundingTextResultCallback.aidl
+++ /dev/null
@@ -1,23 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.view.inputmethod.SurroundingText;
-
-oneway interface ISurroundingTextResultCallback {
- void onResult(in SurroundingText result);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl b/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
deleted file mode 100644
index 0b25a2b..0000000
--- a/core/java/com/android/internal/inputmethod/IVoidResultCallback.aidl
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import com.android.internal.inputmethod.ThrowableHolder;
-
-oneway interface IVoidResultCallback {
- void onResult();
- void onError(in ThrowableHolder exception);
-}
\ No newline at end of file
diff --git a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
index 9fb0bb5..d4cc376 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodPrivilegedOperations.java
@@ -28,6 +28,7 @@
import android.view.inputmethod.InputMethodSubtype;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
import java.util.Objects;
@@ -142,7 +143,7 @@
/**
* Calls {@link IInputMethodPrivilegedOperations#createInputContentUriToken(Uri, String,
- * IInputContentUriTokenResultCallback)}.
+ * AndroidFuture)}.
*
* @param contentUri Content URI to which a temporary read permission should be granted
* @param packageName Indicates what package needs to have a temporary read permission
@@ -156,10 +157,9 @@
return null;
}
try {
- final Completable.IInputContentUriToken value =
- Completable.createIInputContentUriToken();
- ops.createInputContentUriToken(contentUri, packageName, ResultCallbacks.of(value));
- return Completable.getResult(value);
+ final AndroidFuture<IBinder> future = new AndroidFuture<>();
+ ops.createInputContentUriToken(contentUri, packageName, future);
+ return IInputContentUriToken.Stub.asInterface(CompletableFutureUtil.getResult(future));
} catch (RemoteException e) {
// For historical reasons, this error was silently ignored.
// Note that the caller already logs error so we do not need additional Log.e() here.
@@ -206,7 +206,7 @@
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, IVoidResultCallback)}.
+ * Calls {@link IInputMethodPrivilegedOperations#setInputMethod(String, AndroidFuture)}.
*
* @param id IME ID of the IME to switch to
* @see android.view.inputmethod.InputMethodInfo#getId()
@@ -218,9 +218,9 @@
return;
}
try {
- final Completable.Void value = Completable.createVoid();
- ops.setInputMethod(id, ResultCallbacks.of(value));
- Completable.getResult(value);
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ ops.setInputMethod(id, future);
+ CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -228,7 +228,7 @@
/**
* Calls {@link IInputMethodPrivilegedOperations#setInputMethodAndSubtype(String,
- * InputMethodSubtype, IVoidResultCallback)}
+ * InputMethodSubtype, AndroidFuture)}
*
* @param id IME ID of the IME to switch to
* @param subtype {@link InputMethodSubtype} to switch to
@@ -241,9 +241,9 @@
return;
}
try {
- final Completable.Void value = Completable.createVoid();
- ops.setInputMethodAndSubtype(id, subtype, ResultCallbacks.of(value));
- Completable.getResult(value);
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ ops.setInputMethodAndSubtype(id, subtype, future);
+ CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -263,16 +263,16 @@
return;
}
try {
- final Completable.Void value = Completable.createVoid();
- ops.hideMySoftInput(flags, ResultCallbacks.of(value));
- Completable.getResult(value);
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ ops.hideMySoftInput(flags, future);
+ CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, IVoidResultCallback)}
+ * Calls {@link IInputMethodPrivilegedOperations#showMySoftInput(int, AndroidFuture)}
*
* @param flags additional operating flags
* @see android.view.inputmethod.InputMethodManager#SHOW_IMPLICIT
@@ -285,17 +285,16 @@
return;
}
try {
- final Completable.Void value = Completable.createVoid();
- ops.showMySoftInput(flags, ResultCallbacks.of(value));
- Completable.getResult(value);
+ final AndroidFuture<Void> future = new AndroidFuture<>();
+ ops.showMySoftInput(flags, future);
+ CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
/**
- * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(
- * IBooleanResultCallback)}
+ * Calls {@link IInputMethodPrivilegedOperations#switchToPreviousInputMethod(AndroidFuture)}
*
* @return {@code true} if handled
*/
@@ -306,9 +305,9 @@
return false;
}
try {
- final Completable.Boolean value = Completable.createBoolean();
- ops.switchToPreviousInputMethod(ResultCallbacks.of(value));
- return Completable.getResult(value);
+ final AndroidFuture<Boolean> value = new AndroidFuture<>();
+ ops.switchToPreviousInputMethod(value);
+ return CompletableFutureUtil.getResult(value);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -329,9 +328,9 @@
return false;
}
try {
- final Completable.Boolean value = Completable.createBoolean();
- ops.switchToNextInputMethod(onlyCurrentIme, ResultCallbacks.of(value));
- return Completable.getResult(value);
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
+ ops.switchToNextInputMethod(onlyCurrentIme, future);
+ return CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -339,7 +338,7 @@
/**
* Calls {@link IInputMethodPrivilegedOperations#shouldOfferSwitchingToNextInputMethod(
- * IBooleanResultCallback)}
+ * AndroidFuture)}
*
* @return {@code true} if the IEM should offer a way to globally switch IME
*/
@@ -350,9 +349,9 @@
return false;
}
try {
- final Completable.Boolean value = Completable.createBoolean();
- ops.shouldOfferSwitchingToNextInputMethod(ResultCallbacks.of(value));
- return Completable.getResult(value);
+ final AndroidFuture<Boolean> future = new AndroidFuture<>();
+ ops.shouldOfferSwitchingToNextInputMethod(future);
+ return CompletableFutureUtil.getResult(future);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
diff --git a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
index 0c27012..2d0b3f9 100644
--- a/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
+++ b/core/java/com/android/internal/inputmethod/RemoteInputConnectionImpl.java
@@ -21,7 +21,6 @@
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
-import android.os.RemoteException;
import android.os.Trace;
import android.util.Log;
import android.util.proto.ProtoOutputStream;
@@ -40,6 +39,7 @@
import android.view.inputmethod.SurroundingText;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.view.IInputContext;
import java.lang.ref.WeakReference;
@@ -220,7 +220,10 @@
}
@Override
- public void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback) {
+ public void getTextAfterCursor(int length, int flags,
+ AndroidFuture future /* T=CharSequence */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextAfterCursor");
try {
@@ -238,12 +241,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextAfterCursor", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextAfterCursor()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -251,7 +249,10 @@
}
@Override
- public void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback) {
+ public void getTextBeforeCursor(int length, int flags,
+ AndroidFuture future /* T=CharSequence */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getTextBeforeCursor");
try {
@@ -269,12 +270,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getTextBeforeCursor", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getTextBeforeCursor()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -282,7 +278,9 @@
}
@Override
- public void getSelectedText(int flags, ICharSequenceResultCallback callback) {
+ public void getSelectedText(int flags, AndroidFuture future /* T=CharSequence */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<CharSequence> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSelectedText");
try {
@@ -300,12 +298,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSelectedText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getSelectedText()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -314,7 +307,9 @@
@Override
public void getSurroundingText(int beforeLength, int afterLength, int flags,
- ISurroundingTextResultCallback callback) {
+ AndroidFuture future /* T=SurroundingText */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<SurroundingText> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getSurroundingText");
try {
@@ -332,12 +327,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getSurroundingText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getSurroundingText()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -345,7 +335,9 @@
}
@Override
- public void getCursorCapsMode(int reqModes, IIntResultCallback callback) {
+ public void getCursorCapsMode(int reqModes, AndroidFuture future /* T=Integer */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Integer> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getCursorCapsMode");
try {
@@ -363,12 +355,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getCursorCapsMode", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getCursorCapsMode()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -377,7 +364,9 @@
@Override
public void getExtractedText(ExtractedTextRequest request, int flags,
- IExtractedTextResultCallback callback) {
+ AndroidFuture future /* T=ExtractedText */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<ExtractedText> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#getExtractedText");
try {
@@ -395,12 +384,7 @@
ImeTracing.getInstance().triggerClientDump(
TAG + "#getExtractedText", mParentInputMethodManager, icProto);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to getExtractedText()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -710,7 +694,9 @@
}
@Override
- public void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback) {
+ public void requestCursorUpdates(int cursorUpdateMode, AndroidFuture future /* T=Boolean */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Boolean> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#requestCursorUpdates");
try {
@@ -722,12 +708,7 @@
} else {
result = ic.requestCursorUpdates(cursorUpdateMode);
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to requestCursorUpdates()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
@@ -736,7 +717,9 @@
@Override
public void commitContent(InputContentInfo inputContentInfo, int flags, Bundle opts,
- IBooleanResultCallback callback) {
+ AndroidFuture future /* T=Boolean */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Boolean> typedFuture = future;
dispatch(() -> {
Trace.traceBegin(Trace.TRACE_TAG_INPUT, "InputConnection#commitContent");
try {
@@ -754,12 +737,7 @@
result = ic.commitContent(inputContentInfo, flags, opts);
}
}
- try {
- callback.onResult(result);
- } catch (RemoteException e) {
- Log.w(TAG, "Failed to return the result to commitContent()."
- + " result=" + result, e);
- }
+ typedFuture.complete(result);
} finally {
Trace.traceEnd(Trace.TRACE_TAG_INPUT);
}
diff --git a/core/java/com/android/internal/inputmethod/ResultCallbacks.java b/core/java/com/android/internal/inputmethod/ResultCallbacks.java
deleted file mode 100644
index 343a6e6..0000000
--- a/core/java/com/android/internal/inputmethod/ResultCallbacks.java
+++ /dev/null
@@ -1,261 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.inputmethod;
-
-import android.annotation.AnyThread;
-import android.annotation.BinderThread;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-
-import java.util.concurrent.atomic.AtomicReference;
-
-/**
- * Defines a set of factory methods to create {@link android.os.IBinder}-based callbacks that are
- * associated with completable objects defined in {@link Completable}.
- */
-public final class ResultCallbacks {
-
- /**
- * Not intended to be instantiated.
- */
- private ResultCallbacks() {
- }
-
- @AnyThread
- @Nullable
- private static <T> T unwrap(@NonNull AtomicReference<T> atomicRef) {
- // Only the first caller will receive the non-null original object.
- return atomicRef.getAndSet(null);
- }
-
- /**
- * Creates {@link IIntResultCallback.Stub} that is to set {@link Completable.Int} when receiving
- * the result.
- *
- * @param value {@link Completable.Int} to be set when receiving the result.
- * @return {@link IIntResultCallback.Stub} that can be passed as a binder IPC parameter.
- */
- @AnyThread
- public static IIntResultCallback.Stub of(@NonNull Completable.Int value) {
- final AtomicReference<Completable.Int> atomicRef = new AtomicReference<>(value);
-
- return new IIntResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(int result) {
- final Completable.Int value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
-
- @BinderThread
- @Override
- public void onError(ThrowableHolder throwableHolder) {
- final Completable.Int value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onError(throwableHolder);
- }
- };
- }
-
- /**
- * Creates {@link ICharSequenceResultCallback.Stub} that is to set
- * {@link Completable.CharSequence} when receiving the result.
- *
- * @param value {@link Completable.CharSequence} to be set when receiving the result.
- * @return {@link ICharSequenceResultCallback.Stub} that can be passed as a binder IPC
- * parameter.
- */
- @AnyThread
- public static ICharSequenceResultCallback.Stub of(
- @NonNull Completable.CharSequence value) {
- final AtomicReference<Completable.CharSequence> atomicRef = new AtomicReference<>(value);
-
- return new ICharSequenceResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(CharSequence result) {
- final Completable.CharSequence value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
- };
- }
-
- /**
- * Creates {@link IExtractedTextResultCallback.Stub} that is to set
- * {@link Completable.ExtractedText} when receiving the result.
- *
- * @param value {@link Completable.ExtractedText} to be set when receiving the result.
- * @return {@link IExtractedTextResultCallback.Stub} that can be passed as a binder IPC
- * parameter.
- */
- @AnyThread
- public static IExtractedTextResultCallback.Stub of(
- @NonNull Completable.ExtractedText value) {
- final AtomicReference<Completable.ExtractedText> atomicRef = new AtomicReference<>(value);
-
- return new IExtractedTextResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(android.view.inputmethod.ExtractedText result) {
- final Completable.ExtractedText value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
- };
- }
-
- /**
- * Creates {@link ISurroundingTextResultCallback.Stub} that is to set
- * {@link Completable.SurroundingText} when receiving the result.
- *
- * @param value {@link Completable.SurroundingText} to be set when receiving the result.
- * @return {@link ISurroundingTextResultCallback.Stub} that can be passed as a binder IPC
- * parameter.
- */
- @AnyThread
- public static ISurroundingTextResultCallback.Stub of(
- @NonNull Completable.SurroundingText value) {
- final AtomicReference<Completable.SurroundingText> atomicRef = new AtomicReference<>(value);
-
- return new ISurroundingTextResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(android.view.inputmethod.SurroundingText result) {
- final Completable.SurroundingText value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
- };
- }
-
- /**
- * Creates {@link IBooleanResultCallback.Stub} that is to set {@link Completable.Boolean} when
- * receiving the result.
- *
- * @param value {@link Completable.Boolean} to be set when receiving the result.
- * @return {@link IBooleanResultCallback.Stub} that can be passed as a binder IPC parameter.
- */
- @AnyThread
- public static IBooleanResultCallback.Stub of(@NonNull Completable.Boolean value) {
- final AtomicReference<Completable.Boolean> atomicRef = new AtomicReference<>(value);
-
- return new IBooleanResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(boolean result) {
- final Completable.Boolean value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
-
- @BinderThread
- @Override
- public void onError(ThrowableHolder throwableHolder) {
- final Completable.Boolean value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onError(throwableHolder);
- }
- };
- }
-
- /**
- * Creates {@link IVoidResultCallback.Stub} that is to set {@link Completable.Void} when
- * receiving the result.
- *
- * @param value {@link Completable.Void} to be set when receiving the result.
- * @return {@link IVoidResultCallback.Stub} that can be passed as a binder IPC parameter.
- */
- @AnyThread
- public static IVoidResultCallback.Stub of(@NonNull Completable.Void value) {
- final AtomicReference<Completable.Void> atomicRef = new AtomicReference<>(value);
-
- return new IVoidResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult() {
- final Completable.Void value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete();
- }
-
- @BinderThread
- @Override
- public void onError(ThrowableHolder throwableHolder) {
- final Completable.Void value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onError(throwableHolder);
- }
- };
- }
-
- /**
- * Creates {@link IInputContentUriTokenResultCallback.Stub} that is to set
- * {@link Completable.IInputContentUriToken} when receiving the result.
- *
- * @param value {@link Completable.IInputContentUriToken} to be set when receiving the result.
- * @return {@link IInputContentUriTokenResultCallback.Stub} that can be passed as a binder IPC
- * parameter.
- */
- @AnyThread
- public static IInputContentUriTokenResultCallback.Stub of(
- @NonNull Completable.IInputContentUriToken value) {
- final AtomicReference<Completable.IInputContentUriToken>
- atomicRef = new AtomicReference<>(value);
-
- return new IInputContentUriTokenResultCallback.Stub() {
- @BinderThread
- @Override
- public void onResult(IInputContentUriToken result) {
- final Completable.IInputContentUriToken value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onComplete(result);
- }
-
- @BinderThread
- @Override
- public void onError(ThrowableHolder throwableHolder) {
- final Completable.IInputContentUriToken value = unwrap(atomicRef);
- if (value == null) {
- return;
- }
- value.onError(throwableHolder);
- }
- };
- }
-}
diff --git a/core/java/com/android/internal/view/IInputContext.aidl b/core/java/com/android/internal/view/IInputContext.aidl
index dd42c40e..12a98c1 100644
--- a/core/java/com/android/internal/view/IInputContext.aidl
+++ b/core/java/com/android/internal/view/IInputContext.aidl
@@ -23,11 +23,7 @@
import android.view.inputmethod.ExtractedTextRequest;
import android.view.inputmethod.InputContentInfo;
-import com.android.internal.inputmethod.IBooleanResultCallback;
-import com.android.internal.inputmethod.ICharSequenceResultCallback;
-import com.android.internal.inputmethod.IExtractedTextResultCallback;
-import com.android.internal.inputmethod.IIntResultCallback;
-import com.android.internal.inputmethod.ISurroundingTextResultCallback;
+import com.android.internal.infra.AndroidFuture;
/**
* Interface from an input method to the application, allowing it to perform
@@ -35,14 +31,14 @@
* {@hide}
*/
oneway interface IInputContext {
- void getTextBeforeCursor(int length, int flags, ICharSequenceResultCallback callback);
+ void getTextBeforeCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
- void getTextAfterCursor(int length, int flags, ICharSequenceResultCallback callback);
+ void getTextAfterCursor(int length, int flags, in AndroidFuture future /* T=CharSequence */);
- void getCursorCapsMode(int reqModes, IIntResultCallback callback);
+ void getCursorCapsMode(int reqModes, in AndroidFuture future /* T=Integer */);
void getExtractedText(in ExtractedTextRequest request, int flags,
- IExtractedTextResultCallback callback);
+ in AndroidFuture future /* T=ExtractedText */);
void deleteSurroundingText(int beforeLength, int afterLength);
void deleteSurroundingTextInCodePoints(int beforeLength, int afterLength);
@@ -50,7 +46,7 @@
void setComposingText(CharSequence text, int newCursorPosition);
void finishComposingText();
-
+
void commitText(CharSequence text, int newCursorPosition);
void commitCompletion(in CompletionInfo completion);
@@ -58,34 +54,34 @@
void commitCorrection(in CorrectionInfo correction);
void setSelection(int start, int end);
-
+
void performEditorAction(int actionCode);
-
+
void performContextMenuAction(int id);
-
+
void beginBatchEdit();
-
+
void endBatchEdit();
void sendKeyEvent(in KeyEvent event);
-
+
void clearMetaKeyStates(int states);
-
+
void performSpellCheck();
void performPrivateCommand(String action, in Bundle data);
void setComposingRegion(int start, int end);
- void getSelectedText(int flags, ICharSequenceResultCallback callback);
+ void getSelectedText(int flags, in AndroidFuture future /* T=CharSequence */);
- void requestCursorUpdates(int cursorUpdateMode, IBooleanResultCallback callback);
+ void requestCursorUpdates(int cursorUpdateMode, in AndroidFuture future /* T=Boolean */);
void commitContent(in InputContentInfo inputContentInfo, int flags, in Bundle opts,
- IBooleanResultCallback callback);
+ in AndroidFuture future /* T=Boolean */);
void getSurroundingText(int beforeLength, int afterLength, int flags,
- ISurroundingTextResultCallback callback);
+ in AndroidFuture future /* T=SurroundingText */);
void setImeConsumesInput(boolean imeConsumesInput);
}
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index a398c35..43e7fd6 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড HCOলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড VCO লৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"নেটৱৰ্ক পীয়েৰে TTY ম\'ড OFFলৈ সলনি কৰিবলৈ অনুৰোধ কৰিছে"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"কণ্ঠস্বৰ"</string>
<string name="serviceClassData" msgid="4148080018967300248">"ডেটা"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"ফেক্স"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"এছএমএছ"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"কৰ্মস্থানৰ ম’বাইল নম্বৰ"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"কৰ্মস্থানৰ পেজাৰৰ নম্বৰ"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"সহায়ক"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"এমএমএছ"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"নিজৰ উপযোগিতা অনুযায়ী"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"জন্মদিন"</string>
@@ -848,7 +848,7 @@
<string name="orgTypeOther" msgid="5450675258408005553">"অন্যান্য"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"নিজৰ উপযোগিতা অনুযায়ী"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"নিজৰ উপযোগিতা অনুযায়ী"</string>
- <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+ <string name="relationTypeAssistant" msgid="4057605157116589315">"সহায়ক"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"ভাতৃ"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"শিশু"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"সংগী"</string>
@@ -1038,9 +1038,9 @@
<string name="menu_space_shortcut_label" msgid="5949311515646872071">"স্পেচ"</string>
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"লিখক"</string>
<string name="menu_delete_shortcut_label" msgid="4365787714477739080">"মচক"</string>
- <string name="search_go" msgid="2141477624421347086">"Search"</string>
- <string name="search_hint" msgid="455364685740251925">"অনুসন্ধান কৰক…"</string>
- <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+ <string name="search_go" msgid="2141477624421347086">"সন্ধান কৰক"</string>
+ <string name="search_hint" msgid="455364685740251925">"সন্ধান কৰক…"</string>
+ <string name="searchview_description_search" msgid="1045552007537359343">"সন্ধান কৰক"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"প্ৰশ্নৰ সন্ধান কৰক"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"প্ৰশ্ন মচক"</string>
<string name="searchview_description_submit" msgid="6771060386117334686">"প্ৰশ্ন দাখিল কৰক"</string>
@@ -1468,7 +1468,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"জুম নিয়ন্ত্ৰণ কৰিবলৈ দুবাৰ টিপক"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ৱিজেট যোগ কৰিব পৰা নগ\'ল।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"যাওক"</string>
- <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+ <string name="ime_action_search" msgid="4501435960587287668">"সন্ধান কৰক"</string>
<string name="ime_action_send" msgid="8456843745664334138">"পঠিয়াওক"</string>
<string name="ime_action_next" msgid="4169702997635728543">"পৰৱৰ্তী"</string>
<string name="ime_action_done" msgid="6299921014822891569">"সম্পন্ন হ’ল"</string>
@@ -1973,7 +1973,7 @@
<string name="language_picker_section_suggested" msgid="6556199184638990447">"প্ৰস্তাৱিত"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"সকলো ভাষা"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"সকলো অঞ্চল"</string>
- <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+ <string name="locale_search_menu" msgid="6258090710176422934">"সন্ধান কৰক"</string>
<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>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index a4726cf..a1a1731 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -972,7 +972,7 @@
<string name="keyguard_accessibility_pattern_area" msgid="1419570880512350689">"Вобласць узора."</string>
<string name="keyguard_accessibility_slide_area" msgid="4331399051142520176">"Вобласць слайда."</string>
<string name="password_keyboard_label_symbol_key" msgid="2716255580853511949">"123"</string>
- <string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"ABC"</string>
+ <string name="password_keyboard_label_alpha_key" msgid="5294837425652726684">"АБВ"</string>
<string name="password_keyboard_label_alt_key" msgid="8528261816395508841">"Alt"</string>
<string name="granularity_label_character" msgid="8903387663153706317">"Знак"</string>
<string name="granularity_label_word" msgid="3686589158760620518">"слова"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 710e943..540e7bd 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"પીઅરે TTY મોડ HCO ની વિનંતી કરી"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"પીઅરે TTY મોડ VCO ની વિનંતી કરી"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"પીઅરે TTY મોડ બંધ કરવાની વિનંતી કરી"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"વૉઇસ"</string>
<string name="serviceClassData" msgid="4148080018967300248">"ડેટા"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"ફેક્સ"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"તમારા સંપર્કોને ઍક્સેસ કરવાની"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"સ્થાન"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"કૅલેન્ડર"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS સંદેશા મોકલવાની અને જોવાની"</string>
@@ -848,7 +848,7 @@
<string name="orgTypeOther" msgid="5450675258408005553">"અન્ય"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"કસ્ટમ"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"કસ્ટમ"</string>
- <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+ <string name="relationTypeAssistant" msgid="4057605157116589315">"આસિસ્ટંટ"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"ભાઈ"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"બાળક"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"ઘરેલું ભાગીદાર"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index 4d328d3..c6ae32a 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"ನಿಮ್ಮ ಸಂಪರ್ಕಗಳನ್ನು ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"ಸ್ಥಳ"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"ಈ ಸಾಧನದ ಸ್ಥಳವನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"ಕ್ಯಾಲೆಂಡರ್"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"ನಿಮ್ಮ ಕ್ಯಾಲೆಂಡರ್ ಪ್ರವೇಶಿಸಲು"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ಸಂದೇಶಗಳನ್ನು ಕಳುಹಿಸಲು ಮತ್ತು ನಿರ್ವಹಿಸಲು"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ಕಚೇರಿ ಮೊಬೈಲ್"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"ಕಚೇರಿ ಪೇಜರ್"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"ಅಸಿಸ್ಟೆಂಟ್"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"ಕಸ್ಟಮ್"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"ಜನ್ಮದಿನ"</string>
@@ -848,7 +848,7 @@
<string name="orgTypeOther" msgid="5450675258408005553">"ಇತರೆ"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"ಕಸ್ಟಮ್"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"ಕಸ್ಟಮ್"</string>
- <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+ <string name="relationTypeAssistant" msgid="4057605157116589315">"ಅಸಿಸ್ಟೆಂಟ್"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"ಸಹೋದರ"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"ಮಗು"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"ಸ್ಥಳೀಯ ಪಾಲುದಾರ"</string>
@@ -1038,9 +1038,9 @@
<string name="menu_space_shortcut_label" msgid="5949311515646872071">"space"</string>
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ಅಳಿಸಿ"</string>
- <string name="search_go" msgid="2141477624421347086">"Search"</string>
+ <string name="search_go" msgid="2141477624421347086">"ಹುಡುಕಿ"</string>
<string name="search_hint" msgid="455364685740251925">"ಹುಡುಕಿ…"</string>
- <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+ <string name="searchview_description_search" msgid="1045552007537359343">"ಹುಡುಕಿ"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"ಪ್ರಶ್ನೆಯನ್ನು ಹುಡುಕಿ"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"ಪ್ರಶ್ನೆಯನ್ನು ತೆರವುಗೊಳಿಸು"</string>
<string name="searchview_description_submit" msgid="6771060386117334686">"ಪ್ರಶ್ನೆಯನ್ನು ಸಲ್ಲಿಸು"</string>
@@ -1468,7 +1468,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ಝೂಮ್ ನಿಯಂತ್ರಿಸಲು ಎರಡು ಬಾರಿ ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ವಿಜೆಟ್ ಸೇರಿಸಲು ಸಾಧ್ಯವಾಗುತ್ತಿಲ್ಲ."</string>
<string name="ime_action_go" msgid="5536744546326495436">"ಹೋಗು"</string>
- <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+ <string name="ime_action_search" msgid="4501435960587287668">"ಹುಡುಕಿ"</string>
<string name="ime_action_send" msgid="8456843745664334138">"ಕಳುಹಿಸು"</string>
<string name="ime_action_next" msgid="4169702997635728543">"ಮುಂದೆ"</string>
<string name="ime_action_done" msgid="6299921014822891569">"ಮುಗಿದಿದೆ"</string>
@@ -1973,7 +1973,7 @@
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ಸೂಚಿತ ಭಾಷೆ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ಎಲ್ಲಾ ಭಾಷೆಗಳು"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ಎಲ್ಲಾ ಪ್ರದೇಶಗಳು"</string>
- <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+ <string name="locale_search_menu" msgid="6258090710176422934">"ಹುಡುಕಿ"</string>
<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>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index d6491b7..5e8b1f1 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് HCO"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് VCO"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"പിയർ അഭ്യർത്ഥിച്ച TTY മോഡ് \'ഓഫ്\'"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"ശബ്ദം"</string>
<string name="serviceClassData" msgid="4148080018967300248">"ഡാറ്റ"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"ഫാക്സ്"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ഓഫീസ് മൊബൈല്"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"ഔദ്യോഗിക പേജര്"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"അസിസ്റ്റന്റ്"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"അസിസ്റ്റന്റ്"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"ഇഷ്ടാനുസൃതം"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"ജന്മദിനം"</string>
@@ -1038,9 +1038,9 @@
<string name="menu_space_shortcut_label" msgid="5949311515646872071">"space"</string>
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="4365787714477739080">"delete"</string>
- <string name="search_go" msgid="2141477624421347086">"Search"</string>
+ <string name="search_go" msgid="2141477624421347086">"തിരയുക"</string>
<string name="search_hint" msgid="455364685740251925">"തിരയുക…"</string>
- <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+ <string name="searchview_description_search" msgid="1045552007537359343">"തിരയുക"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"തിരയൽ അന്വേഷണം"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"അന്വേഷണം മായ്ക്കുക"</string>
<string name="searchview_description_submit" msgid="6771060386117334686">"ചോദ്യം സമർപ്പിക്കുക"</string>
@@ -1468,7 +1468,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"സൂം നിയന്ത്രണം ലഭിക്കാൻ രണ്ടുതവണ ടാപ്പുചെയ്യുക"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"വിജറ്റ് ചേർക്കാനായില്ല."</string>
<string name="ime_action_go" msgid="5536744546326495436">"പോവുക"</string>
- <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+ <string name="ime_action_search" msgid="4501435960587287668">"തിരയുക"</string>
<string name="ime_action_send" msgid="8456843745664334138">"അയയ്ക്കുക"</string>
<string name="ime_action_next" msgid="4169702997635728543">"അടുത്തത്"</string>
<string name="ime_action_done" msgid="6299921014822891569">"പൂർത്തിയായി"</string>
@@ -1973,7 +1973,7 @@
<string name="language_picker_section_suggested" msgid="6556199184638990447">"നിര്ദ്ദേശിച്ചത്"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"എല്ലാ ഭാഷകളും"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"എല്ലാ പ്രദേശങ്ങളും"</string>
- <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+ <string name="locale_search_menu" msgid="6258090710176422934">"തിരയുക"</string>
<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>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 7c120f4..424a521 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"कार्य मोबाइल"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"कार्य पेजर"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"असिस्टंट"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"कस्टम"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"वाढदिवस"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 7d27d4e..9d42402 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1038,9 +1038,9 @@
<string name="menu_space_shortcut_label" msgid="5949311515646872071">"ସ୍ପେସ୍"</string>
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"ଏଣ୍ଟର୍"</string>
<string name="menu_delete_shortcut_label" msgid="4365787714477739080">"ଡିଲିଟ୍ କରନ୍ତୁ"</string>
- <string name="search_go" msgid="2141477624421347086">"Search"</string>
- <string name="search_hint" msgid="455364685740251925">"ସର୍ଚ୍ଚ…"</string>
- <string name="searchview_description_search" msgid="1045552007537359343">"Search"</string>
+ <string name="search_go" msgid="2141477624421347086">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
+ <string name="search_hint" msgid="455364685740251925">"ସନ୍ଧାନ…"</string>
+ <string name="searchview_description_search" msgid="1045552007537359343">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"କ୍ୱେରୀ ସର୍ଚ୍ଚ କରନ୍ତୁ"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"କ୍ୱେରୀ ଖାଲି କରନ୍ତୁ"</string>
<string name="searchview_description_submit" msgid="6771060386117334686">"କ୍ୱେରୀ ଦାଖଲ କରନ୍ତୁ"</string>
@@ -1468,7 +1468,7 @@
<string name="tutorial_double_tap_to_zoom_message_short" msgid="1842872462124648678">"ଜୁମ୍ ନିୟନ୍ତ୍ରଣ ପାଇଁ ଦୁଇଥର ଟାପ୍ କରନ୍ତୁ"</string>
<string name="gadget_host_error_inflating" msgid="2449961590495198720">"ୱିଜେଟ୍ ଯୋଡ଼ିପାରିବ ନାହିଁ।"</string>
<string name="ime_action_go" msgid="5536744546326495436">"ଯାଆନ୍ତୁ"</string>
- <string name="ime_action_search" msgid="4501435960587287668">"Search"</string>
+ <string name="ime_action_search" msgid="4501435960587287668">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="ime_action_send" msgid="8456843745664334138">"ପଠାନ୍ତୁ"</string>
<string name="ime_action_next" msgid="4169702997635728543">"ପରବର୍ତ୍ତୀ"</string>
<string name="ime_action_done" msgid="6299921014822891569">"ହୋଇଗଲା"</string>
@@ -1973,7 +1973,7 @@
<string name="language_picker_section_suggested" msgid="6556199184638990447">"ପ୍ରସ୍ତାବିତ"</string>
<string name="language_picker_section_all" msgid="1985809075777564284">"ସମସ୍ତ ଭାଷା"</string>
<string name="region_picker_section_all" msgid="756441309928774155">"ସମସ୍ତ ଅଞ୍ଚଳ"</string>
- <string name="locale_search_menu" msgid="6258090710176422934">"Search"</string>
+ <string name="locale_search_menu" msgid="6258090710176422934">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<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>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 12bf1bb..7577457 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"ਆਪਣੇ ਸੰਪਰਕਾਂ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"ਟਿਕਾਣਾ"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"ਇਸ ਡੀਵਾਈਸ ਦੇ ਨਿਰਧਾਰਤ ਟਿਕਾਣੇ ਤੱਕ ਪਹੁੰਚੋ"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"ਕੈਲੰਡਰ"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"ਤੁਹਾਡੇ ਕੈਲੰਡਰ ਤੱਕ ਪਹੁੰਚ ਕਰਨ"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS ਸੁਨੇਹੇ ਭੇਜੋ ਅਤੇ ਦੇਖੋ"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"ਕੰਮ ਦਾ ਮੋਬਾਈਲ"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"ਦਫ਼ਤਰ ਦਾ ਪੇਜਰ"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"ਸਹਾਇਕ"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"ਵਿਉਂਂਤੀ"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"ਜਨਮਦਿਨ"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index cb18e2c..80f55c6 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -322,7 +322,7 @@
<string name="permgroupdesc_microphone" msgid="1047786732792487722">"nahrávanie zvuku"</string>
<string name="permgrouplab_activityRecognition" msgid="3324466667921775766">"Fyzická aktivita"</string>
<string name="permgroupdesc_activityRecognition" msgid="4725624819457670704">"prístup k vašej fyzickej aktivite"</string>
- <string name="permgrouplab_camera" msgid="9090413408963547706">"Fotoaparát"</string>
+ <string name="permgrouplab_camera" msgid="9090413408963547706">"Kamera"</string>
<string name="permgroupdesc_camera" msgid="7585150538459320326">"fotenie a natáčanie videí"</string>
<string name="permgrouplab_nearby_devices" msgid="5529147543651181991">"Zariadenia v okolí"</string>
<string name="permgroupdesc_nearby_devices" msgid="3213561597116913508">"objavovať a pripájať zariadenia v okolí"</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index ffd5078..c6b6b77 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"TTY Mode HCOஐ இணைச் செயல்பாடு கோரியது"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"TTY Mode VCOஐ இணைச் செயல்பாடு கோரியது"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"TTY Mode OFFஐ இணைச் செயல்பாடு கோரியது"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"குரல்"</string>
<string name="serviceClassData" msgid="4148080018967300248">"தரவு"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"தொலைநகல்"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -815,7 +815,7 @@
<string name="phoneTypeTtyTdd" msgid="532038552105328779">"TTY TDD"</string>
<string name="phoneTypeWorkMobile" msgid="7522314392003565121">"பணியிட மொபைல்"</string>
<string name="phoneTypeWorkPager" msgid="3748332310638505234">"பணியிட பேஜர்"</string>
- <string name="phoneTypeAssistant" msgid="757550783842231039">"Assistant"</string>
+ <string name="phoneTypeAssistant" msgid="757550783842231039">"உதவியாளர்"</string>
<string name="phoneTypeMms" msgid="1799747455131365989">"MMS"</string>
<string name="eventTypeCustom" msgid="3257367158986466481">"பிரத்தியேகம்"</string>
<string name="eventTypeBirthday" msgid="7770026752793912283">"பிறந்தநாள்"</string>
@@ -848,7 +848,7 @@
<string name="orgTypeOther" msgid="5450675258408005553">"மற்றவை"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"பிரத்தியேகம்"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"பிரத்தியேகம்"</string>
- <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+ <string name="relationTypeAssistant" msgid="4057605157116589315">"உதவியாளர்"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"சகோதரர்"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"குழந்தை"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"வாழ்வுத் துணை"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index f3d2faa..478886a 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -71,10 +71,10 @@
<string name="RuacMmi" msgid="1876047385848991110">"అవాంఛిత అంతరాయ కాల్స్ల తిరస్కరణ"</string>
<string name="CndMmi" msgid="185136449405618437">"కాలింగ్ నంబర్ బట్వాడా"</string>
<string name="DndMmi" msgid="8797375819689129800">"అంతరాయం కలిగించవద్దు"</string>
- <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"కాలర్ ID డిఫాల్ట్గా పరిమితానికి ఉంటుంది. తర్వాత కాల్: పరిమితం చేయబడింది"</string>
- <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"కాలర్ ID డిఫాల్ట్గా పరిమితానికి ఉంటుంది. తర్వాత కాల్: అపరిమితం"</string>
- <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"కాలర్ ID డిఫాల్ట్గా అపరిమితానికి ఉంటుంది. తర్వాత కాల్: పరిమితం చేయబడింది"</string>
- <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"కాలర్ ID డిఫాల్ట్గా అపరిమితానికి ఉంటుంది. తర్వాత కాల్: అపరిమితం"</string>
+ <string name="CLIRDefaultOnNextCallOn" msgid="4511621022859867988">"కాలర్ ID ఆటోమేటిక్లపై పరిమితి ఉంటుంది. తర్వాత కాల్: పరిమితి ఉంటుంది"</string>
+ <string name="CLIRDefaultOnNextCallOff" msgid="5036749051007098105">"కాలర్ ID ఆటోమేటిక్లపై పరిమితి ఉంటుంది. తర్వాత కాల్: పరిమితి లేదు"</string>
+ <string name="CLIRDefaultOffNextCallOn" msgid="1022781126694885017">"కాలర్ ID ఆటోమేటిక్లపై పరిమితి లేదు. తర్వాత కాల్: పరిమితి ఉంటుంది"</string>
+ <string name="CLIRDefaultOffNextCallOff" msgid="2491576172356463443">"కాలర్ ID ఆటోమేటిక్లపై పరిమితి లేదు. తర్వాత కాల్: పరిమితి లేదు"</string>
<string name="serviceNotProvisioned" msgid="8289333510236766193">"సేవ కేటాయించబడలేదు."</string>
<string name="CLIRPermanent" msgid="166443681876381118">"మీరు కాలర్ ID సెట్టింగ్ను మార్చలేరు."</string>
<string name="RestrictedOnDataTitle" msgid="1500576417268169774">"మొబైల్ డేటా సేవ లేదు"</string>
@@ -100,7 +100,7 @@
<string name="peerTtyModeHco" msgid="5626377160840915617">"అవతలి వారు HCO TTY మోడ్ని అభ్యర్థించారు"</string>
<string name="peerTtyModeVco" msgid="572208600818270944">"అవతలి వారు VCO TTY మోడ్ని అభ్యర్థించారు"</string>
<string name="peerTtyModeOff" msgid="2420380956369226583">"అవతలి వారు OFF TTY మోడ్ని అభ్యర్థించారు"</string>
- <string name="serviceClassVoice" msgid="2065556932043454987">"Voice"</string>
+ <string name="serviceClassVoice" msgid="2065556932043454987">"వాయిస్"</string>
<string name="serviceClassData" msgid="4148080018967300248">"డేటా"</string>
<string name="serviceClassFAX" msgid="2561653371698904118">"ఫ్యాక్స్"</string>
<string name="serviceClassSMS" msgid="1547664561704509004">"SMS"</string>
@@ -306,7 +306,7 @@
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ కాంటాక్ట్లను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"లొకేషన్"</string>
<string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgrouplab_calendar" msgid="6426860926123033230">"క్యాలెండర్"</string>
<string name="permgroupdesc_calendar" msgid="6762751063361489379">"మీ క్యాలెండర్ను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
<string name="permgroupdesc_sms" msgid="5726462398070064542">"SMS మెసేజ్లను పంపడం మరియు వీక్షించడం"</string>
@@ -435,8 +435,8 @@
<string name="permdesc_writeCalendar" product="tv" msgid="951246749004952706">"ఈ యాప్ మీ Android TV పరికరంలో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permdesc_writeCalendar" product="default" msgid="5416380074475634233">"ఈ యాప్ మీ ఫోన్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<string name="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడం"</string>
- <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు స్థాన ప్రదాత ఆదేశాలను యాక్సెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర స్థాన మూలాల నిర్వహణలో యాప్ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
- <string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన స్థానాన్ని యాక్సెస్ చేయండి"</string>
+ <string name="permdesc_accessLocationExtraCommands" msgid="355369611979907967">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్లను యాక్సెస్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఇది GPS లేదా ఇతర లొకేషన్ సోర్స్ల నిర్వహణలో యాప్ ప్రమేయం ఉండేలా అనుమతించవచ్చు."</string>
+ <string name="permlab_accessFineLocation" msgid="6426318438195622966">"స్క్రీన్పై ఉన్నప్పుడు మాత్రమే ఖచ్చితమైన లొకేషన్ను యాక్సెస్ చేయండి"</string>
<string name="permdesc_accessFineLocation" msgid="6732174080240016335">"యాప్ ఉపయోగంలో ఉన్నప్పుడు మాత్రమే ఈ యాప్ మీ ఖచ్చితమైన లొకేషన్ను లొకేషన్ సర్వీస్ల ద్వారా తెలుసుకోగలదు. లొకేషన్ను యాప్ పొందాలంటే, దాని కోసం మీ పరికరం యొక్క లొకేషన్ సర్వీస్లను తప్పనిసరిగా ఆన్ చేయాలి. ఇది బ్యాటరీ వినియోగాన్ని పెంచవచ్చు."</string>
<string name="permlab_accessCoarseLocation" msgid="1561042925407799741">"స్క్రీన్పై ఉన్నప్పుడు మాత్రమే సుమారు లొకేషన్ను యాక్సెస్ చేయండి"</string>
<string name="permdesc_accessCoarseLocation" msgid="778521847873199160">"యాప్ ఉపయోగంలో ఉన్నప్పుడు మాత్రమే ఈ యాప్ మీ ఇంచుమించు లొకేషన్ను లొకేషన్ సర్వీస్ల నుండి తెలుసుకోగలదు. లొకేషన్ను యాప్ పొందాలంటే, దాని కోసం మీ పరికరం యొక్క లొకేషన్ సర్వీస్లను తప్పనిసరిగా ఆన్ చేయాలి."</string>
@@ -848,7 +848,7 @@
<string name="orgTypeOther" msgid="5450675258408005553">"ఇతరం"</string>
<string name="orgTypeCustom" msgid="1126322047677329218">"అనుకూలం"</string>
<string name="relationTypeCustom" msgid="282938315217441351">"అనుకూలం"</string>
- <string name="relationTypeAssistant" msgid="4057605157116589315">"Assistant"</string>
+ <string name="relationTypeAssistant" msgid="4057605157116589315">"అసిస్టెంట్"</string>
<string name="relationTypeBrother" msgid="7141662427379247820">"సోదరుడు"</string>
<string name="relationTypeChild" msgid="9076258911292693601">"బిడ్డ"</string>
<string name="relationTypeDomesticPartner" msgid="7825306887697559238">"జీవిత భాగస్వామి"</string>
@@ -916,12 +916,12 @@
<string name="lockscreen_failed_attempts_almost_glogin" product="tablet" msgid="3069635524964070596">"మీరు మీ అన్లాక్ నమూనాని <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="lockscreen_failed_attempts_almost_glogin" product="tv" msgid="6399092175942158529">"మీరు మీ అన్లాక్ నమూనాని <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీరు మీ Google సైన్ఇన్ను ఉపయోగించి మీ Android TV పరికరాన్ని అన్లాక్ చేయాల్సిందిగా మీకు తెలపబడుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_failed_attempts_almost_glogin" product="default" msgid="5691623136957148335">"మీరు మీ అన్లాక్ నమూనాని <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="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
- <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> వైఫల్య ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tablet" msgid="7914445759242151426">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="tv" msgid="4275591249631864248">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే యూజర్ డేటా మొత్తాన్ని కోల్పోతారు."</string>
+ <string name="lockscreen_failed_attempts_almost_at_wipe" product="default" msgid="1166532464798446579">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్, ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="tablet" msgid="8682445539263683414">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string>
<string name="lockscreen_failed_attempts_now_wiping" product="tv" msgid="2205435033340091883">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
- <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="lockscreen_failed_attempts_now_wiping" product="default" msgid="2203704707679895487">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు తప్పుగా ప్రయత్నించారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string>
<string name="lockscreen_too_many_failed_attempts_countdown" msgid="6807200118164539589">"<xliff:g id="NUMBER">%d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="lockscreen_forgot_pattern_button_text" msgid="8362442730606839031">"నమూనాను మర్చిపోయారా?"</string>
<string name="lockscreen_glogin_forgot_pattern" msgid="9218940117797602518">"ఖాతా అన్లాక్"</string>
@@ -1014,7 +1014,7 @@
<string name="permlab_addVoicemail" msgid="4770245808840814471">"వాయిస్ మెయిల్ను జోడించడం"</string>
<string name="permdesc_addVoicemail" msgid="5470312139820074324">"మీ వాయిస్ మెయిల్ ఇన్బాక్స్కి మెసేజ్లను జోడించడానికి యాప్ను అనుమతిస్తుంది."</string>
<string name="permlab_writeGeolocationPermissions" msgid="8605631647492879449">"బ్రౌజర్ భౌగోళిక స్థానం అనుమతులను సవరించడం"</string>
- <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక స్థానం అనుమతులను సవరించడానికి యాప్ను అనుమతిస్తుంది. హానికరమైన యాప్లు ఏకపక్ష వెబ్ సైట్లకు స్థాన సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
+ <string name="permdesc_writeGeolocationPermissions" msgid="5817346421222227772">"బ్రౌజర్ యొక్క భౌగోళిక లొకేషన్ అనుమతులను సవరించడానికి యాప్ను అనుమతిస్తుంది. హానికరమైన యాప్లు ఏకపక్ష వెబ్ సైట్లకు లొకేషన్ సమాచారాన్ని అనుమతించడానికి దీన్ని ఉపయోగించవచ్చు."</string>
<string name="save_password_message" msgid="2146409467245462965">"మీరు బ్రౌజర్ ఈ పాస్వర్డ్ను గుర్తుపెట్టుకోవాలని కోరుకుంటున్నారా?"</string>
<string name="save_password_notnow" msgid="2878327088951240061">"ఇప్పుడు కాదు"</string>
<string name="save_password_remember" msgid="6490888932657708341">"గుర్తుంచుకో"</string>
@@ -1039,7 +1039,7 @@
<string name="menu_enter_shortcut_label" msgid="6709499510082897320">"enter"</string>
<string name="menu_delete_shortcut_label" msgid="4365787714477739080">"delete"</string>
<string name="search_go" msgid="2141477624421347086">"సెర్చ్"</string>
- <string name="search_hint" msgid="455364685740251925">"వెతుకు..."</string>
+ <string name="search_hint" msgid="455364685740251925">"సెర్చ్ చేయండి..."</string>
<string name="searchview_description_search" msgid="1045552007537359343">"సెర్చ్"</string>
<string name="searchview_description_query" msgid="7430242366971716338">"ప్రశ్నను వెతకండి"</string>
<string name="searchview_description_clear" msgid="1989371719192982900">"ప్రశ్నను క్లియర్ చేయి"</string>
@@ -1198,7 +1198,7 @@
<string name="whichEditApplicationNamed" msgid="8096494987978521514">"%1$sతో సవరించు"</string>
<string name="whichEditApplicationLabel" msgid="1463288652070140285">"సవరించు"</string>
<string name="whichSendApplication" msgid="4143847974460792029">"షేర్ చేయండి"</string>
- <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో భాగస్వామ్యం చేయి"</string>
+ <string name="whichSendApplicationNamed" msgid="4470386782693183461">"%1$sతో షేర్ చేయండి"</string>
<string name="whichSendApplicationLabel" msgid="7467813004769188515">"షేర్ చేయి"</string>
<string name="whichSendToApplication" msgid="77101541959464018">"దీన్ని ఉపయోగించి పంపండి"</string>
<string name="whichSendToApplicationNamed" msgid="3385686512014670003">"%1$sని ఉపయోగించి పంపండి"</string>
@@ -1209,9 +1209,9 @@
<string name="whichImageCaptureApplication" msgid="2737413019463215284">"దీనితో చిత్రాన్ని క్యాప్చర్ చేయి"</string>
<string name="whichImageCaptureApplicationNamed" msgid="8820702441847612202">"%1$sతో చిత్రాన్ని క్యాప్చర్ చేయండి"</string>
<string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"చిత్రాన్ని క్యాప్చర్ చేయి"</string>
- <string name="alwaysUse" msgid="3153558199076112903">"ఈ చర్యకు డిఫాల్ట్గా ఉపయోగించండి."</string>
+ <string name="alwaysUse" msgid="3153558199076112903">"ఈ చర్యకు ఆటోమేటిక్గా ఉపయోగించండి."</string>
<string name="use_a_different_app" msgid="4987790276170972776">"వేరొక యాప్ను ఉపయోగించండి"</string>
- <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్లు > యాప్లు > డౌన్లోడ్ చేయబడినవిలో డిఫాల్ట్ను క్లియర్ చేయి."</string>
+ <string name="clearDefaultHintMsg" msgid="1325866337702524936">"సిస్టమ్ సెట్టింగ్లు > యాప్లు > డౌన్లోడ్ చేయబడినవిలో ఆటోమేటిక్ను క్లియర్ చేయి."</string>
<string name="chooseActivity" msgid="8563390197659779956">"చర్యను ఎంచుకోండి"</string>
<string name="chooseUsbActivity" msgid="2096269989990986612">"USB పరికరం కోసం యాప్ను ఎంచుకోండి"</string>
<string name="noApplications" msgid="1186909265235544019">"ఈ చర్యను అమలు చేయగల యాప్లు ఏవీ లేవు."</string>
@@ -1275,7 +1275,7 @@
<string name="dump_heap_notification" msgid="5316644945404825032">"<xliff:g id="PROC">%1$s</xliff:g> మెమరీ పరిమితిని మించిపోయింది"</string>
<string name="dump_heap_ready_notification" msgid="2302452262927390268">"<xliff:g id="PROC">%1$s</xliff:g> హీప్ డంప్ సిద్ధంగా ఉంది"</string>
<string name="dump_heap_notification_detail" msgid="8431586843001054050">"కుప్పలు తెప్పలుగా సేకరించబడింది. షేర్ చేయడానికి నొక్కండి"</string>
- <string name="dump_heap_title" msgid="4367128917229233901">"హీప్ డంప్ను భాగస్వామ్యం చేయాలా?"</string>
+ <string name="dump_heap_title" msgid="4367128917229233901">"హీప్ డంప్ను షేర్ చేయాలా?"</string>
<string name="dump_heap_text" msgid="1692649033835719336">"ఈ <xliff:g id="PROC">%1$s</xliff:g> ప్రాసెస్ దీని మెమరీ పరిమితి అయిన <xliff:g id="SIZE">%2$s</xliff:g>ని మించిపోయింది. మీరు దీని డెవలపర్తో షేర్ చేయడానికి హీప్ డంప్ అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్లో అప్లికేషన్ యాక్సెస్ కలిగి ఉన్న మీ వ్యక్తిగత సమాచారం ఏదైనా ఉండవచ్చు."</string>
<string name="dump_heap_system_text" msgid="6805155514925350849">"ఈ <xliff:g id="PROC">%1$s</xliff:g> ప్రాసెస్ దాని మెమరీ పరిమితి <xliff:g id="SIZE">%2$s</xliff:g>ని మించిపోయింది. మీరు షేర్ చేయడానికి హీప్ డంప్ అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్ ప్రాసెస్ విధానంలో గోప్యమైన వ్యక్తిగత సమాచారం యాక్సెస్ చేసే అవకాశం ఉంది, వీటిలో మీరు టైప్ చేసే అంశాలు కూడా ఉండవచ్చు."</string>
<string name="dump_heap_ready_text" msgid="5849618132123045516">"మీరు షేర్ చేయదలుచుకున్న <xliff:g id="PROC">%1$s</xliff:g> యొక్క హీప్ డంప్ ప్రాసెస్ విధానం అందుబాటులో ఉంది. జాగ్రత్త: ఈ హీప్ డంప్ ప్రాసెస్ విధానంలో గోప్యమైన వ్యక్తిగత సమాచారం యాక్సెస్ చేసే అవకాశం ఉంది, వీటిలో మీరు టైప్ చేసే అంశాలు కూడా ఉండవచ్చు."</string>
@@ -1294,7 +1294,7 @@
<string name="volume_icon_description_incall" msgid="4491255105381227919">"కాల్ వాల్యూమ్"</string>
<string name="volume_icon_description_media" msgid="4997633254078171233">"మీడియా వాల్యూమ్"</string>
<string name="volume_icon_description_notification" msgid="579091344110747279">"నోటిఫికేషన్ వాల్యూమ్"</string>
- <string name="ringtone_default" msgid="9118299121288174597">"డిఫాల్ట్ రింగ్టోన్"</string>
+ <string name="ringtone_default" msgid="9118299121288174597">"ఆటోమేటిక్ రింగ్టోన్"</string>
<string name="ringtone_default_with_actual" msgid="2709686194556159773">"ఆటోమేటిక్ (<xliff:g id="ACTUAL_RINGTONE">%1$s</xliff:g>)"</string>
<string name="ringtone_silent" msgid="397111123930141876">"ఏదీ వద్దు"</string>
<string name="ringtone_picker_title" msgid="667342618626068253">"రింగ్టోన్లు"</string>
@@ -1386,7 +1386,7 @@
<string name="usb_contaminant_not_detected_title" msgid="2651167729563264053">"USB పోర్ట్ను ఉపయోగించడం సురక్షితం"</string>
<string name="usb_contaminant_not_detected_message" msgid="892863190942660462">"ఫోన్ ఇకపై ద్రవ లేదా వ్యర్థ పదార్థాలను గుర్తించదు."</string>
<string name="taking_remote_bugreport_notification_title" msgid="1582531382166919850">"బగ్ రిపోర్ట్ను తీస్తోంది…"</string>
- <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ రిపోర్ట్ను భాగస్వామ్యం చేయాలా?"</string>
+ <string name="share_remote_bugreport_notification_title" msgid="6708897723753334999">"బగ్ రిపోర్ట్ను షేర్ చేయాలా?"</string>
<string name="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ రిపోర్ట్ను భాగస్వామ్యం చేస్తోంది..."</string>
<string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ రిపోర్ట్ను అభ్యర్థించారు. యాప్లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</string>
<string name="share_remote_bugreport_action" msgid="7630880678785123682">"షేర్ చేయి"</string>
@@ -1526,8 +1526,8 @@
<string name="websearch" msgid="5624340204512793290">"వెబ్ శోధన"</string>
<string name="find_next" msgid="5341217051549648153">"తదుపరిదాన్ని కనుగొను"</string>
<string name="find_previous" msgid="4405898398141275532">"మునుపటిదాన్ని కనుగొను"</string>
- <string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి స్థాన రిక్వెస్ట్"</string>
- <string name="gpsNotifTitle" msgid="1590033371665669570">"స్థాన రిక్వెస్ట్"</string>
+ <string name="gpsNotifTicker" msgid="3207361857637620780">"<xliff:g id="NAME">%s</xliff:g> నుండి లొకేషన్ రిక్వెస్ట్"</string>
+ <string name="gpsNotifTitle" msgid="1590033371665669570">"లొకేషన్ రిక్వెస్ట్"</string>
<string name="gpsNotifMessage" msgid="7346649122793758032">"<xliff:g id="NAME">%1$s</xliff:g> (<xliff:g id="SERVICE">%2$s</xliff:g>) ద్వారా అభ్యర్థించబడింది"</string>
<string name="gpsVerifYes" msgid="3719843080744112940">"అవును"</string>
<string name="gpsVerifNo" msgid="1671201856091564741">"కాదు"</string>
@@ -1676,12 +1676,12 @@
<string name="kg_too_many_failed_pin_attempts_dialog_message" msgid="23741434207544038">"మీరు మీ పిన్ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_too_many_failed_password_attempts_dialog_message" msgid="3328686432962224215">"మీరు మీ పాస్వర్డ్ను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా టైప్ చేశారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<string name="kg_too_many_failed_pattern_attempts_dialog_message" msgid="7357404233979139075">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీసారు. \n\n<xliff:g id="NUMBER_1">%2$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ డిఫాల్ట్కి రీసెట్ చేయబడుతుంది, అలాగే వినియోగదారు డేటా మొత్తాన్ని కోల్పోతారు."</string>
- <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది మరియు మొత్తం వినియోగదారు డేటాను కోల్పోవడం సంభవిస్తుంది."</string>
- <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tablet" msgid="3479940221343361587">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, టాబ్లెట్ ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="tv" msgid="9064457748587850217">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, మీ Android TV పరికరం ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే యూజర్, డేటా మొత్తాన్ని కోల్పోతారు."</string>
+ <string name="kg_failed_attempts_almost_at_wipe" product="default" msgid="5955398963754432548">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER_0">%1$d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత, ఫోన్ ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది, అలాగే మొత్తం యూజర్ డేటాను కోల్పోతారు."</string>
+ <string name="kg_failed_attempts_now_wiping" product="tablet" msgid="2299099385175083308">"మీరు టాబ్లెట్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. టాబ్లెట్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string>
<string name="kg_failed_attempts_now_wiping" product="tv" msgid="5045460916106267585">"మీరు మీ Android TV పరికరాన్ని అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> సార్లు విఫల ప్రయత్నాలు చేశారు. మీ Android TV పరికరం ఇప్పుడు ఫ్యాక్టరీ రీసెట్ చేయబడుతుంది."</string>
- <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ డిఫాల్ట్కు రీసెట్ చేయబడుతుంది."</string>
+ <string name="kg_failed_attempts_now_wiping" product="default" msgid="5043730590446071189">"మీరు ఫోన్ను అన్లాక్ చేయడానికి <xliff:g id="NUMBER">%d</xliff:g> చెల్లని ప్రయత్నాలు చేశారు. ఫోన్ ఇప్పుడు ఫ్యాక్టరీ ఆటోమేటిక్కు రీసెట్ చేయబడుతుంది."</string>
<string name="kg_failed_attempts_almost_at_login" product="tablet" msgid="7086799295109717623">"మీరు మీ అన్లాక్ నమూనాను <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_failed_attempts_almost_at_login" product="tv" msgid="4670840383567106114">"మీరు మీ అన్లాక్ నమూనాను <xliff:g id="NUMBER_0">%1$d</xliff:g> సార్లు తప్పుగా గీశారు. మరో <xliff:g id="NUMBER_1">%2$d</xliff:g> విఫల ప్రయత్నాల తర్వాత మీ Android TV పరికరాన్ని ఇమెయిల్ ఖాతా ద్వారా అన్లాక్ చేయాల్సిందిగా మిమ్మల్ని కోరడం జరుగుతుంది.\n\n <xliff:g id="NUMBER_2">%3$d</xliff:g> సెకన్లలో మళ్లీ ప్రయత్నించండి."</string>
<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>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index cbf35f4..c9df3ff 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1224,6 +1224,22 @@
resource] to be present in order to function. Default value is false. -->
<attr name="isSplitRequired" format="boolean" />
+ <!-- List of split types required by this APK to be present in order to function properly,
+ separated by commas. The platform will reject installation of an app that is missing
+ any required split types. Each split type is an arbitrary string that has no specific
+ meaning to the platform, and is only used for matching <code>splitTypes</code> and
+ <code>requiredSplitTypes</code>. As an example, if a split requires strings, drawables,
+ and native code this value could be "language,density,abi". Default value is null to
+ indicate no split types are required. -->
+ <attr name="requiredSplitTypes" format="string" />
+
+ <!-- List of split types offered by this APK, separated by commas. Each split type is an
+ arbitrary string that has no specific meaning to the platform, and is only used for
+ matching <code>splitTypes</code> and <code>requiredSplitTypes</code>. As an example,
+ if a split offers strings and drawables the value could be "language,density". Default
+ value is null to indicate no split types are offered. -->
+ <attr name="splitTypes" format="string" />
+
<!-- Flag to specify if this app wants to run the dex within its APK but not extracted or
locally compiled variants. This keeps the dex code protected by the APK signature. Such
apps will always run in JIT mode (same when they are first installed), and the system will
@@ -1664,6 +1680,8 @@
<attr name="compileSdkVersion" />
<attr name="compileSdkVersionCodename" />
<attr name="isSplitRequired" />
+ <attr name="requiredSplitTypes" />
+ <attr name="splitTypes" />
</declare-styleable>
<!-- The <code>application</code> tag describes application-level components
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index a20477c..e28288d 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3299,6 +3299,8 @@
<staging-public-group type="attr" first-id="0x01df0000">
<public name="sharedUserMaxSdkVersion" />
+ <public name="requiredSplitTypes" />
+ <public name="splitTypes" />
</staging-public-group>
<staging-public-group type="id" first-id="0x01de0000">
diff --git a/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt b/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
new file mode 100644
index 0000000..8355daa
--- /dev/null
+++ b/core/tests/coretests/src/com/android/internal/inputmethod/CompletableFutureUtilTest.kt
@@ -0,0 +1,284 @@
+/*
+ * Copyright (C) 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.inputmethod
+
+import android.annotation.DurationMillisLong
+import android.os.Handler
+import android.os.SystemClock
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.runner.AndroidJUnit4
+import com.google.common.collect.Range
+import com.google.common.truth.Truth.assertThat
+import org.junit.Assert.fail
+import org.junit.Test
+import org.junit.runner.RunWith
+import java.util.concurrent.CompletableFuture
+import java.util.concurrent.atomic.AtomicBoolean
+import java.util.concurrent.atomic.AtomicLong
+import java.util.concurrent.atomic.AtomicReference
+
+@DurationMillisLong
+const val SHORT_PERIOD_MILLI = 50L
+const val SHORT_PERIOD_NANO = SHORT_PERIOD_MILLI * 1_000_000L
+
+@DurationMillisLong
+const val TIMEOUT_MILLI = 10_000L
+const val TIMEOUT_NANO = TIMEOUT_MILLI * 1_000_000L
+
+const val ERROR_MESSAGE = "Test Error Message!"
+
+@LargeTest
+@RunWith(AndroidJUnit4::class)
+class CompletableFutureUtilTest {
+
+ private inline fun assertRuntimeException(expectedMessage: String, block: () -> Unit) {
+ try {
+ block()
+ fail()
+ } catch (exception: RuntimeException) {
+ assertThat(exception.message).isEqualTo(expectedMessage)
+ // Expected
+ } catch (exception: Throwable) {
+ fail("RuntimeException is expected but got $exception")
+ }
+ }
+
+ private inline fun runOnMainDelayed(delay: Long, crossinline block: () -> Unit) {
+ val handler = Handler.createAsync(
+ InstrumentationRegistry.getInstrumentation().getTargetContext().getMainLooper())
+ handler.postDelayed({
+ block()
+ }, delay)
+ }
+
+ @Test
+ fun testCharSequenceTimedOut() {
+ val completable = CompletableFuture<CharSequence>()
+
+ assertThat(completable.isDone).isFalse()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null, SHORT_PERIOD_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(completable.isDone).isFalse()
+ assertThat(result).isNull()
+ assertThat(elapsed).isGreaterThan(SHORT_PERIOD_NANO)
+ }
+
+ @Test
+ fun testCharSequenceTimedOutWithInterruption() {
+ val completable = CompletableFuture<CharSequence>()
+
+ val beginNanosRef = AtomicLong()
+ val endNanosRef = AtomicLong()
+ val isInterruptedRef = AtomicBoolean()
+ val resultRef = AtomicReference<CharSequence>()
+
+ // Verifies that calling getResultOrNull() on an interrupted thread still times out with
+ // preserving the interrupted state.
+ val thread = Thread {
+ val currentThread = Thread.currentThread()
+ currentThread.interrupt()
+ beginNanosRef.set(SystemClock.elapsedRealtimeNanos())
+ resultRef.set(CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null, SHORT_PERIOD_MILLI))
+ endNanosRef.set(SystemClock.elapsedRealtimeNanos())
+ isInterruptedRef.set(currentThread.isInterrupted())
+ }
+
+ thread.run()
+ thread.join(TIMEOUT_MILLI)
+ assertThat(thread.isAlive).isFalse()
+
+ val elapsedTime = endNanosRef.get() - beginNanosRef.get()
+ assertThat(elapsedTime).isGreaterThan(SHORT_PERIOD_NANO)
+ assertThat(resultRef.get()).isNull()
+ assertThat(isInterruptedRef.get()).isTrue()
+ }
+
+ @Test
+ fun testCharSequenceAfterCompletion() {
+ val expectedValue = "Expected Value"
+ val completable = CompletableFuture<CharSequence>()
+
+ assertThat(completable.isDone).isFalse()
+ completable.complete(expectedValue)
+ assertThat(completable.isDone).isTrue()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null,
+ TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(result).isEqualTo(expectedValue)
+ assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+ }
+
+ @Test
+ fun testCharSequenceAfterError() {
+ val completable = CompletableFuture<CharSequence>()
+
+ assertThat(completable.isDone).isFalse()
+ completable.completeExceptionally(UnsupportedOperationException(ERROR_MESSAGE))
+ assertThat(completable.isDone).isTrue()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(result).isNull()
+ assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+
+ assertRuntimeException(ERROR_MESSAGE) {
+ CompletableFutureUtil.getResult(completable)
+ }
+ }
+
+ @Test
+ fun testCharSequenceAfterCancellation() {
+ val completable = CompletableFuture<CharSequence>()
+ val cancellationGroup = CancellationGroup()
+ cancellationGroup.cancelAll()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ // due to the side-effect of cancellationGroup, the object is already completed here.
+ assertThat(completable.isDone).isTrue()
+ assertThat(result).isNull()
+ assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+
+ // as the object is already cancelled due to the side-effect of cancellationGroup, it cannot
+ // accept a result any more.
+ completable.complete("Hello!")
+ assertThat(completable.isCancelled).isTrue()
+ }
+
+ @Test
+ fun testCharSequenceAfterCompleteAndCancellation() {
+ val expectedValue = "Expected Value"
+ val completable = CompletableFuture<CharSequence>()
+ completable.complete(expectedValue)
+
+ val cancellationGroup = CancellationGroup()
+ cancellationGroup.cancelAll()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(result).isEqualTo(expectedValue)
+ assertThat(CompletableFutureUtil.getResult(completable)).isEqualTo(expectedValue)
+ assertThat(elapsed).isLessThan(SHORT_PERIOD_NANO)
+ }
+
+ @Test
+ fun testCharSequenceMultipleAssignment() {
+ val expectedValue = "Expected Value"
+ val notExpectedValue = "Not Expected Value"
+ val completable = CompletableFuture<CharSequence>()
+ completable.complete(expectedValue)
+ completable.complete(notExpectedValue)
+ assertThat(completable.isDone).isTrue()
+
+ assertThat(CompletableFutureUtil.getResult(completable)).isEqualTo(expectedValue)
+ }
+
+ @Test
+ fun testCharSequenceUnblockByCompletion() {
+ val expectedValue = "Expected Value"
+ val completable = CompletableFuture<CharSequence>()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ runOnMainDelayed(SHORT_PERIOD_MILLI) {
+ completable.complete(expectedValue)
+ }
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(completable.isDone).isTrue()
+ assertThat(result).isEqualTo(expectedValue)
+ assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+ }
+
+ @Test
+ fun testCharSequenceUnblockByCompletionWithCancellationGroup() {
+ val expectedValue = "Expected Value"
+ val completable = CompletableFuture<CharSequence>()
+ var cancellationGroup = CancellationGroup()
+
+ assertThat(cancellationGroup.isCanceled).isFalse()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ runOnMainDelayed(SHORT_PERIOD_MILLI) {
+ completable.complete(expectedValue)
+ }
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(cancellationGroup.isCanceled).isFalse()
+ assertThat(completable.isDone).isTrue()
+ assertThat(result).isEqualTo(expectedValue)
+ assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+ }
+
+ @Test
+ fun testCharSequenceUnblockByError() {
+ val completable = CompletableFuture<CharSequence>()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ runOnMainDelayed(SHORT_PERIOD_MILLI) {
+ completable.completeExceptionally(UnsupportedOperationException(ERROR_MESSAGE))
+ }
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, null, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ assertThat(completable.isDone).isTrue()
+ assertThat(result).isNull()
+ assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+ }
+
+ @Test
+ fun testCharSequenceUnblockByCancellation() {
+ val completable = CompletableFuture<CharSequence>()
+ val cancellationGroup = CancellationGroup()
+
+ val beginNanos = SystemClock.elapsedRealtimeNanos()
+ runOnMainDelayed(SHORT_PERIOD_MILLI) {
+ cancellationGroup.cancelAll()
+ }
+ val result = CompletableFutureUtil.getResultOrNull(
+ completable, null, null, cancellationGroup, TIMEOUT_MILLI)
+ val elapsed = SystemClock.elapsedRealtimeNanos() - beginNanos
+
+ // due to the side-effect of cancellationGroup.
+ assertThat(completable.isDone).isTrue()
+ assertThat(result).isNull()
+ assertThat(elapsed).isIn(Range.closedOpen(SHORT_PERIOD_NANO, TIMEOUT_NANO))
+ }
+}
diff --git a/data/etc/car/com.android.car.carlauncher.xml b/data/etc/car/com.android.car.carlauncher.xml
index abde232..33f885a 100644
--- a/data/etc/car/com.android.car.carlauncher.xml
+++ b/data/etc/car/com.android.car.carlauncher.xml
@@ -17,6 +17,7 @@
<permissions>
<privapp-permissions package="com.android.car.carlauncher">
<permission name="android.permission.ACTIVITY_EMBEDDING"/>
+ <permission name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"/>
<permission name="android.permission.CONTROL_INCALL_EXPERIENCE"/>
<permission name="android.permission.INTERACT_ACROSS_USERS"/>
<permission name="android.permission.MANAGE_USERS"/>
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
index f3a8620..4c0281d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/SyncTransactionQueue.java
@@ -68,6 +68,10 @@
* Queues a sync transaction to be sent serially to WM.
*/
public void queue(WindowContainerTransaction wct) {
+ if (wct.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "Skip queue due to transaction change is empty");
+ return;
+ }
SyncCallback cb = new SyncCallback(wct);
synchronized (mQueue) {
if (DEBUG) Slog.d(TAG, "Queueing up " + wct);
@@ -83,6 +87,10 @@
*/
public void queue(LegacyTransitions.ILegacyTransition transition,
@WindowManager.TransitionType int type, WindowContainerTransaction wct) {
+ if (wct.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "Skip queue due to transaction change is empty");
+ return;
+ }
SyncCallback cb = new SyncCallback(transition, type, wct);
synchronized (mQueue) {
if (DEBUG) Slog.d(TAG, "Queueing up legacy transition " + wct);
@@ -99,6 +107,10 @@
* @return {@code true} if queued, {@code false} if not.
*/
public boolean queueIfWaiting(WindowContainerTransaction wct) {
+ if (wct.isEmpty()) {
+ if (DEBUG) Slog.d(TAG, "Skip queueIfWaiting due to transaction change is empty");
+ return false;
+ }
synchronized (mQueue) {
if (mQueue.isEmpty()) {
if (DEBUG) Slog.d(TAG, "Nothing in queue, so skip queueing up " + wct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 3b9bcd3..f9c681c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -50,6 +50,7 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.policy.DividerSnapAlgorithm;
+import com.android.internal.policy.DockedDividerUtils;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.animation.Interpolators;
import com.android.wm.shell.common.DisplayImeController;
@@ -93,7 +94,8 @@
private final Rect mDividerBounds = new Rect();
private final Rect mBounds1 = new Rect();
private final Rect mBounds2 = new Rect();
- private final Rect mTmpBounds = new Rect();
+ private final Rect mWinBounds1 = new Rect();
+ private final Rect mWinBounds2 = new Rect();
private final SplitLayoutHandler mSplitLayoutHandler;
private final SplitWindowManager mSplitWindowManager;
private final DisplayImeController mDisplayImeController;
@@ -103,6 +105,8 @@
private Context mContext;
private DividerSnapAlgorithm mDividerSnapAlgorithm;
+ private WindowContainerToken mWinToken1;
+ private WindowContainerToken mWinToken2;
private int mDividePosition;
private boolean mInitialized = false;
private int mOrientation;
@@ -189,10 +193,10 @@
final int rotation = configuration.windowConfiguration.getRotation();
final Rect rootBounds = configuration.windowConfiguration.getBounds();
if (rotation != mRotation || !mRootBounds.equals(rootBounds)) {
- mTmpBounds.set(mRootBounds);
+ mTempRect.set(mRootBounds);
mRootBounds.set(rootBounds);
mDividerSnapAlgorithm = getSnapAlgorithm(mContext, mRootBounds);
- initDividerPosition(mTmpBounds);
+ initDividerPosition(mTempRect);
affectsLayout = true;
}
@@ -236,6 +240,8 @@
mBounds1.bottom = position;
mBounds2.top = mBounds1.bottom + mDividerSize;
}
+ DockedDividerUtils.sanitizeStackBounds(mBounds1, true /** topLeft */);
+ DockedDividerUtils.sanitizeStackBounds(mBounds2, false /** topLeft */);
mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
}
@@ -403,8 +409,16 @@
return;
}
- wct.setBounds(task1.token, mBounds1)
- .setBounds(task2.token, mBounds2);
+ if (!mBounds1.equals(mWinBounds1) || !task1.token.equals(mWinToken1)) {
+ wct.setBounds(task1.token, mBounds1);
+ mWinBounds1.set(mBounds1);
+ mWinToken1 = task1.token;
+ }
+ if (!mBounds2.equals(mWinBounds2) || !task2.token.equals(mWinToken2)) {
+ wct.setBounds(task2.token, mBounds2);
+ mWinBounds2.set(mBounds2);
+ mWinToken2 = task2.token;
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
index 40244fb..f201634 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/legacysplitscreen/LegacySplitDisplayLayout.java
@@ -62,6 +62,7 @@
Rect mSecondary = null;
Rect mAdjustedPrimary = null;
Rect mAdjustedSecondary = null;
+ final Rect mTmpBounds = new Rect();
public LegacySplitDisplayLayout(Context ctx, DisplayLayout dl,
LegacySplitScreenTaskListener taskTiles) {
@@ -136,31 +137,41 @@
return mMinimizedSnapAlgorithm;
}
- void resizeSplits(int position) {
+ /**
+ * Resize primary bounds and secondary bounds by divider position.
+ *
+ * @param position divider position.
+ * @return true if calculated bounds changed.
+ */
+ boolean resizeSplits(int position) {
mPrimary = mPrimary == null ? new Rect() : mPrimary;
mSecondary = mSecondary == null ? new Rect() : mSecondary;
- calcSplitBounds(position, mPrimary, mSecondary);
+ int dockSide = getPrimarySplitSide();
+ boolean boundsChanged;
+
+ mTmpBounds.set(mPrimary);
+ DockedDividerUtils.calculateBoundsForPosition(position, dockSide, mPrimary,
+ mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
+ boundsChanged = !mPrimary.equals(mTmpBounds);
+
+ mTmpBounds.set(mSecondary);
+ DockedDividerUtils.calculateBoundsForPosition(position,
+ DockedDividerUtils.invertDockSide(dockSide), mSecondary, mDisplayLayout.width(),
+ mDisplayLayout.height(), mDividerSize);
+ boundsChanged |= !mSecondary.equals(mTmpBounds);
+ return boundsChanged;
}
void resizeSplits(int position, WindowContainerTransaction t) {
- resizeSplits(position);
- t.setBounds(mTiles.mPrimary.token, mPrimary);
- t.setBounds(mTiles.mSecondary.token, mSecondary);
+ if (resizeSplits(position)) {
+ t.setBounds(mTiles.mPrimary.token, mPrimary);
+ t.setBounds(mTiles.mSecondary.token, mSecondary);
- t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
- getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
- t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
- getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
- }
-
- void calcSplitBounds(int position, @NonNull Rect outPrimary, @NonNull Rect outSecondary) {
- int dockSide = getPrimarySplitSide();
- DockedDividerUtils.calculateBoundsForPosition(position, dockSide, outPrimary,
- mDisplayLayout.width(), mDisplayLayout.height(), mDividerSize);
-
- DockedDividerUtils.calculateBoundsForPosition(position,
- DockedDividerUtils.invertDockSide(dockSide), outSecondary, mDisplayLayout.width(),
- mDisplayLayout.height(), mDividerSize);
+ t.setSmallestScreenWidthDp(mTiles.mPrimary.token,
+ getSmallestWidthDpForBounds(mContext, mDisplayLayout, mPrimary));
+ t.setSmallestScreenWidthDp(mTiles.mSecondary.token,
+ getSmallestWidthDpForBounds(mContext, mDisplayLayout, mSecondary));
+ }
}
Rect calcResizableMinimizedHomeStackBounds() {
diff --git a/packages/PrintSpooler/res/values-as/strings.xml b/packages/PrintSpooler/res/values-as/strings.xml
index b6b287f..a93fceb 100644
--- a/packages/PrintSpooler/res/values-as/strings.xml
+++ b/packages/PrintSpooler/res/values-as/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDFৰ জৰিয়তে ছেভ কৰক"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"প্ৰিণ্ট বিকল্পসমূহ বিস্তাৰ কৰা হ’ল"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"প্ৰিণ্ট বিকল্পসমূহ সংকুচিত কৰা হ’ল"</string>
- <string name="search" msgid="5421724265322228497">"Search"</string>
+ <string name="search" msgid="5421724265322228497">"সন্ধান কৰক"</string>
<string name="all_printers_label" msgid="3178848870161526399">"সকলো প্ৰিণ্টাৰ"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"সেৱা যোগ কৰক"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"সন্ধান বাকচটো দেখুওৱা হ’ল"</string>
diff --git a/packages/PrintSpooler/res/values-kn/strings.xml b/packages/PrintSpooler/res/values-kn/strings.xml
index 261fe4b..150ede4 100644
--- a/packages/PrintSpooler/res/values-kn/strings.xml
+++ b/packages/PrintSpooler/res/values-kn/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDF ಗೆ ಉಳಿಸು"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ವಿಸ್ತರಿಸಲಾಗಿದೆ"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"ಪ್ರಿಂಟ್ ಆಯ್ಕೆಗಳನ್ನು ಮುಚ್ಚಲಾಗಿದೆ"</string>
- <string name="search" msgid="5421724265322228497">"Search"</string>
+ <string name="search" msgid="5421724265322228497">"ಹುಡುಕಿ"</string>
<string name="all_printers_label" msgid="3178848870161526399">"ಎಲ್ಲಾ ಪ್ರಿಂಟರ್ಗಳು"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"ಸೇವೆಯನ್ನು ಸೇರಿಸು"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ಹುಡುಕಾಟ ಪೆಟ್ಟಿಗೆಯನ್ನು ತೋರಿಸಲಾಗಿದೆ"</string>
diff --git a/packages/PrintSpooler/res/values-ml/strings.xml b/packages/PrintSpooler/res/values-ml/strings.xml
index 73af95d..dbcd34b 100644
--- a/packages/PrintSpooler/res/values-ml/strings.xml
+++ b/packages/PrintSpooler/res/values-ml/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDF-ൽ സംരക്ഷിക്കുക"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"പ്രിന്റ് ചെയ്യാനുള്ള ഓപ്ഷനുകൾ വിപുലീകരിച്ചു"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"പ്രിന്റ് ചെയ്യാനുള്ള ഓപ്ഷനുകൾ ചുരുക്കി"</string>
- <string name="search" msgid="5421724265322228497">"Search"</string>
+ <string name="search" msgid="5421724265322228497">"തിരയൽ"</string>
<string name="all_printers_label" msgid="3178848870161526399">"എല്ലാ പ്രിന്ററുകളും"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"സേവനം ചേർക്കുക"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"തിരയൽ ബോക്സ് ദൃശ്യമാക്കിയിരിക്കുന്നു"</string>
diff --git a/packages/PrintSpooler/res/values-mr/strings.xml b/packages/PrintSpooler/res/values-mr/strings.xml
index 8119439..e1fa390 100644
--- a/packages/PrintSpooler/res/values-mr/strings.xml
+++ b/packages/PrintSpooler/res/values-mr/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"पीडीएफ वर सेव्ह करा"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"प्रिंट पर्याय विस्तृत झाले"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"प्रिंट पर्याय संक्षिप्त झाले"</string>
- <string name="search" msgid="5421724265322228497">"Search"</string>
+ <string name="search" msgid="5421724265322228497">"शोधा"</string>
<string name="all_printers_label" msgid="3178848870161526399">"सर्व प्रिंटर"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"सेवा जोडा"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"शोध बॉक्स दर्शविला"</string>
diff --git a/packages/PrintSpooler/res/values-or/strings.xml b/packages/PrintSpooler/res/values-or/strings.xml
index d6f920f..fa10909 100644
--- a/packages/PrintSpooler/res/values-or/strings.xml
+++ b/packages/PrintSpooler/res/values-or/strings.xml
@@ -47,7 +47,7 @@
<string name="savetopdf_button" msgid="2976186791686924743">"PDFରେ ସେଭ୍ କରନ୍ତୁ"</string>
<string name="print_options_expanded" msgid="6944679157471691859">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ବଡ଼ କରାଯାଇଛି"</string>
<string name="print_options_collapsed" msgid="7455930445670414332">"ପ୍ରିଣ୍ଟ ବିକଳ୍ପକୁ ଛୋଟ କରାଯାଇଛି"</string>
- <string name="search" msgid="5421724265322228497">"Search"</string>
+ <string name="search" msgid="5421724265322228497">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="all_printers_label" msgid="3178848870161526399">"ସମସ୍ତ ପ୍ରିଣ୍ଟର୍"</string>
<string name="add_print_service_label" msgid="5356702546188981940">"ସେବା ଯୋଗ କରନ୍ତୁ"</string>
<string name="print_search_box_shown_utterance" msgid="7967404953901376090">"ସର୍ଚ୍ଚ ବକ୍ସ ଦେଖାଯାଇଛି"</string>
diff --git a/packages/SettingsLib/res/values-te/arrays.xml b/packages/SettingsLib/res/values-te/arrays.xml
index e0ba520..67decc9 100644
--- a/packages/SettingsLib/res/values-te/arrays.xml
+++ b/packages/SettingsLib/res/values-te/arrays.xml
@@ -76,7 +76,7 @@
<item msgid="1963366694959681026">"avrcp16"</item>
</string-array>
<string-array name="bluetooth_map_versions">
- <item msgid="8786402640610987099">"MAP 1.2 (డిఫాల్ట్)"</item>
+ <item msgid="8786402640610987099">"MAP 1.2 (ఆటోమేటిక్)"</item>
<item msgid="6817922176194686449">"MAP 1.3"</item>
<item msgid="3423518690032737851">"MAP 1.4"</item>
</string-array>
diff --git a/packages/SettingsLib/res/values-te/strings.xml b/packages/SettingsLib/res/values-te/strings.xml
index 2928abc..20c5edb 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -143,7 +143,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"జత చేయి"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"జత చేయి"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"రద్దు చేయి"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"జత చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ పరిచయాలకు మరియు కాల్ చరిత్రకు యాక్సెస్ను మంజూరు చేస్తుంది."</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"పెయిర్ చేయడం వలన కనెక్ట్ చేయబడినప్పుడు మీ కాంటాక్ట్లకు అలాగే కాల్ హిస్టరీకి యాక్సెస్ను మంజూరు చేస్తుంది."</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో జత చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"పిన్ లేదా పాస్కీ చెల్లని కారణంగా <xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో పెయిర్ చేయడం సాధ్యపడలేదు."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"<xliff:g id="DEVICE_NAME">%1$s</xliff:g>తో కమ్యూనికేట్ చేయడం సాధ్యపడదు."</string>
@@ -180,7 +180,7 @@
<string name="user_guest" msgid="6939192779649870792">"గెస్ట్"</string>
<string name="unknown" msgid="3544487229740637809">"తెలియదు"</string>
<string name="running_process_item_user_label" msgid="3988506293099805796">"యూజర్: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
- <string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని డిఫాల్ట్లు సెట్ చేయబడ్డాయి"</string>
+ <string name="launch_defaults_some" msgid="3631650616557252926">"కొన్ని ఆటోమేటిక్ సెట్టింగ్లు సెట్ చేయబడ్డాయి"</string>
<string name="launch_defaults_none" msgid="8049374306261262709">"ఆటోమేటిక్ ఆప్షన్లు ఏవీ సెట్ చేయలేదు"</string>
<string name="tts_settings" msgid="8130616705989351312">"వచనం నుండి ప్రసంగం సెట్టింగ్లు"</string>
<string name="tts_settings_title" msgid="7602210956640483039">"టెక్స్ట్-టు-స్పీచ్ అవుట్పుట్"</string>
@@ -273,8 +273,8 @@
<string name="confirm_enable_oem_unlock_title" msgid="8249318129774367535">"OEM అన్లాకింగ్ను అనుమతించాలా?"</string>
<string name="confirm_enable_oem_unlock_text" msgid="854131050791011970">"హెచ్చరిక: ఈ సెట్టింగ్ ఆన్ చేయబడినప్పుడు పరికరం రక్షణ లక్షణాలు ఈ పరికరంలో పని చేయవు."</string>
<string name="mock_location_app" msgid="6269380172542248304">"డమ్మీ లొకేషన్ యాప్ను ఎంచుకోండి"</string>
- <string name="mock_location_app_not_set" msgid="6972032787262831155">"అనుకృత స్థాన యాప్ ఏదీ సెట్ చేయబడలేదు"</string>
- <string name="mock_location_app_set" msgid="4706722469342913843">"కృత్రిమ స్థాన యాప్: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+ <string name="mock_location_app_not_set" msgid="6972032787262831155">"డమ్మీ లొకేషన్ యాప్ ఏదీ సెట్ చేయబడలేదు"</string>
+ <string name="mock_location_app_set" msgid="4706722469342913843">"డమ్మీ లొకేషన్ యాప్: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
<string name="debug_networking_category" msgid="6829757985772659599">"నెట్వర్కింగ్"</string>
<string name="wifi_display_certification" msgid="1805579519992520381">"వైర్లెస్ డిస్ప్లే సర్టిఫికేషన్"</string>
<string name="wifi_verbose_logging" msgid="1785910450009679371">"Wi‑Fi విశదీకృత లాగింగ్ను ప్రారంభించండి"</string>
diff --git a/packages/Shell/res/values-te/strings.xml b/packages/Shell/res/values-te/strings.xml
index 50b5c85..2f86232 100644
--- a/packages/Shell/res/values-te/strings.xml
+++ b/packages/Shell/res/values-te/strings.xml
@@ -23,9 +23,9 @@
<string name="bugreport_updating_title" msgid="4423539949559634214">"బగ్ రిపోర్ట్కు వివరాలను జోడిస్తోంది"</string>
<string name="bugreport_updating_wait" msgid="3322151947853929470">"దయచేసి వేచి ఉండండి..."</string>
<string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"బగ్ రిపోర్ట్ త్వరలో ఫోన్లో కనిపిస్తుంది"</string>
- <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ రిపోర్ట్ను భాగస్వామ్యం చేయడానికి ఎంచుకోండి"</string>
+ <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"మీ బగ్ రిపోర్ట్ను షేర్ చేయడానికి ఎంచుకోండి"</string>
<string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"మీ బగ్ రిపోర్ట్ను షేర్ చేయడానికి నొక్కండి"</string>
- <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్షాట్ లేకుండా మీ బగ్ రిపోర్ట్ను భాగస్వామ్యం చేయడానికి ఎంచుకోండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
+ <string name="bugreport_finished_pending_screenshot_text" product="tv" msgid="2343263822812016950">"స్క్రీన్షాట్ లేకుండా మీ బగ్ రిపోర్ట్ను షేర్ చేయడానికి ఎంచుకోండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="watch" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_finished_pending_screenshot_text" product="default" msgid="1474435374470177193">"స్క్రీన్షాట్ లేకుండా మీ బగ్ నివే. భాగ. చేయడానికి నొక్కండి లేదా స్క్రీన్షాట్ ముగిసేదాకా వేచి ఉండండి"</string>
<string name="bugreport_confirm" msgid="5917407234515812495">"బగ్ రిపోర్ట్స్లో మీరు గోప్యమైనదిగా పరిగణించే (యాప్ వినియోగం, లొకేషన్ డేటా వంటి) డేటాతో పాటు సిస్టమ్కు సంబంధించిన విభిన్న లాగ్ ఫైళ్ల డేటా ఉంటుంది. బగ్ రిపోర్ట్లను మీరు విశ్వసించే యాప్లు, వ్యక్తులతో మాత్రమే షేర్ చేయండి."</string>
diff --git a/packages/SoundPicker/res/values-te/strings.xml b/packages/SoundPicker/res/values-te/strings.xml
index 10b4e7c..8f5c34a 100644
--- a/packages/SoundPicker/res/values-te/strings.xml
+++ b/packages/SoundPicker/res/values-te/strings.xml
@@ -16,7 +16,7 @@
<resources xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
- <string name="ringtone_default" msgid="798836092118824500">"డిఫాల్ట్ రింగ్టోన్"</string>
+ <string name="ringtone_default" msgid="798836092118824500">"ఆటోమేటిక్ రింగ్టోన్"</string>
<string name="notification_sound_default" msgid="8133121186242636840">"నోటిఫికేషన్ ఆటోమేటిక్ సౌండ్"</string>
<string name="alarm_sound_default" msgid="4787646764557462649">"అలారం ఆటోమేటిక్ సౌండ్"</string>
<string name="add_ringtone_text" msgid="6642389991738337529">"రింగ్టోన్ను జోడించు"</string>
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index a2b4ac122..7513af3 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -120,6 +120,7 @@
android:layout_width="@dimen/notification_panel_width"
android:layout_height="match_parent"
android:layout_marginBottom="@dimen/close_handle_underlap"
+ android:importantForAccessibility="no"
systemui:layout_constraintStart_toStartOf="parent"
systemui:layout_constraintEnd_toEndOf="parent"
/>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index b63d97c..7d3ae96 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -133,7 +133,7 @@
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"দিব্যাংগসকলৰ বাবে থকা সুবিধাসমূহ"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"স্ক্ৰীণ ঘূৰাওক"</string>
<string name="accessibility_recent" msgid="901641734769533575">"অৱলোকন"</string>
- <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+ <string name="accessibility_search_light" msgid="524741790416076988">"সন্ধান কৰক"</string>
<string name="accessibility_camera_button" msgid="2938898391716647247">"কেমেৰা"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ফ\'ন"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"কণ্ঠধ্বনিৰে সহায়"</string>
@@ -442,7 +442,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"বেটাৰিৰ চ্চাৰ্জ সম্পূর্ণ হ\'বলৈ <xliff:g id="CHARGING_TIME">%s</xliff:g> বাকী"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"চ্চার্জ কৰি থকা নাই"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"নেটৱৰ্ক \nনিৰীক্ষণ কৰা হ\'ব পাৰে"</string>
- <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+ <string name="description_target_search" msgid="3875069993128855865">"সন্ধান কৰক"</string>
<string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>ৰ বাবে ওপৰলৈ শ্লাইড কৰক।"</string>
<string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g>ৰ বাবে বাওঁফাললৈ শ্লাইড কৰক।"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"আপুনি নিৰ্দিষ্ট কৰা এলাৰ্ম, ৰিমাইণ্ডাৰ, ইভেন্ট আৰু কল কৰোঁতাৰ বাহিৰে আন কোনো শব্দৰ পৰা আপুনি অসুবিধা নাপাব। কিন্তু, সংগীত, ভিডিঅ\' আৰু খেলসমূহকে ধৰি আপুনি প্লে কৰিব খোজা যিকোনো বস্তু তথাপি শুনিব পাৰিব।"</string>
@@ -1014,7 +1014,7 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(কৰ্মস্থান)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"ফ’ন কল"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g>ৰ জৰিয়তে)"</string>
- <string name="privacy_type_camera" msgid="7974051382167078332">"কেমেৰা"</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"Camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"অৱস্থান"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"মাইক্ৰ\'ফ\'ন"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"ছেন্সৰ অফ হৈ আছে"</string>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index c4ff99e..bd2d05a 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"স্ক্রীণ পূরণ করতে জুম করুন"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ফুল স্ক্রিন করুন"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"স্ক্রিনশট নিন"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock বন্ধ করা হয়েছে"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"একটি ছবি পাঠানো হয়েছে"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"স্ক্রিনশট সেভ করা হচ্ছে..."</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"নেটওয়ার্ক সার্চ করা হচ্ছে…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"নেটওয়ার্কে কানেক্ট করা যায়নি"</string>
<string name="see_all_networks" msgid="3773666844913168122">"সবকটি দেখুন"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> নিম্নলিখিত টাইল দ্রুত সেটিংস মেনুতে যোগ করতে চায়"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"টাইল যোগ করুন"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"টাইল যোগ করবেন না"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 619d690..f5539e3 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zoomer pour remplir l\'écran"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Étirer pour remplir l\'écran"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Capture d\'écran"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Fonctionnalité Smart Lock désactivée"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"a envoyé une image"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Enregistrement capture écran…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Enregistrement capture écran…"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux en cours…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Échec de la connexion au réseau"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Tout afficher"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"L\'application <xliff:g id="APPNAME">%1$s</xliff:g> veut ajouter la tuile suivante au menu Paramètres rapides"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Ajouter la tuile"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Ne pas ajouter tuile"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index dba4aba..a2295ab 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"સ્ક્રીન ભરવા માટે ઝૂમ કરો"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"સ્ક્રીન ભરવા માટે ખેંચો"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"સ્ક્રીનશૉટ"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock બંધ કરેલું છે"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"છબી મોકલી"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"સ્ક્રીનશોટ સાચવી રહ્યું છે…"</string>
@@ -135,7 +134,7 @@
<string name="accessibility_rotate_button" msgid="1238584767612362586">"સ્ક્રીન ફેરવો"</string>
<string name="accessibility_recent" msgid="901641734769533575">"ઝલક"</string>
<string name="accessibility_search_light" msgid="524741790416076988">"શોધ"</string>
- <string name="accessibility_camera_button" msgid="2938898391716647247">"કૅમેરો"</string>
+ <string name="accessibility_camera_button" msgid="2938898391716647247">"કૅમેરા"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ફોન"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"વૉઇસ સહાય"</string>
<string name="accessibility_wallet_button" msgid="1458258783460555507">"વૉલેટ"</string>
@@ -984,7 +983,7 @@
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"ખલેલ પાડશો નહીં એક ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"ખલેલ પાડશો નહીં એક સ્વચાલિત નિયમ અથવા ઍપ્લિકેશન દ્વારા ચાલુ કરાયું હતું."</string>
<string name="qs_dnd_until" msgid="7844269319043747955">"<xliff:g id="ID_1">%s</xliff:g> સુધી"</string>
- <string name="qs_dnd_keep" msgid="3829697305432866434">"Keep"</string>
+ <string name="qs_dnd_keep" msgid="3829697305432866434">"રાખો"</string>
<string name="qs_dnd_replace" msgid="7712119051407052689">"બદલો"</string>
<string name="running_foreground_services_title" msgid="5137313173431186685">"પૃષ્ઠભૂમિમાં ચાલી રહેલ ઍપ્લિકેશનો"</string>
<string name="running_foreground_services_msg" msgid="3009459259222695385">"બૅટરી અને ડેટા વપરાશ વિશેની વિગતો માટે ટૅપ કરો"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"નેટવર્ક શોધી રહ્યાં છીએ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"નેટવર્ક સાથે કનેક્ટ કરવામાં નિષ્ફળ થયાં"</string>
<string name="see_all_networks" msgid="3773666844913168122">"બધા જુઓ"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"ઝડપી સેટિંગમાં <xliff:g id="APPNAME">%1$s</xliff:g> નીચે જણાવેલા ટાઇલ ઉમેરવા માગે છે"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ટાઇલ ઉમેરો"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ટાઇલ ઉમેરશો નહીં"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index e123544..ce0f9b9 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -848,7 +848,7 @@
<string name="keyboard_shortcut_group_applications_sms" msgid="6912633831752843566">"मैसेज (एसएमएस) करें"</string>
<string name="keyboard_shortcut_group_applications_music" msgid="9032078456666204025">"संगीत"</string>
<string name="keyboard_shortcut_group_applications_youtube" msgid="5078136084632450333">"YouTube"</string>
- <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"कैलेंडर"</string>
+ <string name="keyboard_shortcut_group_applications_calendar" msgid="4229602992120154157">"Calendar"</string>
<string name="tuner_full_zen_title" msgid="5120366354224404511">"वॉल्यूम नियंत्रणों के साथ दिखाएं"</string>
<string name="volume_and_do_not_disturb" msgid="502044092739382832">"परेशान न करें"</string>
<string name="volume_dnd_silent" msgid="4154597281458298093">"वॉल्यूम बटन का शॉर्टकट"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index c1f1305..cd2df4e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"הגדלת התצוגה למילוי המסך"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"מתיחה למילוי של המסך"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"צילום מסך"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"השבתת את Smart Lock"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"נשלחה תמונה"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"צילום המסך נשמר..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"המערכת שומרת את צילום המסך..."</string>
@@ -1190,10 +1189,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"בתהליך חיפוש רשתות…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"נכשל הניסיון להתחבר לרשת"</string>
<string name="see_all_networks" msgid="3773666844913168122">"הצגת הכול"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"האפליקציה <xliff:g id="APPNAME">%1$s</xliff:g> מבקשת להוסיף להגדרות המהירות את האריח הבא"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"הוספת אריח"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"אין להוסיף אריח"</string>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 235fc72..06db06d 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ಪರದೆ ತುಂಬಿಸಲು ಝೂಮ್ ಮಾಡು"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ಪರದೆ ತುಂಬಿಸಲು ವಿಸ್ತಾರಗೊಳಿಸು"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ಸ್ಕ್ರೀನ್ಶಾಟ್"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ಅನ್ನು ನಿಷ್ಕ್ರಿಯಗೊಳಿಸಲಾಗಿದೆ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ಚಿತ್ರವನ್ನು ಕಳುಹಿಸಲಾಗಿದೆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ಸ್ಕ್ರೀನ್ಶಾಟ್ ಉಳಿಸಲಾಗುತ್ತಿದೆ…"</string>
@@ -134,7 +133,7 @@
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"ಪ್ರವೇಶಿಸುವಿಕೆ"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"ಪರದೆಯನ್ನು ತಿರುಗಿಸಿ"</string>
<string name="accessibility_recent" msgid="901641734769533575">"ಸಮಗ್ರ ನೋಟ"</string>
- <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+ <string name="accessibility_search_light" msgid="524741790416076988">"ಹುಡುಕಿ"</string>
<string name="accessibility_camera_button" msgid="2938898391716647247">"ಕ್ಯಾಮರಾ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ಫೋನ್"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ಧ್ವನಿ ಸಹಾಯಕ"</string>
@@ -443,7 +442,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> ಪೂರ್ಣಗೊಳ್ಳುವವರೆಗೆ"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ಚಾರ್ಜ್ ಆಗುತ್ತಿಲ್ಲ"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"ನೆಟ್ವರ್ಕ್\n ವೀಕ್ಷಿಸಬಹುದಾಗಿರುತ್ತದೆ"</string>
- <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+ <string name="description_target_search" msgid="3875069993128855865">"ಹುಡುಕಿ"</string>
<string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಮೇಲಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
<string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ಗಾಗಿ ಎಡಕ್ಕೆ ಸ್ಲೈಡ್ ಮಾಡಿ."</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"ಅಲಾರಾಂಗಳು, ಜ್ಞಾಪನೆಗಳು, ಈವೆಂಟ್ಗಳು ಹಾಗೂ ನೀವು ಸೂಚಿಸಿರುವ ಕರೆದಾರರನ್ನು ಹೊರತುಪಡಿಸಿ ಬೇರಾವುದೇ ಸದ್ದುಗಳು ಅಥವಾ ವೈಬ್ರೇಶನ್ಗಳು ನಿಮಗೆ ತೊಂದರೆ ನೀಡುವುದಿಲ್ಲ. ಹಾಗಿದ್ದರೂ, ನೀವು ಪ್ಲೇ ಮಾಡುವ ಸಂಗೀತ, ವೀಡಿಯೊಗಳು ಮತ್ತು ಆಟಗಳ ಆಡಿಯೊವನ್ನು ನೀವು ಕೇಳಿಸಿಕೊಳ್ಳುತ್ತೀರಿ."</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ಹುಡುಕಲಾಗುತ್ತಿದೆ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ನೆಟ್ವರ್ಕ್ಗೆ ಕನೆಕ್ಟ್ ಮಾಡಲು ವಿಫಲವಾಗಿದೆ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ಎಲ್ಲವನ್ನೂ ನೋಡಿ"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ಈ ಕೆಳಗಿನ ಟೈಲ್ ಅನ್ನು ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್ಗಳಿಗೆ ಸೇರಿಸಲು ಬಯಸುತ್ತದೆ"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಿ"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ಟೈಲ್ ಅನ್ನು ಸೇರಿಸಬೇಡಿ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 9c6a698..986141b 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -133,7 +133,7 @@
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"ഉപയോഗസഹായി"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"സ്ക്രീൻ തിരിക്കുക"</string>
<string name="accessibility_recent" msgid="901641734769533575">"അവലോകനം"</string>
- <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+ <string name="accessibility_search_light" msgid="524741790416076988">"തിരയൽ"</string>
<string name="accessibility_camera_button" msgid="2938898391716647247">"ക്യാമറ"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ഫോണ്"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"വോയ്സ് സഹായം"</string>
@@ -442,7 +442,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"ഫുൾ ചാർജാകാൻ, <xliff:g id="CHARGING_TIME">%s</xliff:g>"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ചാർജ്ജുചെയ്യുന്നില്ല"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"നെറ്റ്വർക്ക്\nനിരീക്ഷിക്കപ്പെടാം"</string>
- <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+ <string name="description_target_search" msgid="3875069993128855865">"തിരയൽ"</string>
<string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി മുകളിലേയ്ക്ക് സ്ലൈഡുചെയ്യുക."</string>
<string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> എന്നതിനായി ഇടത്തേയ്ക്ക് സ്ലൈഡുചെയ്യുക."</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"നിങ്ങൾ സജ്ജീകരിച്ച അലാറങ്ങൾ, റിമൈൻഡറുകൾ, ഇവന്റുകൾ, കോളർമാർ എന്നിവയിൽ നിന്നുള്ള ശബ്ദങ്ങളും വൈബ്രേഷനുകളുമൊഴികെ മറ്റൊന്നും നിങ്ങളെ ശല്യപ്പെടുത്തുകയില്ല. സംഗീതം, വീഡിയോകൾ, ഗെയിമുകൾ എന്നിവയുൾപ്പെടെ പ്ലേ ചെയ്യുന്നതെന്തും നിങ്ങൾക്ക് തുടർന്നും കേൾക്കാൻ കഴിയും."</string>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5fb26e0..ae48d21 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -1177,7 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Сүлжээ хайж байна…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Сүлжээнд холбогдож чадсангүй"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Бүгдийг харах"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> нь дараах хавтанг Шуурхай тохиргоонд нэмэх хүмэлтэй байна"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> нь дараах хавтанг Шуурхай тохиргоонд нэмэх хүсэлтэй байна"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Хавтан нэмэх"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Хавтанг бүү нэм"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 87d7b40..dd75e9a 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रीन भरण्यासाठी झूम करा"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रीन भरण्यासाठी ताणा"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रीनशॉट"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock बंद केले"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"इमेज पाठवली आहे"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रीनशॉट सेव्ह करत आहे…"</string>
@@ -134,7 +133,7 @@
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"अॅक्सेसिबिलिटी"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"स्क्रीन फिरवा"</string>
<string name="accessibility_recent" msgid="901641734769533575">"अवलोकन"</string>
- <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+ <string name="accessibility_search_light" msgid="524741790416076988">"शोधा"</string>
<string name="accessibility_camera_button" msgid="2938898391716647247">"कॅमेरा"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"फोन"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"व्हॉइस सहाय्य"</string>
@@ -443,7 +442,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"<xliff:g id="CHARGING_TIME">%s</xliff:g> पूर्ण होईपर्यंत"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"चार्ज होत नाही"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"नेटवर्कचे परीक्षण\nकेले जाऊ शकते"</string>
- <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+ <string name="description_target_search" msgid="3875069993128855865">"शोध"</string>
<string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी वर स्लाइड करा."</string>
<string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> साठी डावीकडे स्लाइड करा."</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"अलार्म, रिमाइंडर, इव्हेंट आणि तुम्ही निश्चित केलेल्या कॉलर व्यतिरिक्त तुम्हाला कोणत्याही आवाज आणि कंपनांचा व्यत्त्यय आणला जाणार नाही. तरीही तुम्ही प्ले करायचे ठरवलेले कोणतेही संगीत, व्हिडिओ आणि गेमचे आवाज ऐकू शकतात."</string>
@@ -1015,7 +1014,7 @@
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(ऑफिस)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"फोन कॉल"</string>
<string name="ongoing_privacy_dialog_attribution_text" msgid="4738795925380373994">"(<xliff:g id="APPLICATION_NAME_S_">%s</xliff:g> द्वारे)"</string>
- <string name="privacy_type_camera" msgid="7974051382167078332">"कॅमेरा"</string>
+ <string name="privacy_type_camera" msgid="7974051382167078332">"camera"</string>
<string name="privacy_type_location" msgid="7991481648444066703">"स्थान"</string>
<string name="privacy_type_microphone" msgid="9136763906797732428">"मायक्रोफोन"</string>
<string name="sensor_privacy_mode" msgid="4462866919026513692">"सेन्सर बंद आहेत"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्क शोधत आहे…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कशी कनेक्ट करता आले नाही"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सर्व पहा"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ला क्विक सेटिंग्जमध्ये पुढील टाइल जोडायची आहे"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल जोडा"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल जोडू नका"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index d90ea35..eb16281 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1177,7 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari rangkaian…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menyambung kepada rangkaian"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> mahu menambah jubin berikut kepada Tetapan Pantas"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> mahu menambah jubin yang berikut kepada Tetapan Pantas"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Tambahkan jubin"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Jangan tambah jubin"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index f19f8de..400b997 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"स्क्रिन भर्न जुम गर्नुहोस्"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"स्क्रिन भर्न तन्काउनुहोस्"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"स्क्रिनसट"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"स्मार्ट लक अफ गरिएको छ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"कुनै छवि पठाइयो"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"स्क्रिनसट बचत गर्दै…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"स्क्रिनसट बचत गर्दै…"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"नेटवर्कहरू खोजिँदै छन्…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"नेटवर्कमा कनेक्ट गर्न सकिएन"</string>
<string name="see_all_networks" msgid="3773666844913168122">"सबै नेटवर्क हेर्नुहोस्"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> द्रुत सेटिङमा निम्न टाइल हाल्न चाहन्छ"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"टाइल हाल्नुहोस्"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"टाइल नहाल्नुहोस्"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 10b3c4c..2aafac4 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ସ୍କ୍ରୀନ ଭରିବା ପାଇଁ ଜୁମ୍ କରନ୍ତୁ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ସ୍କ୍ରୀନ୍କୁ ଭରିବା ପାଇଁ ଟାଣନ୍ତୁ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ସ୍କ୍ରିନ୍ସଟ୍ ନିଅନ୍ତୁ"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"ସ୍ମାର୍ଟ ଲକ୍ ଅକ୍ଷମ କରାଯାଇଛି"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ଏକ ଛବି ପଠାଯାଇଛି"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ସ୍କ୍ରୀନଶଟ୍ ସେଭ୍ କରାଯାଉଛି…"</string>
@@ -134,7 +133,7 @@
<string name="accessibility_accessibility_button" msgid="4089042473497107709">"ଆକ୍ସେସିବିଲିଟୀ"</string>
<string name="accessibility_rotate_button" msgid="1238584767612362586">"ସ୍କ୍ରୀନ୍କୁ ଘୁରାନ୍ତୁ"</string>
<string name="accessibility_recent" msgid="901641734769533575">"ଓଭରଭିଉ"</string>
- <string name="accessibility_search_light" msgid="524741790416076988">"Search"</string>
+ <string name="accessibility_search_light" msgid="524741790416076988">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="accessibility_camera_button" msgid="2938898391716647247">"କ୍ୟାମେରା"</string>
<string name="accessibility_phone_button" msgid="4256353121703100427">"ଫୋନ୍"</string>
<string name="accessibility_voice_assist_button" msgid="6497706615649754510">"ଭଏସ୍ ସହାୟକ"</string>
@@ -443,7 +442,7 @@
<string name="expanded_header_battery_charging_with_time" msgid="757991461445765011">"ପୂର୍ଣ୍ଣ ଚାର୍ଜ ହେବାକୁ ଆଉ <xliff:g id="CHARGING_TIME">%s</xliff:g> ଅଛି"</string>
<string name="expanded_header_battery_not_charging" msgid="809409140358955848">"ଚାର୍ଜ ହେଉନାହିଁ"</string>
<string name="ssl_ca_cert_warning" msgid="8373011375250324005">"ନେଟ୍ୱର୍କ\nମନିଟର୍ କରାଯାଇପାରେ"</string>
- <string name="description_target_search" msgid="3875069993128855865">"Search"</string>
+ <string name="description_target_search" msgid="3875069993128855865">"ସନ୍ଧାନ କରନ୍ତୁ"</string>
<string name="description_direction_up" msgid="3632251507574121434">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ଉପରକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ।"</string>
<string name="description_direction_left" msgid="4762708739096907741">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> ପାଇଁ ବାମକୁ ସ୍ଲାଇଡ୍ କରନ୍ତୁ"</string>
<string name="zen_priority_introduction" msgid="3159291973383796646">"ଆଲାର୍ମ, ରିମାଇଣ୍ଡର୍, ଇଭେଣ୍ଟ ଏବଂ ଆପଣ ନିର୍ଦ୍ଦିଷ୍ଟ କରିଥିବା କଲର୍ଙ୍କ ବ୍ୟତୀତ ଆପଣଙ୍କ ଧ୍ୟାନ ଅନ୍ୟ କୌଣସି ଧ୍ୱନୀ ଏବଂ ଭାଇବ୍ରେଶନ୍ରେ ଆକର୍ଷଣ କରାଯିବନାହିଁ। ମ୍ୟୁଜିକ୍, ଭିଡିଓ ଏବଂ ଗେମ୍ ସମେତ ନିଜେ ଚଲାଇବାକୁ ବାଛିଥିବା ଅନ୍ୟ ସବୁକିଛି ଆପଣ ଶୁଣିପାରିବେ।"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ନେଟୱାର୍କଗୁଡ଼ିକ ସନ୍ଧାନ କରାଯାଉଛି…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ନେଟୱାର୍କକୁ ସଂଯୋଗ କରିବାରେ ବିଫଳ ହୋଇଛି"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ସବୁ ଦେଖନ୍ତୁ"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> କ୍ୱିକ୍ ସେଟିଂସରେ ନିମ୍ନୋକ୍ତ ଟାଇଲ୍ ଯୋଗ କରିବାକୁ ଚାହେଁ"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ଟାଇଲ୍ ଯୋଗ କରନ୍ତୁ"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ଟାଇଲ୍ ଯୋଗ କର ନାହିଁ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index f4ed008..4459ae1c 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਜ਼ੂਮ ਕਰੋ"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"ਸਕ੍ਰੀਨ ਭਰਨ ਲਈ ਸਟ੍ਰੈਚ ਕਰੋ"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"ਸਕ੍ਰੀਨਸ਼ਾਟ"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock ਬੰਦ ਕੀਤਾ ਗਿਆ"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ਚਿੱਤਰ ਭੇਜਿਆ ਗਿਆ"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"ਸਕ੍ਰੀਨਸ਼ਾਟ ਸੁਰੱਖਿਅਤ ਕਰ ਰਿਹਾ ਹੈ…"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"ਨੈੱਟਵਰਕ ਖੋਜੇ ਜਾ ਰਹੇ ਹਨ…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"ਨੈੱਟਵਰਕ ਨਾਲ ਕਨੈਕਟ ਕਰਨਾ ਅਸਫਲ ਰਿਹਾ"</string>
<string name="see_all_networks" msgid="3773666844913168122">"ਸਭ ਦੇਖੋ"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> ਅੱਗੇ ਦਿੱਤੀ ਟਾਇਲ ਨੂੰ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਵਿੱਚ ਸ਼ਾਮਲ ਕਰਨਾ ਚਾਹੁੰਦੀ ਹੈ"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ਟਾਇਲ ਸ਼ਾਮਲ ਕਰੋ"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ਟਾਇਲ ਸ਼ਾਮਲ ਨਾ ਕਰੋ"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index f89d50d..52ee8c6 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"Zmadho për të mbushur ekranin"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"Shtrije për të mbushur ekranin"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"Pamja e ekranit"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock është çaktivizuar"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"dërgoi një imazh"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"Po ruan pamjen e ekranit..."</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"Po ruan pamjen e ekranit…"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Po kërkon për rrjete…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"Lidhja me rrjetin dështoi"</string>
<string name="see_all_networks" msgid="3773666844913168122">"Shiko të gjitha"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> dëshiron të shtojë pllakëzën e mëposhtme te \"Cilësimet e shpejta\""</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"Shto një pllakëz"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"Mos e shto pllakëzën"</string>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 3f0d65d..8c1d5b9 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -77,8 +77,7 @@
<string name="compat_mode_on" msgid="4963711187149440884">"స్క్రీన్కు నింపేలా జూమ్ చేయండి"</string>
<string name="compat_mode_off" msgid="7682459748279487945">"స్క్రీన్కు నింపేలా విస్తరించండి"</string>
<string name="global_action_screenshot" msgid="2760267567509131654">"స్క్రీన్షాట్"</string>
- <!-- no translation found for global_action_smart_lock_disabled (9097102067802412936) -->
- <skip />
+ <string name="global_action_smart_lock_disabled" msgid="9097102067802412936">"Smart Lock డిజేబుల్ చేయబడింది"</string>
<string name="remote_input_image_insertion_text" msgid="4850791636452521123">"ఇమేజ్ను పంపారు"</string>
<string name="screenshot_saving_ticker" msgid="6519186952674544916">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string>
<string name="screenshot_saving_title" msgid="2298349784913287333">"స్క్రీన్షాట్ను సేవ్ చేస్తోంది…"</string>
@@ -276,8 +275,8 @@
<string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"బ్లూటూత్ కనెక్ట్ చేయబడింది."</string>
<string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"బ్లూటూత్ ఆఫ్ చేయబడింది."</string>
<string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"బ్లూటూత్ ఆన్ చేయబడింది."</string>
- <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"స్థాన నివేదన ఆఫ్లో ఉంది."</string>
- <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"స్థాన నివేదన ఆన్లో ఉంది."</string>
+ <string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"లొకేషన్ రిపోర్టింగ్ ఆఫ్లో ఉంది."</string>
+ <string name="accessibility_quick_settings_location_on" msgid="6869947200325467243">"లొకేషన్ రిపోర్టింగ్ ఆన్లో ఉంది."</string>
<string name="accessibility_quick_settings_location_changed_off" msgid="5132776369388699133">"స్థాన నివేదన ఆఫ్ చేయబడింది."</string>
<string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"స్థాన నివేదన ఆన్ చేయబడింది."</string>
<string name="accessibility_quick_settings_alarm" msgid="558094529584082090">"<xliff:g id="TIME">%s</xliff:g>కి అలారం సెట్ చేయబడింది."</string>
@@ -310,7 +309,7 @@
<string name="data_usage_disabled_dialog_enable" msgid="2796648546086408937">"పునఃప్రారంభించు"</string>
<string name="gps_notification_searching_text" msgid="231304732649348313">"GPS కోసం శోధిస్తోంది"</string>
<string name="gps_notification_found_text" msgid="3145873880174658526">"స్థానం GPS ద్వారా సెట్ చేయబడింది"</string>
- <string name="accessibility_location_active" msgid="2845747916764660369">"స్థాన రిక్వెస్ట్లు సక్రియంగా ఉన్నాయి"</string>
+ <string name="accessibility_location_active" msgid="2845747916764660369">"లొకేషన్ రిక్వెస్ట్లు యాక్టివ్గా ఉన్నాయి"</string>
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"సెన్సార్లు ఆఫ్ యాక్టివ్లో ఉంది"</string>
<string name="accessibility_clear_all" msgid="970525598287244592">"అన్ని నోటిఫికేషన్లను క్లియర్ చేయండి."</string>
<string name="notification_group_overflow_indicator" msgid="7605120293801012648">"+ <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -570,7 +569,7 @@
<string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"మీ వ్యక్తిగత ప్రొఫైల్ ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగల <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"మీ పరికరం <xliff:g id="DEVICE_OWNER_APP">%1$s</xliff:g> ద్వారా నిర్వహించబడుతోంది."</string>
<string name="monitoring_description_do_header_with_name" msgid="2696255132542779511">"<xliff:g id="ORGANIZATION_NAME">%1$s</xliff:g> మీ పరికరాన్ని నిర్వహించడానికి <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g>ని ఉపయోగిస్తుంది."</string>
- <string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్లు, కార్పొరేట్ యాక్సెస్, యాప్లు, డేటా మరియు మీ పరికరం యొక్క స్థాన సమాచారాన్ని మీ నిర్వాహకులు పర్యవేక్షించగలరు మరియు నిర్వహించగలరు."</string>
+ <string name="monitoring_description_do_body" msgid="7700878065625769970">"మీ పరికరంతో అనుబంధించబడిన సెట్టింగ్లు, కార్పొరేట్ యాక్సెస్, యాప్లు, డేటా మరియు మీ పరికరం యొక్క లొకేషన్ సమాచారాన్ని మీ అడ్మిన్ పర్యవేక్షించగలరు, మేనేజ్ చేయగలరు."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"మరింత తెలుసుకోండి"</string>
<string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"మీరు <xliff:g id="VPN_APP">%1$s</xliff:g>కి కనెక్ట్ చేయబడ్డారు, ఇది ఇమెయిల్లు, యాప్లు మరియు వెబ్సైట్లతో సహా మీ వ్యక్తిగత నెట్వర్క్ కార్యాచరణను పర్యవేక్షించగలదు."</string>
@@ -871,7 +870,7 @@
<string name="nav_bar_layout" msgid="4716392484772899544">"లేఅవుట్"</string>
<string name="left_nav_bar_button_type" msgid="2634852842345192790">"అత్యంత ఎడమ వైపు ఉన్న బటన్ రకం"</string>
<string name="right_nav_bar_button_type" msgid="4472566498647364715">"అత్యంత కుడివైపు ఉన్న బటన్ రకం"</string>
- <string name="nav_bar_default" msgid="8386559913240761526">"(డిఫాల్ట్)"</string>
+ <string name="nav_bar_default" msgid="8386559913240761526">"(ఆటోమేటిక్)"</string>
<string-array name="nav_bar_buttons">
<item msgid="2681220472659720036">"క్లిప్బోర్డ్"</item>
<item msgid="4795049793625565683">"కీకోడ్"</item>
@@ -902,12 +901,12 @@
<string name="tuner_time" msgid="2450785840990529997">"సమయం"</string>
<string-array name="clock_options">
<item msgid="3986445361435142273">"గంటలు, నిమిషాలు మరియు సెకన్లను చూపు"</item>
- <item msgid="1271006222031257266">"గంటలు మరియు నిమిషాలను చూపు (డిఫాల్ట్)"</item>
+ <item msgid="1271006222031257266">"గంటలు, నిమిషాలను చూపు (ఆటోమేటిక్)"</item>
<item msgid="6135970080453877218">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
</string-array>
<string-array name="battery_options">
<item msgid="7714004721411852551">"ఎల్లప్పుడూ శాతాన్ని చూపు"</item>
- <item msgid="3805744470661798712">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (డిఫాల్ట్)"</item>
+ <item msgid="3805744470661798712">"ఛార్జ్ అవుతున్నప్పుడు శాతాన్ని చూపు (ఆటోమేటిక్)"</item>
<item msgid="8619482474544321778">"ఈ చిహ్నాన్ని చూపవద్దు"</item>
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"తక్కువ ప్రాధాన్యత నోటిఫికేషన్ చిహ్నాలను చూపించు"</string>
@@ -1178,10 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"నెట్వర్క్ల కోసం సెర్చ్ చేస్తోంది…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"నెట్వర్క్కు కనెక్ట్ చేయడం విఫలమైంది"</string>
<string name="see_all_networks" msgid="3773666844913168122">"అన్నీ చూడండి"</string>
- <!-- no translation found for qs_tile_request_dialog_text (3501359944139877694) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_add (4888460910694986304) -->
- <skip />
- <!-- no translation found for qs_tile_request_dialog_not_add (4168716573114067296) -->
- <skip />
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"కింది టైల్ను క్విక్ సెట్టింగ్లకు జోడించడానికి <xliff:g id="APPNAME">%1$s</xliff:g> అనుమతి కోరుతోంది"</string>
+ <string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"టైల్ను జోడించండి"</string>
+ <string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"టైల్ను జోడించవద్దు"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index bbaaf20..59d2acf 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1177,7 +1177,7 @@
<string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"نیٹ ورکس تلاش کیے جا رہے ہیں…"</string>
<string name="wifi_failed_connect_message" msgid="4161863112079000071">"نیٹ ورک سے منسلک ہونے میں ناکام ہو گیا"</string>
<string name="see_all_networks" msgid="3773666844913168122">"سبھی دیکھیں"</string>
- <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> درج ذیل ٹائل کو فوری ترتیبات میں شامل کرنا چاہتا ہے"</string>
+ <string name="qs_tile_request_dialog_text" msgid="3501359944139877694">"<xliff:g id="APPNAME">%1$s</xliff:g> درج ذیل ٹائل کو فوری ترتیبات میں شامل کرنا چاہتی ہے"</string>
<string name="qs_tile_request_dialog_add" msgid="4888460910694986304">"ٹائل شامل کریں"</string>
<string name="qs_tile_request_dialog_not_add" msgid="4168716573114067296">"ٹائل شامل نہ کریں"</string>
</resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 624f3a8..fd31f3f9 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -3000,7 +3000,7 @@
<string name="mobile_data_connection_active">Connected</string>
<!-- Provider Model:
Summary indicating that a SIM has no mobile data connection [CHAR LIMIT=50] -->
- <string name="mobile_data_off_summary">Internet won\u0027t auto\u2011connect</string>
+ <string name="mobile_data_off_summary">Mobile data won\u0027t auto\u2011connect</string>
<!-- Provider Model:
Summary indicating that a active SIM and no network available [CHAR LIMIT=50] -->
<string name="mobile_data_no_connection">No connection</string>
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 93388f9..0f888cb 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
@@ -19,9 +19,7 @@
import static android.view.WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SEARCH_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.isGesturalMode;
@@ -79,9 +77,9 @@
import com.android.systemui.navigationbar.buttons.RotationContextButton;
import com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler;
import com.android.systemui.navigationbar.gestural.FloatingRotationButton;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.recents.OverviewProxyService;
import com.android.systemui.recents.Recents;
+import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.SysUiStatsLog;
@@ -841,7 +839,6 @@
public void onStatusBarPanelStateChanged() {
updateSlippery();
- updatePanelSystemUiStateFlags();
}
public void updateDisabledSystemUiStateFlags() {
@@ -858,21 +855,12 @@
.commitUpdate(displayId);
}
- public void updatePanelSystemUiStateFlags() {
- int displayId = mContext.getDisplayId();
+ private void updatePanelSystemUiStateFlags() {
if (SysUiState.DEBUG) {
Log.d(TAG, "Updating panel sysui state flags: panelView=" + mPanelView);
}
if (mPanelView != null) {
- if (SysUiState.DEBUG) {
- Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
- + mPanelView.isFullyExpanded() + " inQs=" + mPanelView.isInSettings());
- }
- mSysUiFlagContainer.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
- mPanelView.isFullyExpanded() && !mPanelView.isInSettings())
- .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
- mPanelView.isInSettings())
- .commitUpdate(displayId);
+ mPanelView.updateSystemUiStateFlags();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index e0caf12..3167070 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -18,20 +18,27 @@
import static android.app.StatusBarManager.NAVIGATION_HINT_BACK_ALT;
import static android.app.StatusBarManager.NAVIGATION_HINT_IME_SHOWN;
+import static android.app.StatusBarManager.WINDOW_STATE_SHOWING;
+import static android.view.WindowInsetsController.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
+import android.app.StatusBarManager;
+import android.app.StatusBarManager.WindowVisibleState;
import android.content.Context;
import android.inputmethodservice.InputMethodService;
import android.os.IBinder;
import android.view.InsetsVisibilities;
import android.view.View;
+import android.view.WindowInsetsController.Behavior;
import com.android.internal.view.AppearanceRegion;
import com.android.systemui.Dependency;
@@ -60,6 +67,8 @@
private final NavigationBarA11yHelper.NavA11yEventListener mNavA11yEventListener =
this::updateSysuiFlags;
private int mDisabledFlags;
+ private @WindowVisibleState int mTaskBarWindowState = WINDOW_STATE_SHOWING;
+ private @Behavior int mBehavior;
@Inject
public TaskbarDelegate(Context context) {
@@ -114,6 +123,9 @@
(mDisabledFlags & View.STATUS_BAR_DISABLE_HOME) != 0)
.setFlag(SYSUI_STATE_BACK_DISABLED,
(mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
+ .setFlag(SYSUI_STATE_NAV_BAR_HIDDEN, !isWindowVisible())
+ .setFlag(SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY,
+ allowSystemGestureIgnoringBarVisibility())
.commitUpdate(mDisplayId);
}
@@ -130,6 +142,16 @@
}
@Override
+ public void setWindowState(int displayId, int window, int state) {
+ if (displayId == mDisplayId
+ && window == StatusBarManager.WINDOW_NAVIGATION_BAR
+ && mTaskBarWindowState != state) {
+ mTaskBarWindowState = state;
+ updateSysuiFlags();
+ }
+ }
+
+ @Override
public void onRotationProposal(int rotation, boolean isValid) {
mOverviewProxyService.onRotationProposal(rotation, isValid);
}
@@ -146,6 +168,10 @@
AppearanceRegion[] appearanceRegions, boolean navbarColorManagedByIme, int behavior,
InsetsVisibilities requestedVisibilities, String packageName) {
mOverviewProxyService.onSystemBarAttributesChanged(displayId, behavior);
+ if (mBehavior != behavior) {
+ mBehavior = behavior;
+ updateSysuiFlags();
+ }
}
@Override
@@ -161,4 +187,12 @@
public void onNavigationModeChanged(int mode) {
mEdgeBackGestureHandler.onNavigationModeChanged(mode);
}
+
+ private boolean isWindowVisible() {
+ return mTaskBarWindowState == WINDOW_STATE_SHOWING;
+ }
+
+ private boolean allowSystemGestureIgnoringBarVisibility() {
+ return mBehavior != BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE;
+ }
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
new file mode 100644
index 0000000..55da203
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/TEST_MAPPING
@@ -0,0 +1,21 @@
+{
+ "presubmit": [
+ {
+ "name": "CtsAppTestCases",
+ "options": [
+ {
+ "include-filter": "android.app.cts.TileServiceTest"
+ },
+ {
+ "include-filter": "android.app.cts.BooleanTileServiceTest"
+ },
+ {
+ "exclude-annotation": "org.junit.Ignore"
+ },
+ {
+ "exclude-annotation": "androidx.test.filters.FlakyTest"
+ }
+ ]
+ }
+ ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index 396eca5..c5fa76e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -63,6 +63,7 @@
import com.android.systemui.qs.tileimpl.QSTileImpl;
import java.util.Objects;
+import java.util.concurrent.atomic.AtomicBoolean;
import javax.inject.Inject;
@@ -98,6 +99,8 @@
private final TileServiceKey mKey;
+ private final AtomicBoolean mInitialDefaultIconFetched = new AtomicBoolean(false);
+
private CustomTile(
QSHost host,
Looper backgroundLooper,
@@ -128,6 +131,12 @@
@Override
protected void handleInitialize() {
updateDefaultTileAndIcon();
+ if (mInitialDefaultIconFetched.compareAndSet(false, true)) {
+ if (mDefaultIcon == null) {
+ mQSLogger.logTileDestroyed(getTileSpec(),
+ "Custom tile default icon not available");
+ }
+ }
if (mServiceManager.isToggleableTile()) {
// Replace states with BooleanState
resetStates();
@@ -213,9 +222,18 @@
mHandler.post(this::updateDefaultTileAndIcon);
}
+ /**
+ * Custom tile is considered available if there is a default icon (obtained from PM).
+ *
+ * It will return {@code true} before initialization, so tiles are not destroyed prematurely.
+ */
@Override
public boolean isAvailable() {
- return mDefaultIcon != null;
+ if (mInitialDefaultIconFetched.get()) {
+ return mDefaultIcon != null;
+ } else {
+ return true;
+ }
}
public int getUser() {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
index 4616be8..70e3a2b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSTileImpl.java
@@ -105,7 +105,7 @@
protected final ActivityStarter mActivityStarter;
private final UiEventLogger mUiEventLogger;
private final FalsingManager mFalsingManager;
- private final QSLogger mQSLogger;
+ protected final QSLogger mQSLogger;
private volatile int mReadyState;
private final ArrayList<Callback> mCallbacks = new ArrayList<>();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
index 04437ea..ccc08e0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserDetailView.java
@@ -23,6 +23,7 @@
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
+import android.os.Trace;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
@@ -150,6 +151,7 @@
return;
}
+ Trace.beginSection("UserDetailView.Adapter#onClick");
UserSwitcherController.UserRecord tag =
(UserSwitcherController.UserRecord) view.getTag();
if (tag.isDisabledByAdmin) {
@@ -167,6 +169,7 @@
}
onUserListItemClicked(tag);
}
+ Trace.endSection();
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a5fc5ab..50b1186 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -94,6 +94,7 @@
import com.android.systemui.shared.system.smartspace.SmartspaceTransitionController;
import com.android.systemui.statusbar.CommandQueue;
import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import com.android.systemui.statusbar.phone.StatusBar;
import com.android.systemui.statusbar.phone.StatusBarWindowCallback;
import com.android.systemui.statusbar.policy.CallbackController;
@@ -626,18 +627,22 @@
mNavBarControllerLazy.get().getDefaultNavigationBar();
final NavigationBarView navBarView =
mNavBarControllerLazy.get().getNavigationBarView(mContext.getDisplayId());
+ final NotificationPanelViewController panelController =
+ mStatusBarOptionalLazy.get().get().getPanelController();
if (SysUiState.DEBUG) {
Log.d(TAG_OPS, "Updating sysui state flags: navBarFragment=" + navBarFragment
- + " navBarView=" + navBarView);
+ + " navBarView=" + navBarView + " panelController=" + panelController);
}
if (navBarFragment != null) {
navBarFragment.updateSystemUiStateFlags(-1);
}
if (navBarView != null) {
- navBarView.updatePanelSystemUiStateFlags();
navBarView.updateDisabledSystemUiStateFlags();
}
+ if (panelController != null) {
+ panelController.updateSystemUiStateFlags();
+ }
if (mStatusBarWinController != null) {
mStatusBarWinController.notifyStateChangedCallbacks();
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
index 727ce20..289dacb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeController.kt
@@ -78,7 +78,7 @@
}
private fun treeSpecToStrHelper(tree: NodeSpec, sb: StringBuilder, indent: String) {
- sb.append("${indent}ns{${tree.controller.nodeLabel}")
+ sb.append("${indent}{${tree.controller.nodeLabel}}\n")
if (tree.children.isNotEmpty()) {
val childIndent = "$indent "
for (child in tree.children) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
new file mode 100644
index 0000000..9b8ac72
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilder.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 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.collection.render
+
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+
+/**
+ * Converts a notif list (the output of the ShadeListBuilder) into a NodeSpec, an abstract
+ * representation of which views should be present in the shade. This spec will later be consumed
+ * by the ViewDiffer, which will add and remove views until the shade matches the spec. Up until
+ * this point, the pipeline has dealt with pure data representations of notifications (in the
+ * form of NotificationEntries). In this step, NotificationEntries finally become associated with
+ * the views that will represent them. In addition, we add in any non-notification views that also
+ * need to present in the shade, notably the section headers.
+ */
+class NodeSpecBuilder(
+ private val viewBarn: NotifViewBarn
+) {
+ fun buildNodeSpec(
+ rootController: NodeController,
+ notifList: List<ListEntry>
+ ): NodeSpec {
+ val root = NodeSpecImpl(null, rootController)
+ var currentSection: NotifSection? = null
+ val prevSections = mutableSetOf<NotifSection?>()
+
+ for (entry in notifList) {
+ val section = entry.section!!
+
+ if (prevSections.contains(section)) {
+ throw java.lang.RuntimeException("Section ${section.label} has been duplicated")
+ }
+
+ // If this notif begins a new section, first add the section's header view
+ if (section != currentSection) {
+ section.headerController?.let { headerController ->
+ root.children.add(NodeSpecImpl(root, headerController))
+ }
+ prevSections.add(currentSection)
+ currentSection = section
+ }
+
+ // Finally, add the actual notif node!
+ root.children.add(buildNotifNode(root, entry))
+ }
+
+ return root
+ }
+
+ private fun buildNotifNode(parent: NodeSpec, entry: ListEntry): NodeSpec = when (entry) {
+ is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
+ is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
+ .apply { entry.children.forEach { children.add(buildNotifNode(this, it)) } }
+ else -> throw RuntimeException("Unexpected entry: $entry")
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
index 79bc3d7..c79f59b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/NotifViewBarn.kt
@@ -19,18 +19,16 @@
import android.view.textclassifier.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.statusbar.notification.collection.ListEntry
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController
import javax.inject.Inject
/**
- * The ViewBarn is just a map from [ListEntry] to an instance of an
- * [ExpandableNotificationRowController].
+ * The ViewBarn is just a map from [ListEntry] to an instance of a [NodeController].
*/
@SysUISingleton
class NotifViewBarn @Inject constructor() {
- private val rowMap = mutableMapOf<String, ExpandableNotificationRowController>()
+ private val rowMap = mutableMapOf<String, NodeController>()
- fun requireView(forEntry: ListEntry): ExpandableNotificationRowController {
+ fun requireView(forEntry: ListEntry): NodeController {
if (DEBUG) {
Log.d(TAG, "requireView: $forEntry.key")
}
@@ -42,7 +40,7 @@
return li
}
- fun registerViewForEntry(entry: ListEntry, controller: ExpandableNotificationRowController) {
+ fun registerViewForEntry(entry: ListEntry, controller: NodeController) {
if (DEBUG) {
Log.d(TAG, "registerViewForEntry: $entry.key")
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
index ef1d75e9..a2c7aa5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/ShadeViewManager.kt
@@ -18,9 +18,7 @@
import android.content.Context
import android.view.View
-import com.android.systemui.statusbar.notification.collection.GroupEntry
import com.android.systemui.statusbar.notification.collection.ListEntry
-import com.android.systemui.statusbar.notification.collection.NotificationEntry
import com.android.systemui.statusbar.notification.collection.ShadeListBuilder
import com.android.systemui.statusbar.notification.stack.NotificationListContainer
import com.android.systemui.statusbar.phone.NotificationIconAreaController
@@ -34,45 +32,21 @@
context: Context,
listContainer: NotificationListContainer,
logger: ShadeViewDifferLogger,
- private val viewBarn: NotifViewBarn,
+ viewBarn: NotifViewBarn,
private val notificationIconAreaController: NotificationIconAreaController
) {
// We pass a shim view here because the listContainer may not actually have a view associated
// with it and the differ never actually cares about the root node's view.
private val rootController = RootNodeController(listContainer, View(context))
+ private val specBuilder = NodeSpecBuilder(viewBarn)
private val viewDiffer = ShadeViewDiffer(rootController, logger)
fun attach(listBuilder: ShadeListBuilder) =
listBuilder.setOnRenderListListener(::onNewNotifTree)
- private fun onNewNotifTree(tree: List<ListEntry>) = viewDiffer.applySpec(buildTree(tree))
-
- private fun buildTree(notifList: List<ListEntry>): NodeSpec {
- val root = NodeSpecImpl(null, rootController).apply {
- // Insert first section header, if present
- notifList.firstOrNull()?.section?.headerController?.let {
- children.add(NodeSpecImpl(this, it))
- }
- notifList.firstOrNull()?.let {
- children.add(buildNotifNode(it, this))
- }
- notifList.asSequence().zipWithNext().forEach { (prev, entry) ->
- // Insert new header if the section has changed between two entries
- entry.section.takeIf { it != prev.section }?.headerController?.let {
- children.add(NodeSpecImpl(this, it))
- }
- children.add(buildNotifNode(entry, this))
- }
- }
+ private fun onNewNotifTree(notifList: List<ListEntry>) {
+ viewDiffer.applySpec(specBuilder.buildNodeSpec(rootController, notifList))
notificationIconAreaController.updateNotificationIcons(notifList)
- return root
- }
-
- private fun buildNotifNode(entry: ListEntry, parent: NodeSpec): NodeSpec = when (entry) {
- is NotificationEntry -> NodeSpecImpl(parent, viewBarn.requireView(entry))
- is GroupEntry -> NodeSpecImpl(parent, viewBarn.requireView(checkNotNull(entry.summary)))
- .apply { entry.children.forEach { children.add(buildNotifNode(it, this)) } }
- else -> throw RuntimeException("Unexpected entry: $entry")
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
index f613096..0faf520 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelViewController.java
@@ -28,6 +28,8 @@
import static com.android.keyguard.KeyguardClockSwitch.SMALL;
import static com.android.systemui.classifier.Classifier.QS_COLLAPSE;
import static com.android.systemui.classifier.Classifier.QUICK_SETTINGS;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.StatusBarState.SHADE;
import static com.android.systemui.statusbar.StatusBarState.SHADE_LOCKED;
@@ -97,6 +99,7 @@
import com.android.keyguard.dagger.KeyguardStatusViewComponent;
import com.android.keyguard.dagger.KeyguardUserSwitcherComponent;
import com.android.systemui.DejankUtils;
+import com.android.systemui.Dependency;
import com.android.systemui.R;
import com.android.systemui.animation.ActivityLaunchAnimator;
import com.android.systemui.animation.Interpolators;
@@ -120,6 +123,7 @@
import com.android.systemui.media.KeyguardMediaController;
import com.android.systemui.media.MediaDataManager;
import com.android.systemui.media.MediaHierarchyManager;
+import com.android.systemui.model.SysUiState;
import com.android.systemui.navigationbar.NavigationModeController;
import com.android.systemui.plugins.FalsingManager;
import com.android.systemui.plugins.FalsingManager.FalsingTapListener;
@@ -511,6 +515,8 @@
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
+ private final SysUiState mSysUiState;
+
private NotificationShadeDepthController mDepthController;
private int mDisplayId;
@@ -829,6 +835,8 @@
mTapAgainViewController = tapAgainViewController;
mUiExecutor = uiExecutor;
mSecureSettings = secureSettings;
+ // TODO: inject via dagger instead of Dependency
+ mSysUiState = Dependency.get(SysUiState.class);
pulseExpansionHandler.setPulseExpandAbortListener(() -> {
if (mQs != null) {
mQs.animateHeaderSlidingOut();
@@ -4065,6 +4073,20 @@
mContentResolver.unregisterContentObserver(mSettingsChangeObserver);
}
+ /**
+ * Updates notification panel-specific flags on {@link SysUiState}.
+ */
+ public void updateSystemUiStateFlags() {
+ if (SysUiState.DEBUG) {
+ Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
+ + isFullyExpanded() + " inQs=" + isInSettings());
+ }
+ mSysUiState.setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+ isFullyExpanded() && !isInSettings())
+ .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED, isInSettings())
+ .commitUpdate(mDisplayId);
+ }
+
private class OnHeightChangedListener implements ExpandableView.OnHeightChangedListener {
@Override
public void onHeightChanged(ExpandableView view, boolean needsAnimation) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 70a46b2..88a823c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -287,8 +287,13 @@
public void panelExpansionChanged(float frac, boolean expanded) {
super.panelExpansionChanged(frac, expanded);
updateScrimFraction();
- if ((frac == 0 || frac == 1) && mBar.getNavigationBarView() != null) {
- mBar.getNavigationBarView().onStatusBarPanelStateChanged();
+ if ((frac == 0 || frac == 1)) {
+ if (mBar.getNavigationBarView() != null) {
+ mBar.getNavigationBarView().onStatusBarPanelStateChanged();
+ }
+ if (mBar.getNotificationPanelViewController() != null) {
+ mBar.getNotificationPanelViewController().updateSystemUiStateFlags();
+ }
}
if (mExpansionChangedListeners != null) {
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 0f6ad1ce..4452a65 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1824,6 +1824,7 @@
mNotificationPanelViewController.setStatusAccessibilityImportance(expanded
? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
+ mNotificationPanelViewController.updateSystemUiStateFlags();
if (getNavigationBarView() != null) {
getNavigationBarView().onStatusBarPanelStateChanged();
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
index fbb0a95..c746bca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/QSTileHostTest.java
@@ -20,8 +20,8 @@
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertFalse;
import static junit.framework.Assert.assertTrue;
+
import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.ArgumentMatchers.isNull;
import static org.mockito.Mockito.mock;
@@ -424,7 +424,7 @@
mock(MetricsLogger.class),
mock(StatusBarStateController.class),
mock(ActivityStarter.class),
- mQSLogger
+ QSTileHostTest.this.mQSLogger
);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
index 9b5c161..9755d91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/CustomTileTest.kt
@@ -270,4 +270,20 @@
verify(customTileStatePersister)
.persistState(TileServiceKey(componentName, customTile.user), t)
}
+
+ @Test
+ fun testAvailableBeforeInitialization() {
+ `when`(packageManager.getApplicationInfo(anyString(), anyInt()))
+ .thenThrow(PackageManager.NameNotFoundException())
+ val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+ assertTrue(tile.isAvailable)
+ }
+
+ @Test
+ fun testNotAvailableAfterInitializationWithoutIcon() {
+ val tile = CustomTile.create(customTileBuilder, TILE_SPEC, mContext)
+ tile.initialize()
+ testableLooper.processAllMessages()
+ assertFalse(tile.isAvailable)
+ }
}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
index 62667bc..da956ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/EntryUtil.kt
@@ -30,3 +30,7 @@
modifier(builder)
builder.apply(entry)
}
+
+fun getAttachState(entry: ListEntry): ListAttachState {
+ return entry.attachState
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
new file mode 100644
index 0000000..2e676bb
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/collection/render/NodeSpecBuilderTest.kt
@@ -0,0 +1,311 @@
+/*
+ * Copyright (C) 2021 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.collection.render
+
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.GroupEntry
+import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
+import com.android.systemui.statusbar.notification.collection.ListEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.getAttachState
+import com.android.systemui.statusbar.notification.collection.listbuilder.NotifSection
+import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifSectioner
+import com.android.systemui.util.mockito.any
+import org.junit.Before
+import org.junit.Test
+import org.mockito.Mock
+import org.mockito.Mockito
+import org.mockito.Mockito.`when`
+import org.mockito.MockitoAnnotations
+
+@SmallTest
+class NodeSpecBuilderTest : SysuiTestCase() {
+
+ @Mock
+ private lateinit var viewBarn: NotifViewBarn
+
+ private var rootController: NodeController = buildFakeController("rootController")
+ private var headerController0: NodeController = buildFakeController("header0")
+ private var headerController1: NodeController = buildFakeController("header1")
+ private var headerController2: NodeController = buildFakeController("header2")
+
+ private val section0 = buildSection(0, headerController0)
+ private val section0NoHeader = buildSection(0, null)
+ private val section1 = buildSection(1, headerController1)
+ private val section1NoHeader = buildSection(1, null)
+ private val section2 = buildSection(2, headerController2)
+
+ private val fakeViewBarn = FakeViewBarn()
+
+ private lateinit var specBuilder: NodeSpecBuilder
+
+ @Before
+ fun setUp() {
+ MockitoAnnotations.initMocks(this)
+
+ `when`(viewBarn.requireView(any())).thenAnswer {
+ fakeViewBarn.getViewByEntry(it.getArgument(0))
+ }
+
+ specBuilder = NodeSpecBuilder(viewBarn)
+ }
+
+ @Test
+ fun testSimpleMapping() {
+ checkOutput(
+ // GIVEN a simple flat list of notifications all in the same headerless section
+ listOf(
+ notif(0, section0NoHeader),
+ notif(1, section0NoHeader),
+ notif(2, section0NoHeader),
+ notif(3, section0NoHeader)
+ ),
+
+ // THEN we output a similarly simple flag list of nodes
+ tree(
+ notifNode(0),
+ notifNode(1),
+ notifNode(2),
+ notifNode(3)
+ )
+ )
+ }
+
+ @Test
+ fun testHeaderInjection() {
+ checkOutput(
+ // GIVEN a flat list of notifications, spread across three sections
+ listOf(
+ notif(0, section0),
+ notif(1, section0),
+ notif(2, section1),
+ notif(3, section2)
+ ),
+
+ // THEN each section has its header injected
+ tree(
+ node(headerController0),
+ notifNode(0),
+ notifNode(1),
+ node(headerController1),
+ notifNode(2),
+ node(headerController2),
+ notifNode(3)
+ )
+ )
+ }
+
+ @Test
+ fun testGroups() {
+ checkOutput(
+ // GIVEN a mixed list of top-level notifications and groups
+ listOf(
+ notif(0, section0),
+ group(1, section1,
+ notif(2),
+ notif(3),
+ notif(4)
+ ),
+ notif(5, section2),
+ group(6, section2,
+ notif(7),
+ notif(8),
+ notif(9)
+ )
+ ),
+
+ // THEN we properly construct all the nodes
+ tree(
+ node(headerController0),
+ notifNode(0),
+ node(headerController1),
+ notifNode(1,
+ notifNode(2),
+ notifNode(3),
+ notifNode(4)
+ ),
+ node(headerController2),
+ notifNode(5),
+ notifNode(6,
+ notifNode(7),
+ notifNode(8),
+ notifNode(9)
+ )
+ )
+ )
+ }
+
+ @Test
+ fun testSecondSectionWithNoHeader() {
+ checkOutput(
+ // GIVEN a middle section with no associated header view
+ listOf(
+ notif(0, section0),
+ notif(1, section1NoHeader),
+ group(2, section1NoHeader,
+ notif(3),
+ notif(4)
+ ),
+ notif(5, section2)
+ ),
+
+ // THEN the header view is left out of the tree (but the notifs are still present)
+ tree(
+ node(headerController0),
+ notifNode(0),
+ notifNode(1),
+ notifNode(2,
+ notifNode(3),
+ notifNode(4)
+ ),
+ node(headerController2),
+ notifNode(5)
+ )
+ )
+ }
+
+ @Test(expected = RuntimeException::class)
+ fun testRepeatedSectionsThrow() {
+ checkOutput(
+ // GIVEN a malformed list where sections are not contiguous
+ listOf(
+ notif(0, section0),
+ notif(1, section1),
+ notif(2, section0)
+ ),
+
+ // THEN an exception is thrown
+ tree()
+ )
+ }
+
+ private fun checkOutput(list: List<ListEntry>, desiredTree: NodeSpecImpl) {
+ checkTree(desiredTree, specBuilder.buildNodeSpec(rootController, list))
+ }
+
+ private fun checkTree(desiredTree: NodeSpec, actualTree: NodeSpec) {
+ try {
+ checkNode(desiredTree, actualTree)
+ } catch (e: AssertionError) {
+ throw AssertionError("Trees don't match: ${e.message}\nActual tree:\n" +
+ treeSpecToStr(actualTree))
+ }
+ }
+
+ private fun checkNode(desiredTree: NodeSpec, actualTree: NodeSpec) {
+ if (actualTree.controller != desiredTree.controller) {
+ throw AssertionError("Node {${actualTree.controller.nodeLabel}} should " +
+ "be ${desiredTree.controller.nodeLabel}")
+ }
+ for (i in 0 until desiredTree.children.size) {
+ if (i >= actualTree.children.size) {
+ throw AssertionError("Node {${actualTree.controller.nodeLabel}}" +
+ " is missing child ${desiredTree.children[i].controller.nodeLabel}")
+ }
+ checkNode(desiredTree.children[i], actualTree.children[i])
+ }
+ }
+
+ private fun notif(id: Int, section: NotifSection? = null): NotificationEntry {
+ val entry = NotificationEntryBuilder()
+ .setId(id)
+ .build()
+ if (section != null) {
+ getAttachState(entry).section = section
+ }
+ fakeViewBarn.buildNotifView(id, entry)
+ return entry
+ }
+
+ private fun group(
+ id: Int,
+ section: NotifSection,
+ vararg children: NotificationEntry
+ ): GroupEntry {
+ val group = GroupEntryBuilder()
+ .setKey("group_$id")
+ .setSummary(
+ NotificationEntryBuilder()
+ .setId(id)
+ .build())
+ .setChildren(children.asList())
+ .build()
+ getAttachState(group).section = section
+ fakeViewBarn.buildNotifView(id, group.summary!!)
+
+ for (child in children) {
+ getAttachState(child).section = section
+ }
+ return group
+ }
+
+ private fun tree(vararg children: NodeSpecImpl): NodeSpecImpl {
+ return node(rootController, *children)
+ }
+
+ private fun node(view: NodeController, vararg children: NodeSpecImpl): NodeSpecImpl {
+ val node = NodeSpecImpl(null, view)
+ node.children.addAll(children)
+ return node
+ }
+
+ private fun notifNode(id: Int, vararg children: NodeSpecImpl): NodeSpecImpl {
+ return node(fakeViewBarn.getViewById(id), *children)
+ }
+}
+
+private class FakeViewBarn {
+ private val entries = mutableMapOf<Int, NotificationEntry>()
+ private val views = mutableMapOf<NotificationEntry, NodeController>()
+
+ fun buildNotifView(id: Int, entry: NotificationEntry) {
+ if (entries.contains(id)) {
+ throw RuntimeException("ID $id is already in use")
+ }
+ entries[id] = entry
+ views[entry] = buildFakeController("Entry $id")
+ }
+
+ fun getViewById(id: Int): NodeController {
+ return views[entries[id] ?: throw RuntimeException("No view with ID $id")]!!
+ }
+
+ fun getViewByEntry(entry: NotificationEntry): NodeController {
+ return views[entry] ?: throw RuntimeException("No view defined for key ${entry.key}")
+ }
+}
+
+private fun buildFakeController(name: String): NodeController {
+ val controller = Mockito.mock(NodeController::class.java)
+ `when`(controller.nodeLabel).thenReturn(name)
+ return controller
+}
+
+private fun buildSection(index: Int, nodeController: NodeController?): NotifSection {
+ return NotifSection(object : NotifSectioner("Section $index") {
+
+ override fun isInSection(entry: ListEntry?): Boolean {
+ throw NotImplementedError("This should never be called")
+ }
+
+ override fun getHeaderNodeController(): NodeController? {
+ return nodeController
+ }
+ }, index)
+}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 62b36d0..2813236 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -152,12 +152,9 @@
import com.android.internal.annotations.GuardedBy;
import com.android.internal.compat.IPlatformCompat;
import com.android.internal.content.PackageMonitor;
-import com.android.internal.inputmethod.CallbackUtils;
-import com.android.internal.inputmethod.IBooleanResultCallback;
+import com.android.internal.infra.AndroidFuture;
import com.android.internal.inputmethod.IInputContentUriToken;
-import com.android.internal.inputmethod.IInputContentUriTokenResultCallback;
import com.android.internal.inputmethod.IInputMethodPrivilegedOperations;
-import com.android.internal.inputmethod.IVoidResultCallback;
import com.android.internal.inputmethod.ImeTracing;
import com.android.internal.inputmethod.InputBindResult;
import com.android.internal.inputmethod.InputMethodDebug;
@@ -2587,14 +2584,12 @@
}
if (mCurToken != null) {
- try {
- if (DEBUG) {
- Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
- + mCurTokenDisplayId);
- }
- mIWindowManager.removeWindowToken(mCurToken, mCurTokenDisplayId);
- } catch (RemoteException e) {
+ if (DEBUG) {
+ Slog.v(TAG, "Removing window token: " + mCurToken + " for display: "
+ + mCurTokenDisplayId);
}
+ mWindowManagerInternal.removeWindowToken(mCurToken, false /* removeWindows */,
+ false /* animateExit */, mCurTokenDisplayId);
// Set IME window status as invisible when unbind current method.
mImeWindowVis = 0;
mBackDisposition = InputMethodService.BACK_DISPOSITION_DEFAULT;
@@ -5842,9 +5837,15 @@
@BinderThread
@Override
public void createInputContentUriToken(Uri contentUri, String packageName,
- IInputContentUriTokenResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback,
- () -> mImms.createInputContentUriToken(mToken, contentUri, packageName));
+ AndroidFuture future /* T=IBinder */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<IBinder> typedFuture = future;
+ try {
+ typedFuture.complete(mImms.createInputContentUriToken(
+ mToken, contentUri, packageName).asBinder());
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@@ -5855,28 +5856,55 @@
@BinderThread
@Override
- public void setInputMethod(String id, IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> mImms.setInputMethod(mToken, id));
+ public void setInputMethod(String id, AndroidFuture future /* T=Void */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Void> typedFuture = future;
+ try {
+ mImms.setInputMethod(mToken, id);
+ typedFuture.complete(null);
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@Override
public void setInputMethodAndSubtype(String id, InputMethodSubtype subtype,
- IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback,
- () -> mImms.setInputMethodAndSubtype(mToken, id, subtype));
+ AndroidFuture future /* T=Void */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Void> typedFuture = future;
+ try {
+ mImms.setInputMethodAndSubtype(mToken, id, subtype);
+ typedFuture.complete(null);
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@Override
- public void hideMySoftInput(int flags, IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> mImms.hideMySoftInput(mToken, flags));
+ public void hideMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Void> typedFuture = future;
+ try {
+ mImms.hideMySoftInput(mToken, flags);
+ typedFuture.complete(null);
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@Override
- public void showMySoftInput(int flags, IVoidResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> mImms.showMySoftInput(mToken, flags));
+ public void showMySoftInput(int flags, AndroidFuture future /* T=Void */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Void> typedFuture = future;
+ try {
+ mImms.showMySoftInput(mToken, flags);
+ typedFuture.complete(null);
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@@ -5887,24 +5915,39 @@
@BinderThread
@Override
- public void switchToPreviousInputMethod(IBooleanResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback, () -> mImms.switchToPreviousInputMethod(mToken));
+ public void switchToPreviousInputMethod(AndroidFuture future /* T=Boolean */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Boolean> typedFuture = future;
+ try {
+ typedFuture.complete(mImms.switchToPreviousInputMethod(mToken));
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@Override
public void switchToNextInputMethod(boolean onlyCurrentIme,
- IBooleanResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback,
- () -> mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
+ AndroidFuture future /* T=Boolean */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Boolean> typedFuture = future;
+ try {
+ typedFuture.complete(mImms.switchToNextInputMethod(mToken, onlyCurrentIme));
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
@Override
- public void shouldOfferSwitchingToNextInputMethod(
- IBooleanResultCallback resultCallback) {
- CallbackUtils.onResult(resultCallback,
- () -> mImms.shouldOfferSwitchingToNextInputMethod(mToken));
+ public void shouldOfferSwitchingToNextInputMethod(AndroidFuture future /* T=Boolean */) {
+ @SuppressWarnings("unchecked")
+ final AndroidFuture<Boolean> typedFuture = future;
+ try {
+ typedFuture.complete(mImms.shouldOfferSwitchingToNextInputMethod(mToken));
+ } catch (Throwable e) {
+ typedFuture.completeExceptionally(e);
+ }
}
@BinderThread
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubService.java b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
index 4d302b1..350a301 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubService.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubService.java
@@ -28,7 +28,6 @@
import android.hardware.SensorPrivacyManager;
import android.hardware.SensorPrivacyManagerInternal;
import android.hardware.contexthub.V1_0.AsyncEventType;
-import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.Result;
import android.hardware.contexthub.V1_0.TransactionResult;
@@ -200,7 +199,7 @@
return;
}
- Pair<List<ContextHub>, List<String>> hubInfo;
+ Pair<List<ContextHubInfo>, List<String>> hubInfo;
try {
hubInfo = mContextHubWrapper.getHubs();
} catch (RemoteException e) {
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
index 70f50c3..d0e00c4 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubServiceUtil.java
@@ -20,7 +20,6 @@
import android.Manifest;
import android.content.Context;
-import android.hardware.contexthub.V1_0.ContextHub;
import android.hardware.contexthub.V1_0.ContextHubMsg;
import android.hardware.contexthub.V1_0.HostEndPoint;
import android.hardware.contexthub.V1_0.Result;
@@ -52,10 +51,10 @@
* @return the HashMap object
*/
/* package */
- static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHub> hubList) {
+ static HashMap<Integer, ContextHubInfo> createContextHubInfoMap(List<ContextHubInfo> hubList) {
HashMap<Integer, ContextHubInfo> contextHubIdToInfoMap = new HashMap<>();
- for (ContextHub contextHub : hubList) {
- contextHubIdToInfoMap.put(contextHub.hubId, new ContextHubInfo(contextHub));
+ for (ContextHubInfo contextHubInfo : hubList) {
+ contextHubIdToInfoMap.put(contextHubInfo.getId(), contextHubInfo);
}
return contextHubIdToInfoMap;
diff --git a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
index 7be47a4..4b6d093 100644
--- a/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
+++ b/services/core/java/com/android/server/location/contexthub/IContextHubWrapper.java
@@ -20,6 +20,7 @@
import android.hardware.contexthub.V1_1.Setting;
import android.hardware.contexthub.V1_1.SettingValue;
import android.hardware.contexthub.V1_2.IContexthubCallback;
+import android.hardware.location.ContextHubInfo;
import android.os.RemoteException;
import android.util.Log;
import android.util.Pair;
@@ -95,7 +96,7 @@
/**
* Calls the appropriate getHubs function depending on the HAL version.
*/
- public abstract Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException;
+ public abstract Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException;
/**
* Calls the appropriate registerCallback function depending on the HAL version.
@@ -165,8 +166,12 @@
mHub = hub;
}
- public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
- return new Pair(mHub.getHubs(), new ArrayList<String>());
+ public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
+ ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+ for (ContextHub hub : mHub.getHubs()) {
+ hubInfoList.add(new ContextHubInfo(hub));
+ }
+ return new Pair(hubInfoList, new ArrayList<String>());
}
public void registerCallback(
@@ -214,8 +219,12 @@
mHub = hub;
}
- public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
- return new Pair(mHub.getHubs(), new ArrayList<String>());
+ public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
+ ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+ for (ContextHub hub : mHub.getHubs()) {
+ hubInfoList.add(new ContextHubInfo(hub));
+ }
+ return new Pair(hubInfoList, new ArrayList<String>());
}
public void registerCallback(
@@ -266,7 +275,7 @@
implements android.hardware.contexthub.V1_2.IContexthub.getHubs_1_2Callback {
private final android.hardware.contexthub.V1_2.IContexthub mHub;
- private Pair<List<ContextHub>, List<String>> mHubInfo =
+ private Pair<List<ContextHubInfo>, List<String>> mHubInfo =
new Pair<>(Collections.emptyList(), Collections.emptyList());
ContextHubWrapperV1_2(android.hardware.contexthub.V1_2.IContexthub hub) {
@@ -275,10 +284,14 @@
@Override
public void onValues(ArrayList<ContextHub> hubs, ArrayList<String> supportedPermissions) {
- mHubInfo = new Pair(hubs, supportedPermissions);
+ ArrayList<ContextHubInfo> hubInfoList = new ArrayList<>();
+ for (ContextHub hub : hubs) {
+ hubInfoList.add(new ContextHubInfo(hub));
+ }
+ mHubInfo = new Pair(hubInfoList, supportedPermissions);
}
- public Pair<List<ContextHub>, List<String>> getHubs() throws RemoteException {
+ public Pair<List<ContextHubInfo>, List<String>> getHubs() throws RemoteException {
mHub.getHubs_1_2(this);
return mHubInfo;
}
diff --git a/services/core/java/com/android/server/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 15e671c..f552606 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -1583,7 +1583,7 @@
dumpPackageSet(pw, filteringAppId, mForceQueryable, "forceQueryable", " ", expandPackages);
pw.println(" queries via package name:");
dumpQueriesMap(pw, filteringAppId, mQueriesViaPackage, " ", expandPackages);
- pw.println(" queries via intent:");
+ pw.println(" queries via component:");
dumpQueriesMap(pw, filteringAppId, mQueriesViaComponent, " ", expandPackages);
pw.println(" queryable via interaction:");
for (int user : users) {
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 958c769..08c95c2 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -144,6 +144,7 @@
import com.android.internal.os.SomeArgs;
import com.android.internal.security.VerityUtils;
import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.CollectionUtils;
import com.android.internal.util.FrameworkStatsLog;
import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
@@ -2983,6 +2984,8 @@
// Verify that all staged packages are internally consistent
final ArraySet<String> stagedSplits = new ArraySet<>();
+ final ArraySet<String> stagedSplitTypes = new ArraySet<>();
+ final ArraySet<String> requiredSplitTypes = new ArraySet<>();
final ArrayMap<String, ApkLite> splitApks = new ArrayMap<>();
final ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
for (File addedFile : addedFiles) {
@@ -3038,6 +3041,10 @@
} else {
splitApks.put(apk.getSplitName(), apk);
}
+
+ // Collect the requiredSplitTypes and staged splitTypes
+ CollectionUtils.addAll(requiredSplitTypes, apk.getRequiredSplitTypes());
+ CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes());
}
if (removeSplitList.size() > 0) {
@@ -3092,7 +3099,8 @@
throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
"Full install must include a base package");
}
- if (baseApk.isSplitRequired() && stagedSplits.size() <= 1) {
+ if (baseApk.isSplitRequired() && (stagedSplits.size() <= 1
+ || !stagedSplitTypes.containsAll(requiredSplitTypes))) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}
@@ -3130,6 +3138,8 @@
if (mResolvedBaseFile == null) {
mResolvedBaseFile = new File(appInfo.getBaseCodePath());
inheritFileLocked(mResolvedBaseFile);
+ // Collect the requiredSplitTypes from base
+ CollectionUtils.addAll(requiredSplitTypes, existing.getBaseRequiredSplitTypes());
}
// Inherit splits if not overridden.
@@ -3140,6 +3150,10 @@
final boolean splitRemoved = removeSplitList.contains(splitName);
if (!stagedSplits.contains(splitName) && !splitRemoved) {
inheritFileLocked(splitFile);
+ // Collect the requiredSplitTypes and staged splitTypes from splits
+ CollectionUtils.addAll(requiredSplitTypes,
+ existing.getRequiredSplitTypes()[i]);
+ CollectionUtils.addAll(stagedSplitTypes, existing.getSplitTypes()[i]);
}
}
}
@@ -3221,7 +3235,8 @@
final boolean allSplitsRemoved = (existingSplits == removeSplitList.size());
final boolean onlyBaseFileStaged = (stagedSplits.size() == 1
&& stagedSplits.contains(null));
- if (allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged)) {
+ if ((allSplitsRemoved && (stagedSplits.isEmpty() || onlyBaseFileStaged))
+ || !stagedSplitTypes.containsAll(requiredSplitTypes)) {
throw new PackageManagerException(INSTALL_FAILED_MISSING_SPLIT,
"Missing split for " + mPackageName);
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 4862021..e4f6398 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -581,8 +581,12 @@
apkLiteResult.getException());
}
final ApkLite apkLite = apkLiteResult.getResult();
- final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite, null,
- null, null, null, null, null, apkLite.getTargetSdkVersion());
+ final PackageLite pkgLite = new PackageLite(null, apkLite.getPath(), apkLite,
+ null /* splitNames */, null /* isFeatureSplits */,
+ null /* usesSplitNames */, null /* configForSplit */,
+ null /* splitApkPaths */, null /* splitRevisionCodes */,
+ apkLite.getTargetSdkVersion(), null /* requiredSplitTypes */,
+ null /* splitTypes */);
sessionSize += PackageHelper.calculateInstalledSize(pkgLite,
params.sessionParams.abiOverride, fd.getFileDescriptor());
} catch (IOException e) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 7220a23..3627ad1 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1201,10 +1201,10 @@
}
}
- WindowToken removeWindowToken(IBinder binder) {
+ WindowToken removeWindowToken(IBinder binder, boolean animateExit) {
final WindowToken token = mTokenMap.remove(binder);
if (token != null && token.asActivityRecord() == null) {
- token.setExiting();
+ token.setExiting(animateExit);
}
return token;
}
@@ -1282,7 +1282,7 @@
}
void removeAppToken(IBinder binder) {
- final WindowToken token = removeWindowToken(binder);
+ final WindowToken token = removeWindowToken(binder, true /* animateExit */);
if (token == null) {
Slog.w(TAG_WM, "removeAppToken: Attempted to remove non-existing token: " + binder);
return;
diff --git a/services/core/java/com/android/server/wm/WallpaperWindowToken.java b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
index 194f48f..b54e8b7 100644
--- a/services/core/java/com/android/server/wm/WallpaperWindowToken.java
+++ b/services/core/java/com/android/server/wm/WallpaperWindowToken.java
@@ -66,8 +66,8 @@
}
@Override
- void setExiting() {
- super.setExiting();
+ void setExiting(boolean animateExit) {
+ super.setExiting(animateExit);
mDisplayContent.mWallpaperController.removeWallpaperToken(this);
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 8a24209..b8e303b 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -461,8 +461,21 @@
* @param removeWindows Whether to also remove the windows associated with the token.
* @param displayId The display to remove the token from.
*/
+ public final void removeWindowToken(android.os.IBinder token, boolean removeWindows,
+ int displayId) {
+ removeWindowToken(token, removeWindows, true /* animateExit */, displayId);
+ }
+
+ /**
+ * Removes a window token.
+ *
+ * @param token The toke to remove.
+ * @param removeWindows Whether to also remove the windows associated with the token.
+ * @param animateExit Whether to play the windows exit animation after the token removal.
+ * @param displayId The display to remove the token from.
+ */
public abstract void removeWindowToken(android.os.IBinder token, boolean removeWindows,
- int displayId);
+ boolean animateExit, int displayId);
/**
* Registers a listener to be notified about app transition events.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index b1d1244..f24d74a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2811,6 +2811,31 @@
}
+ void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ synchronized (mGlobalLock) {
+ final DisplayContent dc = mRoot.getDisplayContent(displayId);
+
+ if (dc == null) {
+ ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
+ + " for non-exiting displayId=%d", binder, displayId);
+ return;
+ }
+ final WindowToken token = dc.removeWindowToken(binder, animateExit);
+ if (token == null) {
+ ProtoLog.w(WM_ERROR,
+ "removeWindowToken: Attempted to remove non-existing token: %s",
+ binder);
+ return;
+ }
+
+ if (removeWindows) {
+ token.removeAllWindowsIfPossible();
+ }
+ dc.getInputMonitor().updateInputWindowsLw(true /* force */);
+ }
+ }
+
@Override
public void removeWindowToken(IBinder binder, int displayId) {
if (!checkCallingPermission(MANAGE_APP_TOKENS, "removeWindowToken()")) {
@@ -2818,23 +2843,7 @@
}
final long origId = Binder.clearCallingIdentity();
try {
- synchronized (mGlobalLock) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
-
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
- dc.getInputMonitor().updateInputWindowsLw(true /*force*/);
- }
+ removeWindowToken(binder, false /* removeWindows */, true /* animateExit */, displayId);
} finally {
Binder.restoreCallingIdentity(origId);
}
@@ -7550,28 +7559,10 @@
}
@Override
- public void removeWindowToken(IBinder binder, boolean removeWindows, int displayId) {
- synchronized (mGlobalLock) {
- if (removeWindows) {
- final DisplayContent dc = mRoot.getDisplayContent(displayId);
- if (dc == null) {
- ProtoLog.w(WM_ERROR, "removeWindowToken: Attempted to remove token: %s"
- + " for non-exiting displayId=%d", binder, displayId);
- return;
- }
-
- final WindowToken token = dc.removeWindowToken(binder);
- if (token == null) {
- ProtoLog.w(WM_ERROR,
- "removeWindowToken: Attempted to remove non-existing token: %s",
- binder);
- return;
- }
-
- token.removeAllWindowsIfPossible();
- }
- WindowManagerService.this.removeWindowToken(binder, displayId);
- }
+ public void removeWindowToken(IBinder binder, boolean removeWindows, boolean animateExit,
+ int displayId) {
+ WindowManagerService.this.removeWindowToken(binder, removeWindows, animateExit,
+ displayId);
}
@Override
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1ca0c7e..74a030a 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2220,11 +2220,18 @@
}
}
- boolean onSetAppExiting() {
+ boolean onSetAppExiting(boolean animateExit) {
final DisplayContent displayContent = getDisplayContent();
boolean changed = false;
- if (isVisibleNow()) {
+ if (!animateExit) {
+ // Hide the window permanently if no window exist animation is performed, so we can
+ // avoid the window surface becoming visible again unexpectedly during the next
+ // relayout.
+ mPermanentlyHidden = true;
+ hide(false /* doAnimation */, false /* requestAnim */);
+ }
+ if (isVisibleNow() && animateExit) {
mWinAnimator.applyAnimationLocked(TRANSIT_EXIT, false);
if (mWmService.mAccessibilityController != null) {
mWmService.mAccessibilityController.onWindowTransition(this, TRANSIT_EXIT);
@@ -2237,7 +2244,7 @@
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowState c = mChildren.get(i);
- changed |= c.onSetAppExiting();
+ changed |= c.onSetAppExiting(animateExit);
}
return changed;
diff --git a/services/core/java/com/android/server/wm/WindowToken.java b/services/core/java/com/android/server/wm/WindowToken.java
index fa32be3..ad351f0 100644
--- a/services/core/java/com/android/server/wm/WindowToken.java
+++ b/services/core/java/com/android/server/wm/WindowToken.java
@@ -26,6 +26,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_APP_TRANSITIONS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_WINDOW_ANIMATION;
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;
@@ -239,7 +240,7 @@
}
}
- void setExiting() {
+ void setExiting(boolean animateExit) {
if (isEmpty()) {
super.removeImmediately();
return;
@@ -254,11 +255,12 @@
final int count = mChildren.size();
boolean changed = false;
- final boolean delayed = isAnimating(TRANSITION | PARENTS | CHILDREN);
+ final boolean delayed = isAnimating(TRANSITION | PARENTS)
+ || (isAnimating(CHILDREN, ANIMATION_TYPE_WINDOW_ANIMATION) && animateExit);
for (int i = 0; i < count; i++) {
final WindowState win = mChildren.get(i);
- changed |= win.onSetAppExiting();
+ changed |= win.onSetAppExiting(animateExit);
}
final ActivityRecord app = asActivityRecord();
@@ -360,7 +362,7 @@
@Override
void removeImmediately() {
if (mDisplayContent != null) {
- mDisplayContent.removeWindowToken(token);
+ mDisplayContent.removeWindowToken(token, true /* animateExit */);
}
// Needs to occur after the token is removed from the display above to avoid attempt at
// duplicate removal of this window container from it's parent.
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
index 16f72f7..e021d2a 100644
--- a/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexMetadataHelperTest.java
@@ -416,8 +416,11 @@
result.getErrorMessage(), result.getException());
}
final ApkLite baseApk = result.getResult();
- final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk, null,
- null, null, null, null, null, baseApk.getTargetSdkVersion());
+ final PackageLite pkgLite = new PackageLite(null, baseApk.getPath(), baseApk,
+ null /* splitNames */, null /* isFeatureSplits */, null /* usesSplitNames */,
+ null /* configForSplit */, null /* splitApkPaths */,
+ null /* splitRevisionCodes */, baseApk.getTargetSdkVersion(),
+ null /* requiredSplitTypes */, null /* splitTypes */);
Assert.assertEquals(dm.length(), DexMetadataHelper.getPackageDexMetadataSize(pkgLite));
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
index d048f1842..589f913 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTokenTests.java
@@ -24,6 +24,7 @@
import static android.view.WindowManager.LayoutParams.TYPE_TOAST;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.policy.WindowManagerPolicy.TRANSIT_EXIT;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -44,6 +45,7 @@
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mockito;
import java.util.function.BiFunction;
@@ -126,7 +128,7 @@
final WindowState window1 = createWindow(null, TYPE_TOAST, token, "window1");
final WindowState window2 = createWindow(null, TYPE_TOAST, token, "window2");
- mDisplayContent.removeWindowToken(token.token);
+ mDisplayContent.removeWindowToken(token.token, true /* animateExit */);
// Verify that the token is no longer mapped on the display
assertNull(mDisplayContent.getWindowToken(token.token));
// Verify that the token is still attached to its parent
@@ -261,4 +263,29 @@
assertNotNull(app.getFrozenInsetsState());
assertNull(mDisplayContent.mInputMethodWindow.getFrozenInsetsState());
}
+
+ @Test
+ public void testRemoveWindowToken_noAnimateExitWhenSet() {
+ final TestWindowToken token = createTestWindowToken(0, mDisplayContent);
+ final WindowState win = createWindow(null, TYPE_APPLICATION, token, "win");
+ makeWindowVisible(win);
+ assertTrue(win.isOnScreen());
+ spyOn(win);
+ spyOn(win.mWinAnimator);
+ spyOn(win.mToken);
+
+ // Invoking removeWindowToken with setting no window exit animation and not remove window
+ // immediately. verify the window will hide without applying exit animation.
+ mWm.removeWindowToken(win.mToken.token, false /* removeWindows */, false /* animateExit */,
+ mDisplayContent.mDisplayId);
+ verify(win).onSetAppExiting(Mockito.eq(false) /* animateExit */);
+ verify(win).hide(false /* doAnimation */, false /* requestAnim */);
+ assertFalse(win.isOnScreen());
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ assertTrue(win.mToken.hasChild());
+
+ // Even though the window is being removed afterwards, it won't apply exit animation.
+ win.removeIfPossible();
+ verify(win.mWinAnimator, Mockito.never()).applyAnimationLocked(TRANSIT_EXIT, false);
+ }
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
index e6dc852..be919cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppColdTest.kt
@@ -16,6 +16,8 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -33,8 +35,21 @@
import org.junit.runners.Parameterized
/**
- * Test cold launch app from launcher.
+ * Test cold launching an app from launcher
+ *
* To run this test: `atest FlickerTests:OpenAppColdTest`
+ *
+ * Actions:
+ * Make sure no apps are running on the device
+ * Launch an app [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -42,6 +57,9 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
class OpenAppColdTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
super.transition(this, it)
@@ -62,25 +80,46 @@
}
}
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
}
- @FlakyTest(bugId = 192721431)
+ /** {@inheritDoc} */
+ @Postsubmit
@Test
- override fun appLayerReplacesLauncher() {
- super.appLayerReplacesLauncher()
- }
+ override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
- @FlakyTest(bugId = 192721431)
+ /** {@inheritDoc} */
+ @Postsubmit
@Test
- override fun appWindowReplacesLauncherAsTopWindow() {
+ override fun appWindowReplacesLauncherAsTopWindow() =
super.appWindowReplacesLauncherAsTopWindow()
- }
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
index 7833e2f..3678f33 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppFromOverviewTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -33,8 +34,23 @@
import org.junit.runners.Parameterized
/**
- * Launch an app from the recents app view (the overview)
+ * Test launching an app from the recents app view (the overview)
+ *
* To run this test: `atest FlickerTests:OpenAppFromOverviewTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press recents
+ * Relaunch an app [testApp] by selecting it in the overview screen, and wait animation to
+ * complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -42,6 +58,9 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
class OpenAppFromOverviewTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
super.transition(this, it)
@@ -63,13 +82,38 @@
}
}
+ /** {@inheritDoc} */
@FlakyTest
@Test
- override fun navBarLayerRotatesAndScales() {
- super.navBarLayerRotatesAndScales()
- }
+ override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
index 93a58be..b717612 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.content.ComponentName
import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
@@ -29,6 +30,7 @@
import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+import com.google.common.truth.Truth
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -36,8 +38,21 @@
import org.junit.runners.Parameterized
/**
- * Launch an app while the phone is locked
+ * Test launching an app while the device is locked
+ *
* To run this test: `atest FlickerTests:OpenAppNonResizeableTest`
+ *
+ * Actions:
+ * Lock the device.
+ * Launch an app on top of the lock screen [testApp] and wait animation to complete
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -46,14 +61,20 @@
@Group1
class OpenAppNonResizeableTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
override val testApp = NonResizeableAppHelper(instrumentation)
+ private val colorFadComponent = ComponentName("", "ColorFade BLAST#")
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = {
- super.transition(this, it)
+ get() = { args ->
+ super.transition(this, args)
setup {
eachRun {
device.sleep()
- wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitFor("noAppWindowsOnTop") {
+ it.wmState.topVisibleAppWindow.isEmpty()
+ }
}
}
teardown {
@@ -67,17 +88,29 @@
}
}
+ /**
+ * Checks that the nav bar layer starts visible, becomes invisible during unlocking animation
+ * and becomes visible at the end
+ */
@Presubmit
@Test
- override fun navBarLayerIsVisible() {
- testSpec.assertLayersEnd {
- isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ fun navBarLayerVisibilityChanges() {
+ testSpec.assertLayers {
+ this.isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ .then()
+ .isInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ .then()
+ .isVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
}
}
+ /**
+ * Checks that the app layer doesn't exist at the start of the transition, that it is
+ * created (invisible) and becomes visible during the transition
+ */
@Presubmit
@Test
- fun nonResizableAppLayerBecomesVisible() {
+ fun appLayerBecomesVisible() {
testSpec.assertLayers {
this.notContains(testApp.component)
.then()
@@ -87,9 +120,16 @@
}
}
+ /**
+ * Checks that the app window doesn't exist at the start of the transition, that it is
+ * created (invisible - optional) and becomes visible during the transition
+ *
+ * The `isAppWindowInvisible` step is optional because we log once per frame, upon logging,
+ * the window may be visible or not depending on what was processed until that moment.
+ */
@Presubmit
@Test
- fun nonResizableAppWindowBecomesVisible() {
+ fun appWindowBecomesVisible() {
testSpec.assertWm {
this.notContains(testApp.component)
.then()
@@ -100,46 +140,95 @@
}
}
+ /**
+ * Checks if [testApp] is visible at the end of the transition
+ */
@Presubmit
@Test
- fun nonResizableAppWindowBecomesVisibleAtEnd() {
+ fun appWindowBecomesVisibleAtEnd() {
testSpec.assertWmEnd {
this.isVisible(testApp.component)
}
}
- @FlakyTest
+ /**
+ * Checks that the nav bar starts the transition visible, then becomes invisible during
+ * then unlocking animation and becomes visible at the end of the transition
+ */
+ @Postsubmit
@Test
- override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+ fun navBarWindowsVisibilityChanges() {
+ testSpec.assertWm {
+ this.isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ .then()
+ .isNonAppWindowInvisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ .then()
+ .isAboveAppWindowVisible(WindowManagerStateHelper.NAV_BAR_COMPONENT)
+ }
+ }
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
+ /** {@inheritDoc} */
@Postsubmit
@Test
override fun entireScreenCovered() = super.entireScreenCovered()
+ /**
+ * Checks that the focus changes from the launcher to [testApp]
+ */
@FlakyTest
@Test
override fun focusChanges() = super.focusChanges()
- @FlakyTest
+ /**
+ * Checks that the screen is locked at the start of the transition ([colorFadComponent])
+ * layer is visible
+ */
+ @Postsubmit
@Test
- override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+ fun screenLockedStart() {
+ testSpec.assertLayersStart {
+ isVisible(colorFadComponent)
+ }
+ }
- @FlakyTest
+ /**
+ * This test checks if the launcher is visible at the start and the app at the end,
+ * it cannot use the regular assertion (check over time), because on lock screen neither
+ * the app not the launcher are visible, and there is no top visible window.
+ */
+ @Postsubmit
@Test
- override fun appWindowReplacesLauncherAsTopWindow() =
- super.appWindowReplacesLauncherAsTopWindow()
+ override fun appWindowReplacesLauncherAsTopWindow() {
+ testSpec.assertWm {
+ this.invoke("noAppWindowsOnTop") {
+ Truth.assertWithMessage("Should not have any app window on top " +
+ "when the screen is locked")
+ .that(it.wmState.topVisibleAppWindow)
+ .isEmpty()
+ }.then()
+ .isAppWindowOnTop(testApp.component)
+ }
+ }
companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
index 434b244..14d17f8 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppTransition.kt
@@ -40,12 +40,16 @@
import com.android.server.wm.flicker.statusBarLayerRotatesScales
import com.android.server.wm.flicker.statusBarWindowIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SPLASH_SCREEN_COMPONENT
import org.junit.Test
abstract class OpenAppTransition(protected val testSpec: FlickerTestParameter) {
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
protected open val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ /**
+ * Defines the transition used to run the test
+ */
protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
withTestName { testSpec.name }
repeat { testSpec.config.repetitions }
@@ -62,6 +66,10 @@
}
}
+ /**
+ * Entry point for the test runner. It will use this method to initialize and cache
+ * flicker executions
+ */
@FlickerBuilderProvider
fun buildFlicker(): FlickerBuilder {
return FlickerBuilder(instrumentation).apply {
@@ -69,42 +77,60 @@
}
}
- @Presubmit
- @Test
+ /**
+ * Checks that the navigation bar window is visible during the whole transition
+ */
open fun navBarWindowIsVisible() {
testSpec.navBarWindowIsVisible()
}
- @Presubmit
- @Test
+ /**
+ * Checks that the navigation bar layer is visible during the whole transition
+ */
open fun navBarLayerIsVisible() {
testSpec.navBarLayerIsVisible()
}
+ /**
+ * Checks the position of the navigation bar at the start and end of the transition
+ */
@Presubmit
@Test
open fun navBarLayerRotatesAndScales() {
testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_0, testSpec.config.endRotation)
}
+ /**
+ * Checks that the status bar window is visible during the whole transition
+ */
@Presubmit
@Test
open fun statusBarWindowIsVisible() {
testSpec.statusBarWindowIsVisible()
}
+ /**
+ * Checks that the status bar layer is visible during the whole transition
+ */
@Presubmit
@Test
open fun statusBarLayerIsVisible() {
testSpec.statusBarLayerIsVisible()
}
+ /**
+ * Checks the position of the status bar at the start and end of the transition
+ */
@Presubmit
@Test
open fun statusBarLayerRotatesScales() {
testSpec.statusBarLayerRotatesScales(Surface.ROTATION_0, testSpec.config.endRotation)
}
+ /**
+ * Checks that all windows that are visible on the trace, are visible for at least 2
+ * consecutive entries.
+ */
@Presubmit
@Test
open fun visibleWindowsShownMoreThanOneConsecutiveEntry() {
@@ -113,6 +139,10 @@
}
}
+ /**
+ * Checks that all layers that are visible on the trace, are visible for at least 2
+ * consecutive entries.
+ */
@Presubmit
@Test
open fun visibleLayersShownMoreThanOneConsecutiveEntry() {
@@ -121,11 +151,16 @@
}
}
+ /**
+ * Checks that all parts of the screen are covered during the transition
+ */
@Presubmit
@Test
- // During testing the launcher is always in portrait mode
open fun entireScreenCovered() = testSpec.entireScreenCovered()
+ /**
+ * Checks that the focus changes from the launcher to [testApp]
+ */
@Presubmit
@Test
open fun focusChanges() {
@@ -134,12 +169,19 @@
}
}
- @Presubmit
- @Test
+ /**
+ * Checks that [LAUNCHER_COMPONENT] layer is visible at the start of the transition, and
+ * is replaced by [testApp], which remains visible until the end
+ */
open fun appLayerReplacesLauncher() {
testSpec.replacesLayer(LAUNCHER_COMPONENT, testApp.component)
}
+ /**
+ * Checks that [LAUNCHER_COMPONENT] window is visible at the start of the transition, and
+ * is replaced by a snapshot or splash screen (optional), and finally, is replaced by
+ * [testApp], which remains visible until the end
+ */
@Presubmit
@Test
open fun appWindowReplacesLauncherAsTopWindow() {
@@ -148,12 +190,16 @@
.then()
.isAppWindowOnTop(SNAPSHOT_COMPONENT, isOptional = true)
.then()
+ .isAppWindowOnTop(SPLASH_SCREEN_COMPONENT, isOptional = true)
+ .then()
.isAppWindowOnTop(testApp.component)
}
}
- @Presubmit
- @Test
+ /**
+ * Checks that [LAUNCHER_COMPONENT] window is visible at the start, and
+ * becomes invisible during the transition
+ */
open fun launcherWindowBecomesInvisible() {
testSpec.assertWm {
this.isAppWindowVisible(LAUNCHER_COMPONENT)
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
index b509c61..5edee0c 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppWarmTest.kt
@@ -16,6 +16,7 @@
package com.android.server.wm.flicker.launch
+import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
import com.android.server.wm.flicker.FlickerParametersRunnerFactory
@@ -32,8 +33,22 @@
import org.junit.runners.Parameterized
/**
- * Test warm launch app.
+ * Test warm launching an app from launcher
+ *
* To run this test: `atest FlickerTests:OpenAppWarmTest`
+ *
+ * Actions:
+ * Launch [testApp]
+ * Press home
+ * Relaunch an app [testApp] and wait animation to complete (only this action is traced)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [OpenAppTransition]
+ * 2. Part of the test setup occurs automatically via
+ * [com.android.server.wm.flicker.TransitionRunnerWithRules],
+ * including configuring navigation mode, initial orientation and ensuring no
+ * apps are running before setup
*/
@RequiresDevice
@RunWith(Parameterized::class)
@@ -41,6 +56,9 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group1
class OpenAppWarmTest(testSpec: FlickerTestParameter) : OpenAppTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = {
super.transition(this, it)
@@ -65,11 +83,38 @@
}
}
+ /** {@inheritDoc} */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun appLayerReplacesLauncher() = super.appLayerReplacesLauncher()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun launcherWindowBecomesInvisible() = super.launcherWindowBecomesInvisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarLayerIsVisible() = super.navBarLayerIsVisible()
+
+ /** {@inheritDoc} */
+ @Presubmit
+ @Test
+ override fun navBarWindowIsVisible() = super.navBarWindowIsVisible()
+
companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): Collection<FlickerTestParameter> {
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
new file mode 100644
index 0000000..035aac1
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchBetweenTwoAppsBackTest.kt
@@ -0,0 +1,331 @@
+/*
+ * Copyright (C) 2021 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.flicker.quickswitch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.RequiresDevice
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.FlickerBuilderProvider
+import com.android.server.wm.flicker.FlickerParametersRunnerFactory
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.FlickerTestParameterFactory
+import com.android.server.wm.flicker.LAUNCHER_COMPONENT
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.helpers.isRotated
+import com.android.server.wm.flicker.navBarLayerIsVisible
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.navBarWindowIsVisible
+import com.android.server.wm.flicker.startRotation
+import com.android.server.wm.flicker.statusBarLayerIsVisible
+import com.android.server.wm.flicker.statusBarWindowIsVisible
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper.Companion.SNAPSHOT_COMPONENT
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test quick switching back to previous app from last opened app
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchBetweenTwoAppsBackTest`
+ *
+ * Actions:
+ * Launch an app [testApp1]
+ * Launch another app [testApp2]
+ * Swipe right from the bottom of the screen to quick switch back to the first app [testApp1]
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class QuickSwitchBetweenTwoAppsBackTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+
+ private val testApp1 = SimpleAppHelper(instrumentation)
+ private val testApp2 = NonResizeableAppHelper(instrumentation)
+
+ private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp1.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp1.component)
+
+ testApp2.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp2.component)
+ }
+ }
+ transitions {
+ // Swipe right from bottom to quick switch back
+ // NOTE: We don't perform an edge-to-edge swipe but instead only swipe in the middle
+ // as to not accidentally trigger a swipe back or forward action which would result
+ // in the same behavior but not testing quick swap.
+ device.swipe(
+ startDisplayBounds.bounds.right / 3,
+ startDisplayBounds.bounds.bottom,
+ 2 * startDisplayBounds.bounds.right / 3,
+ startDisplayBounds.bounds.bottom,
+ if (testSpec.config.startRotation.isRotated()) 75 else 30
+ )
+
+ wmHelper.waitForFullScreenApp(testApp1.component)
+ wmHelper.waitForAppTransitionIdle()
+ }
+
+ teardown {
+ test {
+ testApp1.exit()
+ testApp2.exit()
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks that the transition starts with [testApp2]'s windows filling/covering exactly the
+ * entirety of the display.
+ */
+ @Postsubmit
+ @Test
+ fun startsWithApp2WindowsCoverFullScreen() {
+ testSpec.assertWmStart {
+ this.frameRegion(testApp2.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with [testApp2]'s layers filling/covering exactly the
+ * entirety of the display.
+ */
+ @Postsubmit
+ @Test
+ fun startsWithApp2LayersCoverFullScreen() {
+ testSpec.assertLayersStart {
+ this.visibleRegion(testApp2.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with [testApp2] being the top window.
+ */
+ @Postsubmit
+ @Test
+ fun startsWithApp2WindowBeingOnTop() {
+ testSpec.assertWmStart {
+ this.isAppWindowOnTop(testApp2.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp1] windows fill the entire screen (i.e. is "fullscreen") at the end of the
+ * transition once we have fully quick switched from [testApp2] back to the [testApp1].
+ */
+ @Postsubmit
+ @Test
+ fun endsWithApp1WindowsCoveringFullScreen() {
+ testSpec.assertWmEnd {
+ this.frameRegion(testApp1.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that [testApp1] layers fill the entire screen (i.e. is "fullscreen") at the end of the
+ * transition once we have fully quick switched from [testApp2] back to the [testApp1].
+ */
+ @Postsubmit
+ @Test
+ fun endsWithApp1LayersCoveringFullScreen() {
+ testSpec.assertLayersEnd {
+ this.visibleRegion(testApp1.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that [testApp1] is the top window at the end of the transition once we have fully quick
+ * switched from [testApp2] back to the [testApp1].
+ */
+ @Postsubmit
+ @Test
+ fun endsWithApp1BeingOnTop() {
+ testSpec.assertWmEnd {
+ this.isAppWindowOnTop(testApp1.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp1]'s window starts off invisible and becomes visible at some point before
+ * the end of the transition and then stays visible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun app1WindowBecomesAndStaysVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(testApp1.component)
+ .then()
+ .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+ .then()
+ .isAppWindowVisible(testApp1.component, ignoreActivity = true)
+ }
+ }
+
+ /**
+ * Checks that [testApp1]'s layer starts off invisible and becomes visible at some point before
+ * the end of the transition and then stays visible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun app1LayerBecomesAndStaysVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(testApp1.component)
+ .then()
+ .isVisible(testApp1.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp2]'s window starts off visible and becomes invisible at some point before
+ * the end of the transition and then stays invisible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun app2WindowBecomesAndStaysInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(testApp2.component, ignoreActivity = true)
+ .then()
+ .isAppWindowInvisible(testApp2.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp2]'s layer starts off visible and becomes invisible at some point before
+ * the end of the transition and then stays invisible until the end of the transition.
+ */
+ @Postsubmit
+ @Test
+ fun app2LayerBecomesAndStaysInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp2.component)
+ .then()
+ .isInvisible(testApp2.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp2]'s window is visible at least until [testApp1]'s window is visible.
+ * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
+ * visible.
+ */
+ @Postsubmit
+ @Test
+ fun app1WindowIsVisibleOnceApp2WindowIsInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(testApp2.component)
+ .then()
+ // TODO: Do we actually want to test this? Seems too implementation specific...
+ .isAppWindowVisible(LAUNCHER_COMPONENT, isOptional = true)
+ .then()
+ .isAppWindowVisible(SNAPSHOT_COMPONENT, isOptional = true)
+ .then()
+ .isAppWindowVisible(testApp1.component)
+ }
+ }
+
+ /**
+ * Checks that [testApp2]'s layer is visible at least until [testApp1]'s window is visible.
+ * Ensures that at any point, either [testApp1] or [testApp2]'s windows are at least partially
+ * visible.
+ */
+ @Postsubmit
+ @Test
+ fun app1LayerIsVisibleOnceApp2LayerIsInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(testApp2.component)
+ .then()
+ .isVisible(LAUNCHER_COMPONENT, isOptional = true)
+ .then()
+ .isVisible(SNAPSHOT_COMPONENT, isOptional = true)
+ .then()
+ .isVisible(testApp1.component)
+ }
+ }
+
+ /**
+ * Checks that the navbar window is visible throughout the entire transition.
+ */
+ @Postsubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
+
+ /**
+ * Checks that the navbar layer is visible throughout the entire transition.
+ */
+ @Postsubmit
+ @Test
+ fun navBarLayerAlwaysIsVisible() = testSpec.navBarLayerIsVisible()
+
+ /**
+ * Checks that the navbar is always in the right position and covers the expected region.
+ *
+ * NOTE: This doesn't check that the navbar is visible or not.
+ */
+ @Postsubmit
+ @Test
+ fun navbarIsAlwaysInRightPosition() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+ /**
+ * Checks that the status bar window is visible throughout the entire transition.
+ */
+ @Postsubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
+
+ /**
+ * Checks that the status bar layer is visible throughout the entire transition.
+ */
+ @Postsubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedNavigationModes = listOf(
+ WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY
+ ),
+ supportedRotations = listOf(Surface.ROTATION_0, Surface.ROTATION_90)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index 1bb0696..63b2fcd 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -163,6 +163,31 @@
return true;
}
+static bool AutoGenerateIsSplitRequired(xml::Element* el, SourcePathDiagnostics* diag) {
+ constexpr const char* kRequiredSplitTypes = "requiredSplitTypes";
+ constexpr const char* kIsSplitRequired = "isSplitRequired";
+
+ xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kRequiredSplitTypes);
+ if (attr != nullptr) {
+ // Now inject the android:isSplitRequired="true" attribute.
+ xml::Attribute* attr = el->FindAttribute(xml::kSchemaAndroid, kIsSplitRequired);
+ if (attr != nullptr) {
+ if (!ResourceUtils::ParseBool(attr->value).value_or(false)) {
+ // The isFeatureSplit attribute is false, which conflicts with the use
+ // of "featureSplit".
+ diag->Error(DiagMessage(el->line_number)
+ << "attribute 'requiredSplitTypes' used in <manifest> but "
+ "'android:isSplitRequired' is not 'true'");
+ return false;
+ }
+ // The attribute is already there and set to true, nothing to do.
+ } else {
+ el->attributes.push_back(xml::Attribute{xml::kSchemaAndroid, kIsSplitRequired, "true"});
+ }
+ }
+ return true;
+}
+
static bool VerifyManifest(xml::Element* el, xml::XmlActionExecutorPolicy policy,
SourcePathDiagnostics* diag) {
xml::Attribute* attr = el->FindAttribute({}, "package");
@@ -329,6 +354,7 @@
// Manifest actions.
xml::XmlNodeAction& manifest_action = (*executor)["manifest"];
manifest_action.Action(AutoGenerateIsFeatureSplit);
+ manifest_action.Action(AutoGenerateIsSplitRequired);
manifest_action.Action(VerifyManifest);
manifest_action.Action(FixCoreAppAttribute);
manifest_action.Action([&](xml::Element* el) -> bool {