Merge "[RESTRICT AUTOMERGE][CarTelemetryService] Add permission to kitchen sink for CarServiceTest" into sc-v2-dev
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
index d493a1c..272e12d 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/AppSearchBatchResult.java
@@ -96,6 +96,17 @@
return Collections.unmodifiableMap(mAll);
}
+ /**
+ * Asserts that this {@link AppSearchBatchResult} has no failures.
+ *
+ * @hide
+ */
+ public void checkSuccess() {
+ if (!isSuccess()) {
+ throw new IllegalStateException("AppSearchBatchResult has failures: " + this);
+ }
+ }
+
@Override
@NonNull
public String toString() {
diff --git a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
index 10e014b..d6d5315 100644
--- a/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
+++ b/apex/appsearch/framework/java/external/android/app/appsearch/util/SchemaMigrationUtil.java
@@ -71,7 +71,7 @@
/**
* Checks the setSchema() call won't delete any types or has incompatible types after all {@link
- * Migrator} has been triggered..
+ * Migrator} has been triggered.
*/
public static void checkDeletedAndIncompatibleAfterMigration(
@NonNull SetSchemaResponse setSchemaResponse, @NonNull Set<String> activeMigrators)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
index c33d5ec..d4e3239 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/AppSearchManagerService.java
@@ -363,6 +363,7 @@
schemasVisibleToPackages.put(entry.getKey(), packageIdentifiers);
}
instance = mAppSearchUserInstanceManager.getUserInstance(targetUser);
+ // TODO(b/173532925): Implement logging for statsBuilder
SetSchemaResponse setSchemaResponse = instance.getAppSearchImpl().setSchema(
packageName,
databaseName,
@@ -371,7 +372,8 @@
schemasNotDisplayedBySystem,
schemasVisibleToPackages,
forceOverride,
- schemaVersion);
+ schemaVersion,
+ /*setSchemaStatsBuilder=*/ null);
++operationSuccessCount;
invokeCallbackOnResult(callback,
AppSearchResult.newSuccessfulResult(setSchemaResponse.getBundle()));
@@ -816,8 +818,10 @@
AppSearchUserInstance instance =
mAppSearchUserInstanceManager.getUserInstance(targetUser);
+ // TODO(b/173532925): Implement logging for statsBuilder
SearchResultPage searchResultPage =
- instance.getAppSearchImpl().getNextPage(packageName, nextPageToken);
+ instance.getAppSearchImpl().getNextPage(
+ packageName, nextPageToken, /*statsBuilder=*/ null);
invokeCallbackOnResult(
callback,
AppSearchResult.newSuccessfulResult(searchResultPage.getBundle()));
@@ -898,8 +902,11 @@
outputStream, searchResultPage.getResults().get(i)
.getGenericDocument().getBundle());
}
+ // TODO(b/173532925): Implement logging for statsBuilder
searchResultPage = instance.getAppSearchImpl().getNextPage(
- packageName, searchResultPage.getNextPageToken());
+ packageName,
+ searchResultPage.getNextPageToken(),
+ /*statsBuilder=*/ null);
}
}
invokeCallbackOnResult(callback, AppSearchResult.newSuccessfulResult(null));
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
index 15916cc..324163f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchImpl.java
@@ -59,6 +59,7 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
import com.android.server.appsearch.external.localstorage.visibilitystore.VisibilityStore;
import com.google.android.icing.IcingSearchEngine;
@@ -393,6 +394,7 @@
* @param forceOverride Whether to force-apply the schema even if it is incompatible. Documents
* which do not comply with the new schema will be deleted.
* @param version The overall version number of the request.
+ * @param setSchemaStatsBuilder Builder for {@link SetSchemaStats} to hold stats for setSchema
* @return The response contains deleted schema types and incompatible schema types of this
* call.
* @throws AppSearchException On IcingSearchEngine error. If the status code is
@@ -408,7 +410,8 @@
@NonNull List<String> schemasNotDisplayedBySystem,
@NonNull Map<String, List<PackageIdentifier>> schemasVisibleToPackages,
boolean forceOverride,
- int version)
+ int version,
+ @Nullable SetSchemaStats.Builder setSchemaStatsBuilder)
throws AppSearchException {
mReadWriteLock.writeLock().lock();
try {
@@ -438,6 +441,12 @@
mLogUtil.piiTrace(
"setSchema, response", setSchemaResultProto.getStatus(), setSchemaResultProto);
+ if (setSchemaStatsBuilder != null) {
+ setSchemaStatsBuilder.setStatusCode(
+ statusProtoToResultCode(setSchemaResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, setSchemaStatsBuilder);
+ }
+
// Determine whether it succeeded.
try {
checkSuccess(setSchemaResultProto.getStatus());
@@ -1127,8 +1136,13 @@
* @throws AppSearchException on IcingSearchEngine error or if can't advance on nextPageToken.
*/
@NonNull
- public SearchResultPage getNextPage(@NonNull String packageName, long nextPageToken)
+ public SearchResultPage getNextPage(
+ @NonNull String packageName,
+ long nextPageToken,
+ @Nullable SearchStats.Builder statsBuilder)
throws AppSearchException {
+ long totalLatencyStartMillis = SystemClock.elapsedRealtime();
+
mReadWriteLock.readLock().lock();
try {
throwIfClosedLocked();
@@ -1137,6 +1151,13 @@
checkNextPageToken(packageName, nextPageToken);
SearchResultProto searchResultProto =
mIcingSearchEngineLocked.getNextPage(nextPageToken);
+
+ if (statsBuilder != null) {
+ statsBuilder.setStatusCode(statusProtoToResultCode(searchResultProto.getStatus()));
+ AppSearchLoggerHelper.copyNativeStats(
+ searchResultProto.getQueryStats(), statsBuilder);
+ }
+
mLogUtil.piiTrace(
"getNextPage, response",
searchResultProto.getResultsCount(),
@@ -1152,9 +1173,22 @@
mNextPageTokensLocked.get(packageName).remove(nextPageToken);
}
}
- return rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
+ long rewriteSearchResultLatencyStartMillis = SystemClock.elapsedRealtime();
+ SearchResultPage resultPage =
+ rewriteSearchResultProto(searchResultProto, mSchemaMapLocked);
+ if (statsBuilder != null) {
+ statsBuilder.setRewriteSearchResultLatencyMillis(
+ (int)
+ (SystemClock.elapsedRealtime()
+ - rewriteSearchResultLatencyStartMillis));
+ }
+ return resultPage;
} finally {
mReadWriteLock.readLock().unlock();
+ if (statsBuilder != null) {
+ statsBuilder.setTotalLatencyMillis(
+ (int) (SystemClock.elapsedRealtime() - totalLatencyStartMillis));
+ }
}
}
@@ -1334,7 +1368,7 @@
statusProtoToResultCode(deleteResultProto.getStatus()));
// TODO(b/187206766) also log query stats here once IcingLib returns it
AppSearchLoggerHelper.copyNativeStats(
- deleteResultProto.getDeleteStats(), removeStatsBuilder);
+ deleteResultProto.getDeleteByQueryStats(), removeStatsBuilder);
}
// It seems that the caller wants to get success if the data matching the query is
@@ -1343,7 +1377,8 @@
deleteResultProto.getStatus(), StatusProto.Code.OK, StatusProto.Code.NOT_FOUND);
// Update derived maps
- int numDocumentsDeleted = deleteResultProto.getDeleteStats().getNumDocumentsDeleted();
+ int numDocumentsDeleted =
+ deleteResultProto.getDeleteByQueryStats().getNumDocumentsDeleted();
updateDocumentCountAfterRemovalLocked(packageName, numDocumentsDeleted);
} finally {
mReadWriteLock.writeLock().unlock();
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
index 98cedc7..1f7d44e 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLogger.java
@@ -24,6 +24,7 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
/**
* An interface for implementing client-defined logging AppSearch operations stats.
@@ -54,5 +55,8 @@
/** Logs {@link OptimizeStats} */
void logStats(@NonNull OptimizeStats stats);
+ /** Logs {@link SetSchemaStats} */
+ void logStats(@NonNull SetSchemaStats stats);
+
// TODO(b/173532925) Add remaining logStats once we add all the stats.
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
index cd653e5..c19ba14 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/AppSearchLoggerHelper.java
@@ -23,12 +23,15 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
+import com.google.android.icing.proto.DeleteByQueryStatsProto;
import com.google.android.icing.proto.DeleteStatsProto;
import com.google.android.icing.proto.InitializeStatsProto;
import com.google.android.icing.proto.OptimizeStatsProto;
import com.google.android.icing.proto.PutDocumentStatsProto;
import com.google.android.icing.proto.QueryStatsProto;
+import com.google.android.icing.proto.SetSchemaResultProto;
import java.util.Objects;
@@ -142,6 +145,26 @@
}
/**
+ * Copies native DeleteByQuery stats to builder.
+ *
+ * @param fromNativeStats Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(
+ @NonNull DeleteByQueryStatsProto fromNativeStats,
+ @NonNull RemoveStats.Builder toStatsBuilder) {
+ Objects.requireNonNull(fromNativeStats);
+ Objects.requireNonNull(toStatsBuilder);
+
+ @SuppressWarnings("deprecation")
+ int deleteType = DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY.getNumber();
+ toStatsBuilder
+ .setNativeLatencyMillis(fromNativeStats.getLatencyMs())
+ .setDeleteType(deleteType)
+ .setDeletedDocumentCount(fromNativeStats.getNumDocumentsDeleted());
+ }
+
+ /**
* Copies native {@link OptimizeStatsProto} to builder.
*
* @param fromNativeStats Stats copied from.
@@ -164,4 +187,25 @@
.setStorageSizeAfterBytes(fromNativeStats.getStorageSizeAfter())
.setTimeSinceLastOptimizeMillis(fromNativeStats.getTimeSinceLastOptimizeMs());
}
+
+ /*
+ * Copy SetSchema result stats to builder.
+ *
+ * @param fromProto Stats copied from.
+ * @param toStatsBuilder Stats copied to.
+ */
+ static void copyNativeStats(
+ @NonNull SetSchemaResultProto fromProto,
+ @NonNull SetSchemaStats.Builder toStatsBuilder) {
+ Objects.requireNonNull(fromProto);
+ Objects.requireNonNull(toStatsBuilder);
+ toStatsBuilder
+ .setNewTypeCount(fromProto.getNewSchemaTypesCount())
+ .setDeletedTypeCount(fromProto.getDeletedSchemaTypesCount())
+ .setCompatibleTypeChangeCount(fromProto.getFullyCompatibleChangedSchemaTypesCount())
+ .setIndexIncompatibleTypeChangeCount(
+ fromProto.getIndexIncompatibleChangedSchemaTypesCount())
+ .setBackwardsIncompatibleTypeChangeCount(
+ fromProto.getIncompatibleSchemaTypesCount());
+ }
}
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
index d7904f3..75ae2d0a 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SearchStats.java
@@ -40,6 +40,7 @@
VISIBILITY_SCOPE_LOCAL,
// Searches the global documents. Including platform surfaceable and 3p-access.
VISIBILITY_SCOPE_GLOBAL,
+ VISIBILITY_SCOPE_UNKNOWN,
// TODO(b/173532925) Add THIRD_PARTY_ACCESS once we can distinguish platform
// surfaceable from 3p access(right both of them are categorized as
// VISIBILITY_SCOPE_GLOBAL)
@@ -51,6 +52,7 @@
public static final int VISIBILITY_SCOPE_LOCAL = 1;
// Searches the global documents. Including platform surfaceable and 3p-access.
public static final int VISIBILITY_SCOPE_GLOBAL = 2;
+ public static final int VISIBILITY_SCOPE_UNKNOWN = 3;
// TODO(b/173532925): Add a field searchType to indicate where the search is used(normal
// query vs in removeByQuery vs during migration)
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
index 9d789a8..3e5a80f 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/external/localstorage/stats/SetSchemaStats.java
@@ -47,9 +47,6 @@
private final int mTotalLatencyMillis;
- /** Overall time used for the native function call. */
- private final int mNativeLatencyMillis;
-
/** Number of newly added schema types. */
private final int mNewTypeCount;
@@ -72,7 +69,6 @@
mStatusCode = builder.mStatusCode;
mSchemaMigrationStats = builder.mSchemaMigrationStats;
mTotalLatencyMillis = builder.mTotalLatencyMillis;
- mNativeLatencyMillis = builder.mNativeLatencyMillis;
mNewTypeCount = builder.mNewTypeCount;
mDeletedTypeCount = builder.mDeletedTypeCount;
mCompatibleTypeChangeCount = builder.mCompatibleTypeChangeCount;
@@ -112,11 +108,6 @@
return mTotalLatencyMillis;
}
- /** Returns overall time used for the native function call. */
- public int getNativeLatencyMillis() {
- return mNativeLatencyMillis;
- }
-
/** Returns number of newly added schema types. */
public int getNewTypeCount() {
return mNewTypeCount;
@@ -159,7 +150,6 @@
@AppSearchResult.ResultCode int mStatusCode;
@Nullable SchemaMigrationStats mSchemaMigrationStats;
int mTotalLatencyMillis;
- int mNativeLatencyMillis;
int mNewTypeCount;
int mDeletedTypeCount;
int mCompatibleTypeChangeCount;
@@ -193,13 +183,6 @@
return this;
}
- /** Sets native latency in milliseconds. */
- @NonNull
- public Builder setNativeLatencyMillis(int nativeLatencyMillis) {
- mNativeLatencyMillis = nativeLatencyMillis;
- return this;
- }
-
/** Sets number of new types. */
@NonNull
public Builder setNewTypeCount(int newTypeCount) {
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
index fdf6a00..4c29ece 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/stats/PlatformLogger.java
@@ -36,6 +36,7 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
import com.android.server.appsearch.util.PackageUtil;
import java.io.UnsupportedEncodingException;
@@ -180,6 +181,11 @@
}
}
+ @Override
+ public void logStats(@NonNull SetSchemaStats stats) {
+ // TODO(b/173532925): Log stats
+ }
+
/**
* Removes cached UID for package.
*
diff --git a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
index ce142d6..c4d1016 100644
--- a/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
+++ b/apex/appsearch/service/java/com/android/server/appsearch/visibilitystore/VisibilityStoreImpl.java
@@ -126,7 +126,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ SCHEMA_VERSION);
+ /*version=*/ SCHEMA_VERSION,
+ /*setSchemaStatsBuilder=*/ null);
}
// Populate visibility settings set
diff --git a/apex/appsearch/synced_jetpack_changeid.txt b/apex/appsearch/synced_jetpack_changeid.txt
index a81d7d80..4db8355 100644
--- a/apex/appsearch/synced_jetpack_changeid.txt
+++ b/apex/appsearch/synced_jetpack_changeid.txt
@@ -1 +1 @@
-Ie04f1ecc033faae8085afcb51eb9e40a298998d5
+bd53b062816070b64feb992c2bf58f3afa3d420e
diff --git a/apex/appsearch/testing/Android.bp b/apex/appsearch/testing/Android.bp
index 5407cb4..f78d98a 100644
--- a/apex/appsearch/testing/Android.bp
+++ b/apex/appsearch/testing/Android.bp
@@ -28,6 +28,7 @@
"framework",
"framework-appsearch",
"guava",
+ "service-appsearch",
"truth-prebuilt",
],
visibility: [
diff --git a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
index ec9a42ea..4d8e8e9 100644
--- a/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
+++ b/apex/appsearch/testing/java/com/android/server/appsearch/testing/external/AppSearchTestUtils.java
@@ -19,6 +19,8 @@
import static com.google.common.truth.Truth.assertThat;
import static com.google.common.truth.Truth.assertWithMessage;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.appsearch.AppSearchBatchResult;
import android.app.appsearch.AppSearchSessionShim;
import android.app.appsearch.GenericDocument;
@@ -26,12 +28,66 @@
import android.app.appsearch.SearchResult;
import android.app.appsearch.SearchResultsShim;
+import com.android.server.appsearch.external.localstorage.AppSearchLogger;
+import com.android.server.appsearch.external.localstorage.stats.CallStats;
+import com.android.server.appsearch.external.localstorage.stats.InitializeStats;
+import com.android.server.appsearch.external.localstorage.stats.OptimizeStats;
+import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
+import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
+import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
+
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.concurrent.Future;
public class AppSearchTestUtils {
+ // Non-thread-safe logger implementation for testing
+ public static class TestLogger implements AppSearchLogger {
+ @Nullable public CallStats mCallStats;
+ @Nullable public PutDocumentStats mPutDocumentStats;
+ @Nullable public InitializeStats mInitializeStats;
+ @Nullable public SearchStats mSearchStats;
+ @Nullable public RemoveStats mRemoveStats;
+ @Nullable public OptimizeStats mOptimizeStats;
+ @Nullable public SetSchemaStats mSetSchemaStats;
+
+ @Override
+ public void logStats(@NonNull CallStats stats) {
+ mCallStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull PutDocumentStats stats) {
+ mPutDocumentStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull InitializeStats stats) {
+ mInitializeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SearchStats stats) {
+ mSearchStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull RemoveStats stats) {
+ mRemoveStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull OptimizeStats stats) {
+ mOptimizeStats = stats;
+ }
+
+ @Override
+ public void logStats(@NonNull SetSchemaStats stats) {
+ mSetSchemaStats = stats;
+ }
+ }
public static <K, V> AppSearchBatchResult<K, V> checkIsBatchResultSuccess(
Future<AppSearchBatchResult<K, V>> future) throws Exception {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 98e447c..7ed0bed 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -127,6 +127,7 @@
})";
static const char IMAGE_FRAG_DYNAMIC_COLORING_SHADER_SOURCE[] = R"(
precision mediump float;
+ const float cWhiteMaskThreshold = 0.05f;
uniform sampler2D uTexture;
uniform float uFade;
uniform float uColorProgress;
@@ -141,10 +142,20 @@
varying highp vec2 vUv;
void main() {
vec4 mask = texture2D(uTexture, vUv);
- vec4 color = mask.r * mix(uStartColor0, uEndColor0, uColorProgress)
- + mask.g * mix(uStartColor1, uEndColor1, uColorProgress)
- + mask.b * mix(uStartColor2, uEndColor2, uColorProgress)
- + mask.a * mix(uStartColor3, uEndColor3, uColorProgress);
+ float r = mask.r;
+ float g = mask.g;
+ float b = mask.b;
+ float a = mask.a;
+ // If all channels have values, render pixel as a shade of white.
+ float useWhiteMask = step(cWhiteMaskThreshold, r)
+ * step(cWhiteMaskThreshold, g)
+ * step(cWhiteMaskThreshold, b)
+ * step(cWhiteMaskThreshold, a);
+ vec4 color = r * mix(uStartColor0, uEndColor0, uColorProgress)
+ + g * mix(uStartColor1, uEndColor1, uColorProgress)
+ + b * mix(uStartColor2, uEndColor2, uColorProgress)
+ + a * mix(uStartColor3, uEndColor3, uColorProgress);
+ color = mix(color, vec4(vec3((r + g + b + a) * 0.25f), 1.0), useWhiteMask);
gl_FragColor = vec4(color.x, color.y, color.z, (1.0 - uFade)) * color.a;
})";
static const char IMAGE_FRAG_SHADER_SOURCE[] = R"(
@@ -1077,6 +1088,8 @@
int pause = 0;
int progress = 0;
int framesToFadeCount = 0;
+ int colorTransitionStart = 0;
+ int colorTransitionEnd = 0;
char path[ANIM_ENTRY_NAME_MAX];
char color[7] = "000000"; // default to black if unspecified
char clockPos1[TEXT_POS_LEN_MAX + 1] = "";
@@ -1102,14 +1115,17 @@
} else {
animation.progressEnabled = false;
}
- } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s",
+ } else if (sscanf(l, "dynamic_colors %" STRTO(ANIM_PATH_MAX) "s #%6s #%6s #%6s #%6s %d %d",
dynamicColoringPartNameBuffer,
- start_color_0, start_color_1, start_color_2, start_color_3)) {
+ start_color_0, start_color_1, start_color_2, start_color_3,
+ &colorTransitionStart, &colorTransitionEnd)) {
animation.dynamicColoringEnabled = true;
parseColor(start_color_0, animation.startColors[0]);
parseColor(start_color_1, animation.startColors[1]);
parseColor(start_color_2, animation.startColors[2]);
parseColor(start_color_3, animation.startColors[3]);
+ animation.colorTransitionStart = colorTransitionStart;
+ animation.colorTransitionEnd = colorTransitionEnd;
dynamicColoringPartName = std::string(dynamicColoringPartNameBuffer);
} else if (sscanf(l, "%c %d %d %" STRTO(ANIM_PATH_MAX) "s%n",
&pathType, &count, &pause, path, &nextReadPos) >= 4) {
@@ -1461,11 +1477,16 @@
if (shouldStopPlayingPart(part, fadedFramesCount, lastDisplayedProgress)) break;
// Color progress is
- // - the normalized animation progress between [0, 1] for the dynamic coloring part,
+ // - the animation progress, normalized from
+ // [colorTransitionStart,colorTransitionEnd] to [0, 1] for the dynamic coloring
+ // part.
// - 0 for parts that come before,
// - 1 for parts that come after.
float colorProgress = part.useDynamicColoring
- ? (float)j / fcount
+ ? fmin(fmax(
+ ((float)j - animation.colorTransitionStart) /
+ fmax(animation.colorTransitionEnd -
+ animation.colorTransitionStart, 1.0f), 0.0f), 1.0f)
: (part.postDynamicColoring ? 1 : 0);
processDisplayEvents();
diff --git a/cmds/bootanimation/BootAnimation.h b/cmds/bootanimation/BootAnimation.h
index 0e29621..7a597da 100644
--- a/cmds/bootanimation/BootAnimation.h
+++ b/cmds/bootanimation/BootAnimation.h
@@ -111,6 +111,8 @@
Font progressFont;
// Controls if dynamic coloring is enabled for the whole animation.
bool dynamicColoringEnabled = false;
+ int colorTransitionStart = 0; // Start frame of dynamic color transition.
+ int colorTransitionEnd = 0; // End frame of dynamic color transition.
float startColors[4][3]; // Start colors of dynamic color transition.
float endColors[4][3]; // End colors of dynamic color transition.
};
diff --git a/core/api/current.txt b/core/api/current.txt
index 3ddb374..94d650d 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -99,6 +99,7 @@
field public static final String INTERACT_ACROSS_PROFILES = "android.permission.INTERACT_ACROSS_PROFILES";
field public static final String INTERNET = "android.permission.INTERNET";
field public static final String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
+ field public static final String LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK = "android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK";
field public static final String LOADER_USAGE_STATS = "android.permission.LOADER_USAGE_STATS";
field public static final String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
field public static final String MANAGE_DOCUMENTS = "android.permission.MANAGE_DOCUMENTS";
@@ -20181,8 +20182,10 @@
method public int getAllowedCapturePolicy();
method public int getContentType();
method public int getFlags();
+ method public int getSpatializationBehavior();
method public int getUsage();
method public int getVolumeControlStream();
+ method public boolean isContentSpatialized();
method public void writeToParcel(android.os.Parcel, int);
field public static final int ALLOW_CAPTURE_BY_ALL = 1; // 0x1
field public static final int ALLOW_CAPTURE_BY_NONE = 3; // 0x3
@@ -20196,6 +20199,8 @@
field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
field @Deprecated public static final int FLAG_LOW_LATENCY = 256; // 0x100
+ field public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0; // 0x0
+ field public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1; // 0x1
field public static final int USAGE_ALARM = 4; // 0x4
field public static final int USAGE_ASSISTANCE_ACCESSIBILITY = 11; // 0xb
field public static final int USAGE_ASSISTANCE_NAVIGATION_GUIDANCE = 12; // 0xc
@@ -20222,7 +20227,9 @@
method public android.media.AudioAttributes.Builder setContentType(int);
method public android.media.AudioAttributes.Builder setFlags(int);
method @NonNull public android.media.AudioAttributes.Builder setHapticChannelsMuted(boolean);
+ method @NonNull public android.media.AudioAttributes.Builder setIsContentSpatialized(boolean);
method public android.media.AudioAttributes.Builder setLegacyStreamType(int);
+ method @NonNull public android.media.AudioAttributes.Builder setSpatializationBehavior(int);
method public android.media.AudioAttributes.Builder setUsage(int);
}
@@ -20447,6 +20454,7 @@
method public String getProperty(String);
method public int getRingerMode();
method @Deprecated public int getRouting(int);
+ method @Nullable public android.media.Spatializer getSpatializer();
method public int getStreamMaxVolume(int);
method public int getStreamMinVolume(int);
method public int getStreamVolume(int);
@@ -23843,6 +23851,19 @@
method public void onLoadComplete(android.media.SoundPool, int, int);
}
+ public class Spatializer {
+ method public void addOnSpatializerStateChangedListener(@NonNull java.util.concurrent.Executor, @NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
+ method public boolean canBeSpatialized(@NonNull android.media.AudioAttributes, @NonNull android.media.AudioFormat);
+ method public boolean isAvailable();
+ method public boolean isEnabled();
+ method public void removeOnSpatializerStateChangedListener(@NonNull android.media.Spatializer.OnSpatializerStateChangedListener);
+ }
+
+ public static interface Spatializer.OnSpatializerStateChangedListener {
+ method public void onSpatializerAvailableChanged(@NonNull android.media.Spatializer, boolean);
+ method public void onSpatializerEnabledChanged(@NonNull android.media.Spatializer, boolean);
+ }
+
public final class SubtitleData {
ctor public SubtitleData(int, long, long, @NonNull byte[]);
method @NonNull public byte[] getData();
@@ -35206,6 +35227,7 @@
field public static final String ACTION_SEARCH_SETTINGS = "android.search.action.SEARCH_SETTINGS";
field public static final String ACTION_SECURITY_SETTINGS = "android.settings.SECURITY_SETTINGS";
field public static final String ACTION_SETTINGS = "android.settings.SETTINGS";
+ field public static final String ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK = "android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK";
field public static final String ACTION_SHOW_REGULATORY_INFO = "android.settings.SHOW_REGULATORY_INFO";
field public static final String ACTION_SHOW_WORK_POLICY_INFO = "android.settings.SHOW_WORK_POLICY_INFO";
field public static final String ACTION_SOUND_SETTINGS = "android.settings.SOUND_SETTINGS";
@@ -35246,6 +35268,9 @@
field public static final String EXTRA_EASY_CONNECT_ERROR_CODE = "android.provider.extra.EASY_CONNECT_ERROR_CODE";
field public static final String EXTRA_INPUT_METHOD_ID = "input_method_id";
field public static final String EXTRA_NOTIFICATION_LISTENER_COMPONENT_NAME = "android.provider.extra.NOTIFICATION_LISTENER_COMPONENT_NAME";
+ field public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI = "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI";
+ field public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT = "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT";
+ field public static final String EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY = "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY";
field public static final String EXTRA_SUB_ID = "android.provider.extra.SUB_ID";
field public static final String EXTRA_WIFI_NETWORK_LIST = "android.provider.extra.WIFI_NETWORK_LIST";
field public static final String EXTRA_WIFI_NETWORK_RESULT_LIST = "android.provider.extra.WIFI_NETWORK_RESULT_LIST";
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 2846b36..0d3dd7c 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -26,6 +26,7 @@
field public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = "android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY";
field public static final String ALLOCATE_AGGRESSIVE = "android.permission.ALLOCATE_AGGRESSIVE";
field public static final String ALLOW_ANY_CODEC_FOR_PLAYBACK = "android.permission.ALLOW_ANY_CODEC_FOR_PLAYBACK";
+ field public static final String ALLOW_PLACE_IN_TWO_PANE_SETTINGS = "android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS";
field public static final String AMBIENT_WALLPAPER = "android.permission.AMBIENT_WALLPAPER";
field public static final String APPROVE_INCIDENT_REPORTS = "android.permission.APPROVE_INCIDENT_REPORTS";
field public static final String ASSOCIATE_COMPANION_DEVICES = "android.permission.ASSOCIATE_COMPANION_DEVICES";
@@ -5372,6 +5373,13 @@
field public static final android.media.RouteDiscoveryPreference EMPTY;
}
+ public class Spatializer {
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void addCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
+ method @NonNull @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public java.util.List<android.media.AudioDeviceAttributes> getCompatibleAudioDevices();
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void removeCompatibleAudioDevice(@NonNull android.media.AudioDeviceAttributes);
+ method @RequiresPermission("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS") public void setEnabled(boolean);
+ }
+
}
package android.media.audiofx {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0732c61..becdd92 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3229,6 +3229,7 @@
method @NonNull public android.content.res.Configuration getConfiguration();
method @NonNull public android.os.IBinder getFragmentToken();
method @NonNull public android.graphics.Point getPositionInParent();
+ method public int getRunningActivityCount();
method @NonNull public android.window.WindowContainerToken getToken();
method public int getWindowingMode();
method public boolean hasRunningActivity();
diff --git a/core/java/android/accounts/Account.java b/core/java/android/accounts/Account.java
index 0d6a079..e6cdcc0 100644
--- a/core/java/android/accounts/Account.java
+++ b/core/java/android/accounts/Account.java
@@ -31,6 +31,7 @@
import com.android.internal.annotations.GuardedBy;
+import java.util.Objects;
import java.util.Set;
/**
@@ -86,6 +87,12 @@
if (TextUtils.isEmpty(type)) {
throw new IllegalArgumentException("the type must not be empty: " + type);
}
+ if (name.length() > 200) {
+ throw new IllegalArgumentException("account name is longer than 200 characters");
+ }
+ if (type.length() > 200) {
+ throw new IllegalArgumentException("account type is longer than 200 characters");
+ }
this.name = name;
this.type = type;
this.accessId = accessId;
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index 76f8731..d1def7e 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -55,7 +55,7 @@
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.SplashScreen;
import android.window.WindowContainerToken;
@@ -426,7 +426,7 @@
private IAppTransitionAnimationSpecsFuture mSpecsFuture;
private RemoteAnimationAdapter mRemoteAnimationAdapter;
private IBinder mLaunchCookie;
- private IRemoteTransition mRemoteTransition;
+ private RemoteTransition mRemoteTransition;
private boolean mOverrideTaskTransition;
private String mSplashScreenThemeResName;
@SplashScreen.SplashScreenStyle
@@ -1054,7 +1054,7 @@
*/
@RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
public static ActivityOptions makeRemoteAnimation(RemoteAnimationAdapter remoteAnimationAdapter,
- IRemoteTransition remoteTransition) {
+ RemoteTransition remoteTransition) {
final ActivityOptions opts = new ActivityOptions();
opts.mRemoteAnimationAdapter = remoteAnimationAdapter;
opts.mAnimationType = ANIM_REMOTE_ANIMATION;
@@ -1064,11 +1064,11 @@
/**
* Create an {@link ActivityOptions} instance that lets the application control the entire
- * transition using a {@link IRemoteTransition}.
+ * transition using a {@link RemoteTransition}.
* @hide
*/
@RequiresPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS)
- public static ActivityOptions makeRemoteTransition(IRemoteTransition remoteTransition) {
+ public static ActivityOptions makeRemoteTransition(RemoteTransition remoteTransition) {
final ActivityOptions opts = new ActivityOptions();
opts.mRemoteTransition = remoteTransition;
return opts;
@@ -1181,8 +1181,7 @@
}
mRemoteAnimationAdapter = opts.getParcelable(KEY_REMOTE_ANIMATION_ADAPTER);
mLaunchCookie = opts.getBinder(KEY_LAUNCH_COOKIE);
- mRemoteTransition = IRemoteTransition.Stub.asInterface(opts.getBinder(
- KEY_REMOTE_TRANSITION));
+ mRemoteTransition = opts.getParcelable(KEY_REMOTE_TRANSITION);
mOverrideTaskTransition = opts.getBoolean(KEY_OVERRIDE_TASK_TRANSITION);
mSplashScreenThemeResName = opts.getString(KEY_SPLASH_SCREEN_THEME);
mRemoveWithTaskOrganizer = opts.getBoolean(KEY_REMOVE_WITH_TASK_ORGANIZER);
@@ -1348,7 +1347,7 @@
}
/** @hide */
- public IRemoteTransition getRemoteTransition() {
+ public RemoteTransition getRemoteTransition() {
return mRemoteTransition;
}
@@ -1965,7 +1964,7 @@
b.putBinder(KEY_LAUNCH_COOKIE, mLaunchCookie);
}
if (mRemoteTransition != null) {
- b.putBinder(KEY_REMOTE_TRANSITION, mRemoteTransition.asBinder());
+ b.putParcelable(KEY_REMOTE_TRANSITION, mRemoteTransition);
}
if (mOverrideTaskTransition) {
b.putBoolean(KEY_OVERRIDE_TASK_TRANSITION, mOverrideTaskTransition);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ae812ec..2e22b92 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -466,11 +466,7 @@
@Override
public int hashCode() {
- return hashCode(authority, userId);
- }
-
- public static int hashCode(final String auth, final int userIdent) {
- return ((auth != null) ? auth.hashCode() : 0) ^ userIdent;
+ return ((authority != null) ? authority.hashCode() : 0) ^ userId;
}
}
@@ -492,7 +488,7 @@
// Note we never removes items from this map but that's okay because there are only so many
// users and so many authorities.
@GuardedBy("mGetProviderKeys")
- final SparseArray<ProviderKey> mGetProviderKeys = new SparseArray<>();
+ final ArrayMap<ProviderKey, ProviderKey> mGetProviderKeys = new ArrayMap<>();
final ArrayMap<Activity, ArrayList<OnActivityPausedListener>> mOnPauseListeners
= new ArrayMap<Activity, ArrayList<OnActivityPausedListener>>();
@@ -6992,11 +6988,11 @@
}
private ProviderKey getGetProviderKey(String auth, int userId) {
- final int key = ProviderKey.hashCode(auth, userId);
+ final ProviderKey key = new ProviderKey(auth, userId);
synchronized (mGetProviderKeys) {
ProviderKey lock = mGetProviderKeys.get(key);
if (lock == null) {
- lock = new ProviderKey(auth, userId);
+ lock = key;
mGetProviderKeys.put(key, lock);
}
return lock;
diff --git a/core/java/android/app/GameManager.java b/core/java/android/app/GameManager.java
index 5964f71..babeb08 100644
--- a/core/java/android/app/GameManager.java
+++ b/core/java/android/app/GameManager.java
@@ -135,6 +135,7 @@
throw e.rethrowFromSystemServer();
}
}
+
/**
* Returns a list of supported game modes for a given package.
* <p>
@@ -151,4 +152,20 @@
}
}
+ /**
+ * Returns if ANGLE is enabled for a given package.
+ * <p>
+ * The caller must have {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ *
+ * @hide
+ */
+ @UserHandleAware
+ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
+ public @GameMode boolean isAngleEnabled(@NonNull String packageName) {
+ try {
+ return mService.getAngleEnabled(packageName, mContext.getUserId());
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
}
diff --git a/core/java/android/app/IGameManagerService.aidl b/core/java/android/app/IGameManagerService.aidl
index 4bf8a3f..189f0a2 100644
--- a/core/java/android/app/IGameManagerService.aidl
+++ b/core/java/android/app/IGameManagerService.aidl
@@ -23,4 +23,5 @@
int getGameMode(String packageName, int userId);
void setGameMode(String packageName, int gameMode, int userId);
int[] getAvailableGameModes(String packageName);
+ boolean getAngleEnabled(String packageName, int userId);
}
\ No newline at end of file
diff --git a/core/java/android/app/NotificationChannel.java b/core/java/android/app/NotificationChannel.java
index 1837fb8..6553b61 100644
--- a/core/java/android/app/NotificationChannel.java
+++ b/core/java/android/app/NotificationChannel.java
@@ -260,8 +260,6 @@
private boolean mDemoted = false;
private boolean mImportantConvo = false;
private long mDeletedTime = DEFAULT_DELETION_TIME_MS;
- // If the sound for this channel is missing, e.g. after restore.
- private boolean mIsSoundMissing;
/**
* Creates a notification channel.
@@ -717,13 +715,6 @@
}
/**
- * @hide
- */
- public boolean isSoundMissing() {
- return mIsSoundMissing;
- }
-
- /**
* Returns the audio attributes for sound played by notifications posted to this channel.
*/
public AudioAttributes getAudioAttributes() {
@@ -1007,9 +998,8 @@
// according to the docs because canonicalize method has to handle canonical uris as well.
Uri canonicalizedUri = contentResolver.canonicalize(uri);
if (canonicalizedUri == null) {
- // We got a null because the uri in the backup does not exist here.
- mIsSoundMissing = true;
- return null;
+ // We got a null because the uri in the backup does not exist here, so we return default
+ return Settings.System.DEFAULT_NOTIFICATION_URI;
}
return contentResolver.uncanonicalize(canonicalizedUri);
}
diff --git a/core/java/android/app/search/Query.java b/core/java/android/app/search/Query.java
index c64e107..f073b4e 100644
--- a/core/java/android/app/search/Query.java
+++ b/core/java/android/app/search/Query.java
@@ -70,7 +70,7 @@
@NonNull Bundle extras) {
mInput = input;
mTimestampMillis = timestampMillis;
- mExtras = extras == null ? extras : new Bundle();
+ mExtras = extras != null ? extras : new Bundle();
}
/**
diff --git a/core/java/android/bluetooth/BluetoothDevice.java b/core/java/android/bluetooth/BluetoothDevice.java
index bbb550f..5a5fac4 100644
--- a/core/java/android/bluetooth/BluetoothDevice.java
+++ b/core/java/android/bluetooth/BluetoothDevice.java
@@ -1329,7 +1329,10 @@
if (alias == null) {
return getName();
}
- return alias;
+ return alias
+ .replace('\t', ' ')
+ .replace('\n', ' ')
+ .replace('\r', ' ');
} catch (RemoteException e) {
Log.e(TAG, "", e);
}
diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java
index 2702772..08e95a2 100644
--- a/core/java/android/content/Context.java
+++ b/core/java/android/content/Context.java
@@ -3195,7 +3195,7 @@
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#O}
* or higher are not allowed to start background services from the background.
* See
- * <a href="{@docRoot}/about/versions/oreo/background">
+ * <a href="/about/versions/oreo/background">
* Background Execution Limits</a>
* for more details.
*
@@ -3204,7 +3204,7 @@
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
- * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+ * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
@@ -3258,7 +3258,7 @@
* apps targeting SDK Version {@link android.os.Build.VERSION_CODES#S}
* or higher are not allowed to start foreground services from the background.
* See
- * <a href="{@docRoot}/about/versions/12/behavior-changes-12">
+ * <a href="/about/versions/12/behavior-changes-12">
* Behavior changes: Apps targeting Android 12
* </a>
* for more details.
diff --git a/core/java/android/content/pm/PackageItemInfo.java b/core/java/android/content/pm/PackageItemInfo.java
index dd2080b..2bac066 100644
--- a/core/java/android/content/pm/PackageItemInfo.java
+++ b/core/java/android/content/pm/PackageItemInfo.java
@@ -207,7 +207,9 @@
return loadSafeLabel(pm, DEFAULT_MAX_LABEL_SIZE_PX, SAFE_STRING_FLAG_TRIM
| SAFE_STRING_FLAG_FIRST_LINE);
} else {
- return loadUnsafeLabel(pm);
+ // Trims the label string to the MAX_SAFE_LABEL_LENGTH. This is to prevent that the
+ // system is overwhelmed by an enormous string returned by the application.
+ return TextUtils.trimToSize(loadUnsafeLabel(pm), MAX_SAFE_LABEL_LENGTH);
}
}
diff --git a/core/java/android/hardware/biometrics/BiometricPrompt.java b/core/java/android/hardware/biometrics/BiometricPrompt.java
index 3f3db29..c8c122d 100644
--- a/core/java/android/hardware/biometrics/BiometricPrompt.java
+++ b/core/java/android/hardware/biometrics/BiometricPrompt.java
@@ -438,9 +438,16 @@
}
private class OnAuthenticationCancelListener implements CancellationSignal.OnCancelListener {
+ private final long mAuthRequestId;
+
+ OnAuthenticationCancelListener(long id) {
+ mAuthRequestId = id;
+ }
+
@Override
public void onCancel() {
- cancelAuthentication();
+ Log.d(TAG, "Cancel BP authentication requested for: " + mAuthRequestId);
+ cancelAuthentication(mAuthRequestId);
}
}
@@ -853,10 +860,12 @@
* @param userId The user to authenticate
* @param operationId The keystore operation associated with authentication
*
+ * @return A requestId that can be used to cancel this operation.
+ *
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public void authenticateUserForOperation(
+ public long authenticateUserForOperation(
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@NonNull AuthenticationCallback callback,
@@ -871,7 +880,8 @@
if (callback == null) {
throw new IllegalArgumentException("Must supply a callback");
}
- authenticateInternal(operationId, cancel, executor, callback, userId);
+
+ return authenticateInternal(operationId, cancel, executor, callback, userId);
}
/**
@@ -1002,10 +1012,10 @@
authenticateInternal(null /* crypto */, cancel, executor, callback, mContext.getUserId());
}
- private void cancelAuthentication() {
+ private void cancelAuthentication(long requestId) {
if (mService != null) {
try {
- mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+ mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
Log.e(TAG, "Unable to cancel authentication", e);
}
@@ -1024,7 +1034,7 @@
authenticateInternal(operationId, cancel, executor, callback, userId);
}
- private void authenticateInternal(
+ private long authenticateInternal(
long operationId,
@NonNull CancellationSignal cancel,
@NonNull @CallbackExecutor Executor executor,
@@ -1040,9 +1050,7 @@
try {
if (cancel.isCanceled()) {
Log.w(TAG, "Authentication already canceled");
- return;
- } else {
- cancel.setOnCancelListener(new OnAuthenticationCancelListener());
+ return -1;
}
mExecutor = executor;
@@ -1065,14 +1073,16 @@
promptInfo = mPromptInfo;
}
- mService.authenticate(mToken, operationId, userId, mBiometricServiceReceiver,
- mContext.getOpPackageName(), promptInfo);
-
+ final long authId = mService.authenticate(mToken, operationId, userId,
+ mBiometricServiceReceiver, mContext.getOpPackageName(), promptInfo);
+ cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+ return authId;
} catch (RemoteException e) {
Log.e(TAG, "Remote exception while authenticating", e);
mExecutor.execute(() -> callback.onAuthenticationError(
BiometricPrompt.BIOMETRIC_ERROR_HW_UNAVAILABLE,
mContext.getString(R.string.biometric_error_hw_unavailable)));
+ return -1;
}
}
diff --git a/core/java/android/hardware/biometrics/IAuthService.aidl b/core/java/android/hardware/biometrics/IAuthService.aidl
index 4c2a9ae..91f794c 100644
--- a/core/java/android/hardware/biometrics/IAuthService.aidl
+++ b/core/java/android/hardware/biometrics/IAuthService.aidl
@@ -41,13 +41,14 @@
// Retrieve the package where BIometricOrompt's UI is implemented
String getUiPackage();
- // Requests authentication. The service choose the appropriate biometric to use, and show
- // the corresponding BiometricDialog.
- void authenticate(IBinder token, long sessionId, int userId,
+ // Requests authentication. The service chooses the appropriate biometric to use, and shows
+ // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
+ // this operation.
+ long authenticate(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
- // Cancel authentication for the given sessionId
- void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel authentication for the given requestId.
+ void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// TODO(b/141025588): Make userId the first arg to be consistent with hasEnrolledBiometrics.
// Checks if biometrics can be used.
diff --git a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
index 876513f..addd622 100644
--- a/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricAuthenticator.aidl
@@ -48,13 +48,13 @@
// startPreparedClient().
void prepareForAuthentication(boolean requireConfirmation, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
- int cookie, boolean allowBackgroundAuthentication);
+ long requestId, int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client.
void startPreparedClient(int cookie);
- // Cancels authentication.
- void cancelAuthenticationFromService(IBinder token, String opPackageName);
+ // Cancels authentication for the given requestId.
+ void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId);
// Determine if HAL is loaded and ready
boolean isHardwareDetected(String opPackageName);
diff --git a/core/java/android/hardware/biometrics/IBiometricService.aidl b/core/java/android/hardware/biometrics/IBiometricService.aidl
index 64b5118..2c3c8c3 100644
--- a/core/java/android/hardware/biometrics/IBiometricService.aidl
+++ b/core/java/android/hardware/biometrics/IBiometricService.aidl
@@ -36,13 +36,14 @@
// Retrieve static sensor properties for all biometric sensors
List<SensorPropertiesInternal> getSensorProperties(String opPackageName);
- // Requests authentication. The service choose the appropriate biometric to use, and show
- // the corresponding BiometricDialog.
- void authenticate(IBinder token, long operationId, int userId,
+ // Requests authentication. The service chooses the appropriate biometric to use, and shows
+ // the corresponding BiometricDialog. A requestId is returned that can be used to cancel
+ // this operation.
+ long authenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, in PromptInfo promptInfo);
- // Cancel authentication for the given session.
- void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel authentication for the given requestId.
+ void cancelAuthentication(IBinder token, String opPackageName, long requestId);
// Checks if biometrics can be used.
int canAuthenticate(String opPackageName, int userId, int callingUserId, int authenticators);
diff --git a/core/java/android/hardware/display/DisplayManager.java b/core/java/android/hardware/display/DisplayManager.java
index 5034ef1d..73961ff 100644
--- a/core/java/android/hardware/display/DisplayManager.java
+++ b/core/java/android/hardware/display/DisplayManager.java
@@ -864,7 +864,8 @@
if (surface != null) {
builder.setSurface(surface);
}
- return createVirtualDisplay(null /* projection */, builder.build(), callback, handler);
+ return createVirtualDisplay(null /* projection */, builder.build(), callback, handler,
+ null /* windowContext */);
}
// TODO : Remove this hidden API after remove all callers. (Refer to MultiDisplayService)
@@ -882,15 +883,17 @@
if (surface != null) {
builder.setSurface(surface);
}
- return createVirtualDisplay(projection, builder.build(), callback, handler);
+ return createVirtualDisplay(projection, builder.build(), callback, handler,
+ null /* windowContext */);
}
/** @hide */
public VirtualDisplay createVirtualDisplay(@Nullable MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig,
- @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+ @Nullable Context windowContext) {
return mGlobal.createVirtualDisplay(mContext, projection, virtualDisplayConfig, callback,
- handler);
+ handler, windowContext);
}
/**
diff --git a/core/java/android/hardware/display/DisplayManagerGlobal.java b/core/java/android/hardware/display/DisplayManagerGlobal.java
index 3e15c0ee..1fec3c9f 100644
--- a/core/java/android/hardware/display/DisplayManagerGlobal.java
+++ b/core/java/android/hardware/display/DisplayManagerGlobal.java
@@ -361,6 +361,11 @@
for (int i = 0; i < numListeners; i++) {
mask |= mDisplayListeners.get(i).mEventsMask;
}
+ if (mDispatchNativeCallbacks) {
+ mask |= DisplayManager.EVENT_FLAG_DISPLAY_ADDED
+ | DisplayManager.EVENT_FLAG_DISPLAY_CHANGED
+ | DisplayManager.EVENT_FLAG_DISPLAY_REMOVED;
+ }
return mask;
}
@@ -578,7 +583,7 @@
public VirtualDisplay createVirtualDisplay(@NonNull Context context, MediaProjection projection,
@NonNull VirtualDisplayConfig virtualDisplayConfig, VirtualDisplay.Callback callback,
- Handler handler) {
+ Handler handler, @Nullable Context windowContext) {
VirtualDisplayCallback callbackWrapper = new VirtualDisplayCallback(callback, handler);
IMediaProjection projectionToken = projection != null ? projection.getProjection() : null;
int displayId;
@@ -604,7 +609,7 @@
return null;
}
return new VirtualDisplay(this, display, callbackWrapper,
- virtualDisplayConfig.getSurface());
+ virtualDisplayConfig.getSurface(), windowContext);
}
public void setVirtualDisplaySurface(IVirtualDisplayCallback token, Surface surface) {
@@ -1075,12 +1080,17 @@
private static native void nSignalNativeCallbacks(float refreshRate);
- // Called from AChoreographer via JNI.
- // Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
- private void registerNativeChoreographerForRefreshRateCallbacks() {
+ /**
+ * Called from AChoreographer via JNI.
+ * Registers AChoreographer so that refresh rate callbacks can be dispatched from DMS.
+ * Public for unit testing to be able to call this method.
+ */
+ @VisibleForTesting
+ public void registerNativeChoreographerForRefreshRateCallbacks() {
synchronized (mLock) {
- registerCallbackIfNeededLocked();
mDispatchNativeCallbacks = true;
+ registerCallbackIfNeededLocked();
+ updateCallbackIfNeededLocked();
DisplayInfo display = getDisplayInfoLocked(Display.DEFAULT_DISPLAY);
if (display != null) {
// We need to tell AChoreographer instances the current refresh rate so that apps
@@ -1091,11 +1101,16 @@
}
}
- // Called from AChoreographer via JNI.
- // Unregisters AChoreographer from receiving refresh rate callbacks.
- private void unregisterNativeChoreographerForRefreshRateCallbacks() {
+ /**
+ * Called from AChoreographer via JNI.
+ * Unregisters AChoreographer from receiving refresh rate callbacks.
+ * Public for unit testing to be able to call this method.
+ */
+ @VisibleForTesting
+ public void unregisterNativeChoreographerForRefreshRateCallbacks() {
synchronized (mLock) {
mDispatchNativeCallbacks = false;
+ updateCallbackIfNeededLocked();
}
}
}
diff --git a/core/java/android/hardware/display/VirtualDisplay.java b/core/java/android/hardware/display/VirtualDisplay.java
index bf62c95..71cbd20 100644
--- a/core/java/android/hardware/display/VirtualDisplay.java
+++ b/core/java/android/hardware/display/VirtualDisplay.java
@@ -15,6 +15,8 @@
*/
package android.hardware.display;
+import android.annotation.Nullable;
+import android.content.Context;
import android.view.Display;
import android.view.Surface;
@@ -36,13 +38,19 @@
private final Display mDisplay;
private IVirtualDisplayCallback mToken;
private Surface mSurface;
+ /**
+ * Store the WindowContext in a field. If it is a local variable, and it is garbage collected
+ * during a MediaProjection session, the WindowContainer listener no longer exists.
+ */
+ @Nullable private final Context mWindowContext;
VirtualDisplay(DisplayManagerGlobal global, Display display,
- IVirtualDisplayCallback token, Surface surface) {
+ IVirtualDisplayCallback token, Surface surface, Context windowContext) {
mGlobal = global;
mDisplay = display;
mToken = token;
mSurface = surface;
+ mWindowContext = windowContext;
}
/**
diff --git a/core/java/android/hardware/face/FaceManager.java b/core/java/android/hardware/face/FaceManager.java
index 385ad2d..56f8142 100644
--- a/core/java/android/hardware/face/FaceManager.java
+++ b/core/java/android/hardware/face/FaceManager.java
@@ -58,7 +58,7 @@
public class FaceManager implements BiometricAuthenticator, BiometricFaceConstants {
private static final String TAG = "FaceManager";
- private static final boolean DEBUG = true;
+
private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_ACQUIRED = 101;
private static final int MSG_AUTHENTICATION_SUCCEEDED = 102;
@@ -207,13 +207,9 @@
throw new IllegalArgumentException("Must supply an authentication callback");
}
- if (cancel != null) {
- if (cancel.isCanceled()) {
- Slog.w(TAG, "authentication already canceled");
- return;
- } else {
- cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
- }
+ if (cancel != null && cancel.isCanceled()) {
+ Slog.w(TAG, "authentication already canceled");
+ return;
}
if (mService != null) {
@@ -223,17 +219,18 @@
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
Trace.beginSection("FaceManager#authenticate");
- mService.authenticate(mToken, operationId, userId, mServiceReceiver,
- mContext.getOpPackageName(), isKeyguardBypassEnabled);
+ final long authId = mService.authenticate(mToken, operationId, userId,
+ mServiceReceiver, mContext.getOpPackageName(), isKeyguardBypassEnabled);
+ if (cancel != null) {
+ cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+ }
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
- if (callback != null) {
- // Though this may not be a hardware issue, it will cause apps to give up or
- // try again later.
- callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
- getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
- 0 /* vendorCode */));
- }
+ // Though this may not be a hardware issue, it will cause apps to give up or
+ // try again later.
+ callback.onAuthenticationError(FACE_ERROR_HW_UNAVAILABLE,
+ getErrorString(mContext, FACE_ERROR_HW_UNAVAILABLE,
+ 0 /* vendorCode */));
} finally {
Trace.endSection();
}
@@ -255,14 +252,14 @@
if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled");
return;
- } else {
- cancel.setOnCancelListener(new OnFaceDetectionCancelListener());
}
mFaceDetectionCallback = callback;
try {
- mService.detectFace(mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+ final long authId = mService.detectFace(
+ mToken, userId, mServiceReceiver, mContext.getOpPackageName());
+ cancel.setOnCancelListener(new OnFaceDetectionCancelListener(authId));
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e);
}
@@ -726,23 +723,23 @@
}
}
- private void cancelAuthentication(CryptoObject cryptoObject) {
+ private void cancelAuthentication(long requestId) {
if (mService != null) {
try {
- mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+ mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
}
- private void cancelFaceDetect() {
+ private void cancelFaceDetect(long requestId) {
if (mService == null) {
return;
}
try {
- mService.cancelFaceDetect(mToken, mContext.getOpPackageName());
+ mService.cancelFaceDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -794,9 +791,9 @@
// This is used as a last resort in case a vendor string is missing
// It should not happen for anything other than FACE_ERROR_VENDOR, but
// warn and use the default if all else fails.
- // TODO(b/196639965): update string
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
- return "";
+ return context.getString(
+ com.android.internal.R.string.face_error_vendor_unknown);
}
/**
@@ -1110,22 +1107,30 @@
}
private class OnAuthenticationCancelListener implements OnCancelListener {
- private final CryptoObject mCrypto;
+ private final long mAuthRequestId;
- OnAuthenticationCancelListener(CryptoObject crypto) {
- mCrypto = crypto;
+ OnAuthenticationCancelListener(long id) {
+ mAuthRequestId = id;
}
@Override
public void onCancel() {
- cancelAuthentication(mCrypto);
+ Slog.d(TAG, "Cancel face authentication requested for: " + mAuthRequestId);
+ cancelAuthentication(mAuthRequestId);
}
}
private class OnFaceDetectionCancelListener implements OnCancelListener {
+ private final long mAuthRequestId;
+
+ OnFaceDetectionCancelListener(long id) {
+ mAuthRequestId = id;
+ }
+
@Override
public void onCancel() {
- cancelFaceDetect();
+ Slog.d(TAG, "Cancel face detect requested for: " + mAuthRequestId);
+ cancelFaceDetect(mAuthRequestId);
}
}
diff --git a/core/java/android/hardware/face/IFaceService.aidl b/core/java/android/hardware/face/IFaceService.aidl
index db02a0ef..e919824 100644
--- a/core/java/android/hardware/face/IFaceService.aidl
+++ b/core/java/android/hardware/face/IFaceService.aidl
@@ -44,34 +44,36 @@
// Retrieve static sensor properties for the specified sensor
FaceSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
- // Authenticate the given sessionId with a face
- void authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
+ // Authenticate with a face. A requestId is returned that can be used to cancel this operation.
+ long authenticate(IBinder token, long operationId, int userId, IFaceServiceReceiver receiver,
String opPackageName, boolean isKeyguardBypassEnabled);
// Uses the face hardware to detect for the presence of a face, without giving details
- // about accept/reject/lockout.
- void detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
+ // about accept/reject/lockout. A requestId is returned that can be used to cancel this
+ // operation.
+ long detectFace(IBinder token, int userId, IFaceServiceReceiver receiver, String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication.
// This is protected by the MANAGE_BIOMETRIC signatuer permission. This method should only be
// called from BiometricService. The additional uid, pid, userId arguments should be determined
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
- void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token, long operationId,
- int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
- int cookie, boolean allowBackgroundAuthentication);
+ void prepareForAuthentication(int sensorId, boolean requireConfirmation, IBinder token,
+ long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
+ String opPackageName, long requestId, int cookie,
+ boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie);
- // Cancel authentication for the given sessionId
- void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel authentication for the given requestId.
+ void cancelAuthentication(IBinder token, String opPackageName, long requestId);
- // Cancel face detection
- void cancelFaceDetect(IBinder token, String opPackageName);
+ // Cancel face detection for the given requestId.
+ void cancelFaceDetect(IBinder token, String opPackageName, long requestId);
// Same as above, with extra arguments.
- void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
// Start face enrollment
void enroll(int userId, IBinder token, in byte [] hardwareAuthToken, IFaceServiceReceiver receiver,
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 87d45b9..d48d562 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -189,22 +189,30 @@
}
private class OnAuthenticationCancelListener implements OnCancelListener {
- private android.hardware.biometrics.CryptoObject mCrypto;
+ private final long mAuthRequestId;
- public OnAuthenticationCancelListener(android.hardware.biometrics.CryptoObject crypto) {
- mCrypto = crypto;
+ OnAuthenticationCancelListener(long id) {
+ mAuthRequestId = id;
}
@Override
public void onCancel() {
- cancelAuthentication(mCrypto);
+ Slog.d(TAG, "Cancel fingerprint authentication requested for: " + mAuthRequestId);
+ cancelAuthentication(mAuthRequestId);
}
}
private class OnFingerprintDetectionCancelListener implements OnCancelListener {
+ private final long mAuthRequestId;
+
+ OnFingerprintDetectionCancelListener(long id) {
+ mAuthRequestId = id;
+ }
+
@Override
public void onCancel() {
- cancelFingerprintDetect();
+ Slog.d(TAG, "Cancel fingerprint detect requested for: " + mAuthRequestId);
+ cancelFingerprintDetect(mAuthRequestId);
}
}
@@ -552,13 +560,9 @@
throw new IllegalArgumentException("Must supply an authentication callback");
}
- if (cancel != null) {
- if (cancel.isCanceled()) {
- Slog.w(TAG, "authentication already canceled");
- return;
- } else {
- cancel.setOnCancelListener(new OnAuthenticationCancelListener(crypto));
- }
+ if (cancel != null && cancel.isCanceled()) {
+ Slog.w(TAG, "authentication already canceled");
+ return;
}
if (mService != null) {
@@ -567,8 +571,11 @@
mAuthenticationCallback = callback;
mCryptoObject = crypto;
final long operationId = crypto != null ? crypto.getOpId() : 0;
- mService.authenticate(mToken, operationId, sensorId, userId, mServiceReceiver,
- mContext.getOpPackageName());
+ final long authId = mService.authenticate(mToken, operationId, sensorId, userId,
+ mServiceReceiver, mContext.getOpPackageName());
+ if (cancel != null) {
+ cancel.setOnCancelListener(new OnAuthenticationCancelListener(authId));
+ }
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception while authenticating: ", e);
// Though this may not be a hardware issue, it will cause apps to give up or try
@@ -595,15 +602,14 @@
if (cancel.isCanceled()) {
Slog.w(TAG, "Detection already cancelled");
return;
- } else {
- cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener());
}
mFingerprintDetectionCallback = callback;
try {
- mService.detectFingerprint(mToken, userId, mServiceReceiver,
+ final long authId = mService.detectFingerprint(mToken, userId, mServiceReceiver,
mContext.getOpPackageName());
+ cancel.setOnCancelListener(new OnFingerprintDetectionCancelListener(authId));
} catch (RemoteException e) {
Slog.w(TAG, "Remote exception when requesting finger detect", e);
}
@@ -844,26 +850,6 @@
}
/**
- * Checks if the specified user has enrollments in any of the specified sensors.
- * @hide
- */
- @RequiresPermission(USE_BIOMETRIC_INTERNAL)
- public boolean hasEnrolledTemplatesForAnySensor(int userId,
- @NonNull List<FingerprintSensorPropertiesInternal> sensors) {
- if (mService == null) {
- Slog.w(TAG, "hasEnrolledTemplatesForAnySensor: no fingerprint service");
- return false;
- }
-
- try {
- return mService.hasEnrolledTemplatesForAnySensor(userId, sensors,
- mContext.getOpPackageName());
- } catch (RemoteException e) {
- throw e.rethrowFromSystemServer();
- }
- }
-
- /**
* @hide
*/
@RequiresPermission(USE_BIOMETRIC_INTERNAL)
@@ -1320,21 +1306,21 @@
}
}
- private void cancelAuthentication(android.hardware.biometrics.CryptoObject cryptoObject) {
+ private void cancelAuthentication(long requestId) {
if (mService != null) try {
- mService.cancelAuthentication(mToken, mContext.getOpPackageName());
+ mService.cancelAuthentication(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
- private void cancelFingerprintDetect() {
+ private void cancelFingerprintDetect(long requestId) {
if (mService == null) {
return;
}
try {
- mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName());
+ mService.cancelFingerprintDetect(mToken, mContext.getOpPackageName(), requestId);
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
@@ -1390,9 +1376,9 @@
// This is used as a last resort in case a vendor string is missing
// It should not happen for anything other than FINGERPRINT_ERROR_VENDOR, but
// warn and use the default if all else fails.
- // TODO(b/196639965): update string
Slog.w(TAG, "Invalid error message: " + errMsg + ", " + vendorCode);
- return "";
+ return context.getString(
+ com.android.internal.R.string.fingerprint_error_vendor_unknown);
}
/**
diff --git a/core/java/android/hardware/fingerprint/FingerprintStateListener.java b/core/java/android/hardware/fingerprint/FingerprintStateListener.java
index 6e607a2..cf914c5 100644
--- a/core/java/android/hardware/fingerprint/FingerprintStateListener.java
+++ b/core/java/android/hardware/fingerprint/FingerprintStateListener.java
@@ -49,5 +49,10 @@
* Defines behavior in response to state update
* @param newState new state of fingerprint sensor
*/
- public abstract void onStateChanged(@FingerprintStateListener.State int newState);
+ public void onStateChanged(@FingerprintStateListener.State int newState) {};
+
+ /**
+ * Invoked when enrollment state changes for the specified user
+ */
+ public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {};
}
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index 3979afe..de94b2f 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -48,15 +48,16 @@
// Retrieve static sensor properties for the specified sensor
FingerprintSensorPropertiesInternal getSensorProperties(int sensorId, String opPackageName);
- // Authenticate the given sessionId with a fingerprint. This is protected by
- // USE_FINGERPRINT/USE_BIOMETRIC permission. This is effectively deprecated, since it only comes
- // through FingerprintManager now.
- void authenticate(IBinder token, long operationId, int sensorId, int userId,
+ // Authenticate with a fingerprint. This is protected by USE_FINGERPRINT/USE_BIOMETRIC
+ // permission. This is effectively deprecated, since it only comes through FingerprintManager
+ // now. A requestId is returned that can be used to cancel this operation.
+ long authenticate(IBinder token, long operationId, int sensorId, int userId,
IFingerprintServiceReceiver receiver, String opPackageName);
// Uses the fingerprint hardware to detect for the presence of a finger, without giving details
- // about accept/reject/lockout.
- void detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
+ // about accept/reject/lockout. A requestId is returned that can be used to cancel this
+ // operation.
+ long detectFingerprint(IBinder token, int userId, IFingerprintServiceReceiver receiver,
String opPackageName);
// This method prepares the service to start authenticating, but doesn't start authentication.
@@ -65,21 +66,21 @@
// by BiometricService. To start authentication after the clients are ready, use
// startPreparedClient().
void prepareForAuthentication(int sensorId, IBinder token, long operationId, int userId,
- IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
- boolean allowBackgroundAuthentication);
+ IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
+ int cookie, boolean allowBackgroundAuthentication);
// Starts authentication with the previously prepared client.
void startPreparedClient(int sensorId, int cookie);
- // Cancel authentication for the given sessionId
- void cancelAuthentication(IBinder token, String opPackageName);
+ // Cancel authentication for the given requestId.
+ void cancelAuthentication(IBinder token, String opPackageName, long requestId);
- // Cancel finger detection
- void cancelFingerprintDetect(IBinder token, String opPackageName);
+ // Cancel finger detection for the given requestId.
+ void cancelFingerprintDetect(IBinder token, String opPackageName, long requestId);
// Same as above, except this is protected by the MANAGE_BIOMETRIC signature permission. Takes
// an additional uid, pid, userid.
- void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName);
+ void cancelAuthenticationFromService(int sensorId, IBinder token, String opPackageName, long requestId);
// Start fingerprint enrollment
void enroll(IBinder token, in byte [] hardwareAuthToken, int userId, IFingerprintServiceReceiver receiver,
@@ -119,9 +120,6 @@
// Determine if a user has at least one enrolled fingerprint.
boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName);
- // Determine if a user has at least one enrolled fingerprint in any of the specified sensors
- boolean hasEnrolledTemplatesForAnySensor(int userId, in List<FingerprintSensorPropertiesInternal> sensors, String opPackageName);
-
// Return the LockoutTracker status for the specified user
int getLockoutModeForUser(int sensorId, int userId);
diff --git a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
index 56dba7e..1aa6fa1 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintStateListener.aidl
@@ -24,4 +24,5 @@
*/
oneway interface IFingerprintStateListener {
void onStateChanged(int newState);
+ void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments);
}
diff --git a/core/java/android/os/GraphicsEnvironment.java b/core/java/android/os/GraphicsEnvironment.java
index be21fea..1cceea3 100644
--- a/core/java/android/os/GraphicsEnvironment.java
+++ b/core/java/android/os/GraphicsEnvironment.java
@@ -17,6 +17,7 @@
package android.os;
import android.app.Activity;
+import android.app.GameManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
@@ -26,8 +27,6 @@
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
-import android.content.res.AssetFileDescriptor;
-import android.content.res.AssetManager;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
@@ -37,9 +36,6 @@
import java.io.BufferedReader;
import java.io.File;
-import java.io.FileDescriptor;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
@@ -88,9 +84,6 @@
private static final String UPDATABLE_DRIVER_ALLOWLIST_ALL = "*";
private static final String UPDATABLE_DRIVER_SPHAL_LIBRARIES_FILENAME = "sphal_libraries.txt";
- // ANGLE related properties.
- private static final String ANGLE_RULES_FILE = "a4a_rules.json";
- private static final String ANGLE_TEMP_RULES = "debug.angle.rules";
private static final String ACTION_ANGLE_FOR_ANDROID = "android.app.action.ANGLE_FOR_ANDROID";
private static final String ACTION_ANGLE_FOR_ANDROID_TOAST_MESSAGE =
"android.app.action.ANGLE_FOR_ANDROID_TOAST_MESSAGE";
@@ -121,6 +114,7 @@
private ClassLoader mClassLoader;
private String mLibrarySearchPaths;
private String mLibraryPermittedPaths;
+ private GameManager mGameManager;
private int mAngleOptInIndex = -1;
@@ -133,6 +127,8 @@
final ApplicationInfo appInfoWithMetaData =
getAppInfoWithMetadata(context, pm, packageName);
+ mGameManager = context.getSystemService(GameManager.class);
+
Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "setupGpuLayers");
setupGpuLayers(context, coreSettings, pm, packageName, appInfoWithMetaData);
Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS);
@@ -151,6 +147,23 @@
}
/**
+ * Query to determine if the Game Mode has enabled ANGLE.
+ */
+ private boolean isAngleEnabledByGameMode(Context context, String packageName) {
+ try {
+ final boolean gameModeEnabledAngle =
+ (mGameManager != null) && mGameManager.isAngleEnabled(packageName);
+ Log.v(TAG, "ANGLE GameManagerService for " + packageName + ": " + gameModeEnabledAngle);
+ return gameModeEnabledAngle;
+ } catch (SecurityException e) {
+ Log.e(TAG, "Caught exception while querying GameManagerService if ANGLE is enabled "
+ + "for package: " + packageName);
+ }
+
+ return false;
+ }
+
+ /**
* Query to determine if ANGLE should be used
*/
private boolean shouldUseAngle(Context context, Bundle coreSettings,
@@ -164,21 +177,16 @@
Log.v(TAG, "ANGLE Developer option for '" + packageName + "' "
+ "set to: '" + devOptIn + "'");
- // We only want to use ANGLE if the app is in the allowlist, or the developer has
- // explicitly chosen something other than default driver.
- // The allowlist will be generated by the ANGLE APK at both boot time and
- // ANGLE update time. It will only include apps mentioned in the rules file.
- final boolean allowed = checkAngleAllowlist(context, coreSettings, packageName);
+ // We only want to use ANGLE if the developer has explicitly chosen something other than
+ // default driver.
final boolean requested = devOptIn.equals(ANGLE_GL_DRIVER_CHOICE_ANGLE);
-
- if (allowed) {
- Log.v(TAG, "ANGLE allowlist includes " + packageName);
- }
if (requested) {
Log.v(TAG, "ANGLE developer option for " + packageName + ": " + devOptIn);
}
- return allowed || requested;
+ final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
+
+ return requested || gameModeEnabledAngle;
}
private int getVulkanVersion(PackageManager pm) {
@@ -475,117 +483,6 @@
}
/**
- * Attempt to setup ANGLE with a temporary rules file.
- * True: Temporary rules file was loaded.
- * False: Temporary rules file was *not* loaded.
- */
- private boolean setupAngleWithTempRulesFile(Context context,
- String packageName,
- String paths,
- String devOptIn) {
- /**
- * We only want to load a temp rules file for:
- * - apps that are marked 'debuggable' in their manifest
- * - devices that are running a userdebug build (ro.debuggable) or can inject libraries for
- * debugging (PR_SET_DUMPABLE).
- */
- if (!isDebuggable()) {
- Log.v(TAG, "Skipping loading temporary rules file");
- return false;
- }
-
- final String angleTempRules = SystemProperties.get(ANGLE_TEMP_RULES);
-
- if (TextUtils.isEmpty(angleTempRules)) {
- Log.v(TAG, "System property '" + ANGLE_TEMP_RULES + "' is not set or is empty");
- return false;
- }
-
- Log.i(TAG, "Detected system property " + ANGLE_TEMP_RULES + ": " + angleTempRules);
-
- final File tempRulesFile = new File(angleTempRules);
- if (tempRulesFile.exists()) {
- Log.i(TAG, angleTempRules + " exists, loading file.");
- try {
- final FileInputStream stream = new FileInputStream(angleTempRules);
-
- try {
- final FileDescriptor rulesFd = stream.getFD();
- final long rulesOffset = 0;
- final long rulesLength = stream.getChannel().size();
- Log.i(TAG, "Loaded temporary ANGLE rules from " + angleTempRules);
-
- setAngleInfo(paths, packageName, devOptIn, null,
- rulesFd, rulesOffset, rulesLength);
-
- stream.close();
-
- // We successfully setup ANGLE, so return with good status
- return true;
- } catch (IOException e) {
- Log.w(TAG, "Hit IOException thrown by FileInputStream: " + e);
- }
- } catch (FileNotFoundException e) {
- Log.w(TAG, "Temp ANGLE rules file not found: " + e);
- } catch (SecurityException e) {
- Log.w(TAG, "Temp ANGLE rules file not accessible: " + e);
- }
- }
-
- return false;
- }
-
- /**
- * Attempt to setup ANGLE with a rules file loaded from the ANGLE APK.
- * True: APK rules file was loaded.
- * False: APK rules file was *not* loaded.
- */
- private boolean setupAngleRulesApk(String anglePkgName,
- ApplicationInfo angleInfo,
- PackageManager pm,
- String packageName,
- String paths,
- String devOptIn,
- String[] features) {
- // Pass the rules file to loader for ANGLE decisions
- try {
- final AssetManager angleAssets = pm.getResourcesForApplication(angleInfo).getAssets();
-
- try {
- final AssetFileDescriptor assetsFd = angleAssets.openFd(ANGLE_RULES_FILE);
-
- setAngleInfo(paths, packageName, devOptIn, features, assetsFd.getFileDescriptor(),
- assetsFd.getStartOffset(), assetsFd.getLength());
-
- assetsFd.close();
-
- return true;
- } catch (IOException e) {
- Log.w(TAG, "Failed to get AssetFileDescriptor for " + ANGLE_RULES_FILE
- + " from '" + anglePkgName + "': " + e);
- }
- } catch (PackageManager.NameNotFoundException e) {
- Log.w(TAG, "Failed to get AssetManager for '" + anglePkgName + "': " + e);
- }
-
- return false;
- }
-
- /**
- * Pull ANGLE allowlist from GlobalSettings and compare against current package
- */
- private boolean checkAngleAllowlist(Context context, Bundle bundle, String packageName) {
- final ContentResolver contentResolver = context.getContentResolver();
- final List<String> angleAllowlist =
- getGlobalSettingsString(contentResolver, bundle,
- Settings.Global.ANGLE_ALLOWLIST);
-
- if (DEBUG) Log.v(TAG, "ANGLE allowlist: " + angleAllowlist);
-
- return angleAllowlist.contains(packageName);
- }
-
- /**
* Pass ANGLE details down to trigger enable logic
*
* @param context
@@ -647,28 +544,21 @@
if (DEBUG) Log.v(TAG, "ANGLE package libs: " + paths);
- // If the user has set the developer option to something other than default,
- // we need to call setupAngleRulesApk() with the package name and the developer
- // option value (native/angle/other). Then later when we are actually trying to
- // load a driver, GraphicsEnv::getShouldUseAngle() has seen the package name before
- // and can confidently answer yes/no based on the previously set developer
- // option value.
- final String devOptIn = getDriverForPackage(context, bundle, packageName);
-
- if (setupAngleWithTempRulesFile(context, packageName, paths, devOptIn)) {
- // We setup ANGLE with a temp rules file, so we're done here.
- return true;
+ // We need to call setAngleInfo() with the package name and the developer option value
+ //(native/angle/other). Then later when we are actually trying to load a driver,
+ //GraphicsEnv::getShouldUseAngle() has seen the package name before and can confidently
+ //answer yes/no based on the previously set developer option value.
+ final String devOptIn;
+ final String[] features = getAngleEglFeatures(context, bundle);
+ final boolean gameModeEnabledAngle = isAngleEnabledByGameMode(context, packageName);
+ if (gameModeEnabledAngle) {
+ devOptIn = ANGLE_GL_DRIVER_CHOICE_ANGLE;
+ } else {
+ devOptIn = getDriverForPackage(context, bundle, packageName);
}
+ setAngleInfo(paths, packageName, devOptIn, features);
- String[] features = getAngleEglFeatures(context, bundle);
-
- if (setupAngleRulesApk(
- anglePkgName, angleInfo, pm, packageName, paths, devOptIn, features)) {
- // ANGLE with rules is set up from the APK, hence return.
- return true;
- }
-
- return false;
+ return true;
}
/**
@@ -956,7 +846,7 @@
private static native void setGpuStats(String driverPackageName, String driverVersionName,
long driverVersionCode, long driverBuildTime, String appPackageName, int vulkanVersion);
private static native void setAngleInfo(String path, String appPackage, String devOptIn,
- String[] features, FileDescriptor rulesFd, long rulesOffset, long rulesLength);
+ String[] features);
private static native boolean getShouldUseAngle(String packageName);
private static native boolean setInjectLayersPrSetDumpable();
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 94d19bc..ab13e2e 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -28,12 +28,14 @@
import android.annotation.SystemApi;
import android.annotation.TestApi;
import android.annotation.UserIdInt;
+import android.app.Activity;
import android.app.ActivityThread;
import android.app.AppOpsManager;
import android.app.Application;
import android.app.AutomaticZenRule;
import android.app.NotificationChannel;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.SearchManager;
import android.app.WallpaperManager;
import android.compat.annotation.UnsupportedAppUsage;
@@ -11911,6 +11913,13 @@
public static final String WIFI_MIGRATION_COMPLETED = "wifi_migration_completed";
/**
+ * Whether UWB should be enabled.
+ * @hide
+ */
+ @Readable
+ public static final String UWB_ENABLED = "uwb_enabled";
+
+ /**
* Value to specify whether network quality scores and badging should be shown in the UI.
*
* Type: int (0 for false, 1 for true)
@@ -13736,13 +13745,6 @@
"angle_gl_driver_selection_values";
/**
- * List of package names that should check ANGLE rules
- * @hide
- */
- @Readable
- public static final String ANGLE_ALLOWLIST = "angle_allowlist";
-
- /**
* Lists of ANGLE EGL features for debugging.
* Each list of features is separated by a comma, each feature in each list is separated by
* a colon.
@@ -16942,6 +16944,54 @@
"android.settings.MANAGE_APP_ALL_FILES_ACCESS_PERMISSION";
/**
+ * Activity Action: For system or preinstalled apps to show their {@link Activity} in 2-pane
+ * mode in Settings app on large screen devices.
+ * <p>
+ * Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI} must be included to
+ * specify the intent for the activity which will be displayed in 2-pane mode in Settings app.
+ * It's an intent URI string from {@code intent.toUri(Intent.URI_INTENT_SCHEME)}.
+ *
+ * Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY} must be included to
+ * specify a key that indicates the menu item which will be highlighted on settings home menu.
+ *
+ * Input: {@link #EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT} is optional. Apps
+ * can use the {@link PendingIntent} extra to launch into its private {@link Activity}.
+ * <p>
+ * Output: Nothing.
+ */
+ @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+ public static final String ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK =
+ "android.settings.SETTINGS_LARGE_SCREEN_DEEP_LINK";
+
+ /**
+ * Activity Extra: Specify the intent for the {@link Activity} which will be displayed in 2-pane
+ * mode in Settings app. It's an intent URI string from
+ * {@code intent.toUri(Intent.URI_INTENT_SCHEME)}.
+ * <p>
+ * This must be passed as an extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}.
+ */
+ public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI =
+ "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_INTENT_URI";
+
+ /**
+ * Activity Extra: Specify a key that indicates the menu item which should be highlighted on
+ * settings home menu.
+ * <p>
+ * This must be passed as an extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}.
+ */
+ public static final String EXTRA_SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY =
+ "android.provider.extra.SETTINGS_LARGE_SCREEN_HIGHLIGHT_MENU_KEY";
+
+ /**
+ * Activity Extra: Apps can use the {@link PendingIntent} extra to launch into its private
+ * {@link Activity}.
+ * <p>
+ * This is an optional extra field to {@link #ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK}.
+ */
+ public static final String EXTRA_SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT =
+ "android.provider.extra.SETTINGS_LARGE_SCREEN_DEEP_LINK_PENDING_INTENT";
+
+ /**
* Performs a strict and comprehensive check of whether a calling package is allowed to
* write/modify system settings, as the condition differs for pre-M, M+, and
* privileged/preinstalled apps. If the provided uid does not match the
diff --git a/core/java/android/util/DisplayUtils.java b/core/java/android/util/DisplayUtils.java
new file mode 100644
index 0000000..4fe7f83
--- /dev/null
+++ b/core/java/android/util/DisplayUtils.java
@@ -0,0 +1,54 @@
+/*
+ * 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 android.util;
+
+import android.content.res.Resources;
+
+import com.android.internal.R;
+
+/**
+ * Utils for loading resources for multi-display.
+ *
+ * @hide
+ */
+public class DisplayUtils {
+
+ /**
+ * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
+ * which is used to get the related cutout configs for that display.
+ *
+ * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
+ * display if there are different type of cutouts on each display.
+ * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
+ * and the system will load the default configs for main built-in display.
+ */
+ public static int getDisplayUniqueIdConfigIndex(Resources res, String displayUniqueId) {
+ int index = -1;
+ if (displayUniqueId == null || displayUniqueId.isEmpty()) {
+ return index;
+ }
+ final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
+ final int size = ids.length;
+ for (int i = 0; i < size; i++) {
+ if (displayUniqueId.equals(ids[i])) {
+ index = i;
+ break;
+ }
+ }
+ return index;
+ }
+}
diff --git a/core/java/android/util/imetracing/ImeTracingServerImpl.java b/core/java/android/util/imetracing/ImeTracingServerImpl.java
index 06e4c50..d605430 100644
--- a/core/java/android/util/imetracing/ImeTracingServerImpl.java
+++ b/core/java/android/util/imetracing/ImeTracingServerImpl.java
@@ -41,9 +41,9 @@
*/
class ImeTracingServerImpl extends ImeTracing {
private static final String TRACE_DIRNAME = "/data/misc/wmtrace/";
- private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.pb";
- private static final String TRACE_FILENAME_IMS = "ime_trace_service.pb";
- private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.pb";
+ private static final String TRACE_FILENAME_CLIENTS = "ime_trace_clients.winscope";
+ private static final String TRACE_FILENAME_IMS = "ime_trace_service.winscope";
+ private static final String TRACE_FILENAME_IMMS = "ime_trace_managerservice.winscope";
private static final int BUFFER_CAPACITY = 4096 * 1024;
// Needed for winscope to auto-detect the dump type. Explained further in
diff --git a/core/java/android/view/DisplayCutout.java b/core/java/android/view/DisplayCutout.java
index 0257e55..c1a5636 100644
--- a/core/java/android/view/DisplayCutout.java
+++ b/core/java/android/view/DisplayCutout.java
@@ -39,6 +39,7 @@
import android.os.Parcel;
import android.os.Parcelable;
import android.text.TextUtils;
+import android.util.DisplayUtils;
import android.util.Pair;
import android.util.RotationUtils;
import android.util.proto.ProtoOutputStream;
@@ -874,38 +875,13 @@
}
/**
- * Gets the index of the given display unique id in {@link R.array#config_displayUniqueIdArray}
- * which is used to get the related cutout configs for that display.
- *
- * For multi-display device, {@link R.array#config_displayUniqueIdArray} should be set for each
- * display if there are different type of cutouts on each display.
- * For single display device, {@link R.array#config_displayUniqueIdArray} should not to be set
- * and the system will load the default configs for main built-in display.
- */
- private static int getDisplayCutoutConfigIndex(Resources res, String displayUniqueId) {
- int index = -1;
- if (displayUniqueId == null || displayUniqueId.isEmpty()) {
- return index;
- }
- final String[] ids = res.getStringArray(R.array.config_displayUniqueIdArray);
- final int size = ids.length;
- for (int i = 0; i < size; i++) {
- if (displayUniqueId.equals(ids[i])) {
- index = i;
- break;
- }
- }
- return index;
- }
-
- /**
* Gets the display cutout by the given display unique id.
*
* Loads the default config {@link R.string#config_mainBuiltInDisplayCutout) if
* {@link R.array#config_displayUniqueIdArray} is not set.
*/
private static String getDisplayCutoutPath(Resources res, String displayUniqueId) {
- final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
final String[] array = res.getStringArray(R.array.config_displayCutoutPathArray);
if (index >= 0 && index < array.length) {
return array[index];
@@ -920,7 +896,7 @@
* {@link R.array#config_displayUniqueIdArray} is not set.
*/
private static String getDisplayCutoutApproximationRect(Resources res, String displayUniqueId) {
- final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
final String[] array = res.getStringArray(
R.array.config_displayCutoutApproximationRectArray);
if (index >= 0 && index < array.length) {
@@ -939,7 +915,7 @@
* @hide
*/
public static boolean getMaskBuiltInDisplayCutout(Resources res, String displayUniqueId) {
- final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
final TypedArray array = res.obtainTypedArray(R.array.config_maskBuiltInDisplayCutoutArray);
boolean maskCutout;
if (index >= 0 && index < array.length()) {
@@ -961,7 +937,7 @@
* @hide
*/
public static boolean getFillBuiltInDisplayCutout(Resources res, String displayUniqueId) {
- final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
final TypedArray array = res.obtainTypedArray(R.array.config_fillBuiltInDisplayCutoutArray);
boolean fillCutout;
if (index >= 0 && index < array.length()) {
@@ -984,7 +960,7 @@
*/
private static Insets getWaterfallInsets(Resources res, String displayUniqueId) {
Insets insets;
- final int index = getDisplayCutoutConfigIndex(res, displayUniqueId);
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
final TypedArray array = res.obtainTypedArray(R.array.config_waterfallCutoutArray);
if (index >= 0 && index < array.length() && array.getResourceId(index, 0) > 0) {
final int resourceId = array.getResourceId(index, 0);
diff --git a/core/java/android/view/IDisplayWindowListener.aidl b/core/java/android/view/IDisplayWindowListener.aidl
index 610e0f8..f95d6b3 100644
--- a/core/java/android/view/IDisplayWindowListener.aidl
+++ b/core/java/android/view/IDisplayWindowListener.aidl
@@ -32,7 +32,8 @@
oneway interface IDisplayWindowListener {
/**
- * Called when a display is added to the WM hierarchy.
+ * Called when a new display is added to the WM hierarchy. The existing display ids are returned
+ * when this listener is registered with WM via {@link #registerDisplayWindowListener}.
*/
void onDisplayAdded(int displayId);
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 9ce4122..52d57cf 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -521,9 +521,10 @@
void unregisterDisplayFoldListener(IDisplayFoldListener listener);
/**
- * Registers an IDisplayContainerListener
+ * Registers an IDisplayContainerListener, and returns the set of existing display ids. The
+ * listener's onDisplayAdded() will not be called for the displays returned.
*/
- void registerDisplayWindowListener(IDisplayWindowListener listener);
+ int[] registerDisplayWindowListener(IDisplayWindowListener listener);
/**
* Unregisters an IDisplayContainerListener.
diff --git a/core/java/android/view/InsetsAnimationControlCallbacks.java b/core/java/android/view/InsetsAnimationControlCallbacks.java
index 3431c3e..04bb609 100644
--- a/core/java/android/view/InsetsAnimationControlCallbacks.java
+++ b/core/java/android/view/InsetsAnimationControlCallbacks.java
@@ -20,7 +20,8 @@
import android.view.WindowInsetsAnimation.Bounds;
/**
- * Provide an interface to let InsetsAnimationControlImpl call back into its owner.
+ * Provide an interface to let InsetsAnimationControlImpl and InsetsResizeAnimationRunner call back
+ * into its owner.
* @hide
*/
public interface InsetsAnimationControlCallbacks {
@@ -34,10 +35,9 @@
* <li>Dispatch {@link WindowInsetsAnimationControlListener#onReady}</li>
* </ul>
*/
- void startAnimation(InsetsAnimationControlImpl controller,
- WindowInsetsAnimationControlListener listener, int types,
- WindowInsetsAnimation animation,
- Bounds bounds);
+ <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+ void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
+ WindowInsetsAnimation animation, Bounds bounds);
/**
* Schedule the apply by posting the animation callback.
diff --git a/core/java/android/view/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 17b3020..7d8d653 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -69,7 +69,7 @@
* @hide
*/
@VisibleForTesting
-public class InsetsAnimationControlImpl implements WindowInsetsAnimationController,
+public class InsetsAnimationControlImpl implements InternalInsetsAnimationController,
InsetsAnimationControlRunner {
private static final String TAG = "InsetsAnimationCtrlImpl";
@@ -105,7 +105,7 @@
private float mCurrentAlpha = 1.0f;
private float mPendingAlpha = 1.0f;
@VisibleForTesting(visibility = PACKAGE)
- public boolean mReadyDispatched;
+ private boolean mReadyDispatched;
private Boolean mPerceptible;
@VisibleForTesting
@@ -170,6 +170,11 @@
}
@Override
+ public void setReadyDispatched(boolean dispatched) {
+ mReadyDispatched = dispatched;
+ }
+
+ @Override
public Insets getHiddenStateInsets() {
return mHiddenInsets;
}
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 691e638..fc97541 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -54,8 +54,8 @@
@Override
@UiThread
- public void startAnimation(InsetsAnimationControlImpl controller,
- WindowInsetsAnimationControlListener listener, int types,
+ public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+ void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation, Bounds bounds) {
// Animation will be started in constructor already.
}
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index acdaa52..adda721 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -205,6 +205,9 @@
private static final int ANIMATION_DURATION_FADE_IN_MS = 500;
private static final int ANIMATION_DURATION_FADE_OUT_MS = 1500;
+ /** Visible for WindowManagerWrapper */
+ public static final int ANIMATION_DURATION_RESIZE = 300;
+
private static final int ANIMATION_DELAY_DIM_MS = 500;
private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
@@ -235,6 +238,9 @@
private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
new PathInterpolator(0.4f, 0f, 1f, 1f);
+ /** Visible for WindowManagerWrapper */
+ public static final Interpolator RESIZE_INTERPOLATOR = new LinearInterpolator();
+
/** The amount IME will move up/down when animating in floating mode. */
private static final int FLOATING_IME_BOTTOM_INSET_DP = -80;
@@ -288,9 +294,13 @@
@VisibleForTesting
public static final int ANIMATION_TYPE_USER = 2;
+ /** Running animation will resize insets */
+ @VisibleForTesting
+ public static final int ANIMATION_TYPE_RESIZE = 3;
+
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {ANIMATION_TYPE_NONE, ANIMATION_TYPE_SHOW, ANIMATION_TYPE_HIDE,
- ANIMATION_TYPE_USER})
+ ANIMATION_TYPE_USER, ANIMATION_TYPE_RESIZE})
@interface AnimationType {
}
@@ -320,7 +330,7 @@
private final boolean mDisable;
private final int mFloatingImeBottomInset;
- private ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
+ private final ThreadLocal<AnimationHandler> mSfAnimationHandlerThreadLocal =
new ThreadLocal<AnimationHandler>() {
@Override
protected AnimationHandler initialValue() {
@@ -550,7 +560,6 @@
private final SparseArray<InsetsSourceControl> mTmpControlArray = new SparseArray<>();
private final ArrayList<RunningAnimation> mRunningAnimations = new ArrayList<>();
- private final ArrayList<InsetsAnimationControlImpl> mTmpFinishedControls = new ArrayList<>();
private final ArraySet<InsetsSourceConsumer> mRequestedVisibilityChanged = new ArraySet<>();
private WindowInsets mLastInsets;
@@ -570,7 +579,7 @@
private int mCaptionInsetsHeight = 0;
private boolean mAnimationsDisabled;
- private Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
+ private final Runnable mPendingControlTimeout = this::abortPendingImeControlRequest;
private final ArrayList<OnControllableInsetsChangedListener> mControllableInsetsChangedListeners
= new ArrayList<>();
@@ -580,7 +589,7 @@
/** Set of inset types which cannot be controlled by the user animation */
private @InsetsType int mDisabledUserAnimationInsetsTypes;
- private Runnable mInvokeControllableInsetsChangedListeners =
+ private final Runnable mInvokeControllableInsetsChangedListeners =
this::invokeControllableInsetsChangedListeners;
public InsetsController(Host host) {
@@ -608,23 +617,23 @@
}
final List<WindowInsetsAnimation> runningAnimations = new ArrayList<>();
+ final List<WindowInsetsAnimation> finishedAnimations = new ArrayList<>();
final InsetsState state = new InsetsState(mState, true /* copySources */);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
if (DEBUG) Log.d(TAG, "Running animation type: " + runningAnimation.type);
- InsetsAnimationControlRunner runner = runningAnimation.runner;
- if (runner instanceof InsetsAnimationControlImpl) {
- InsetsAnimationControlImpl control = (InsetsAnimationControlImpl) runner;
+ final InsetsAnimationControlRunner runner = runningAnimation.runner;
+ if (runner instanceof WindowInsetsAnimationController) {
// Keep track of running animation to be dispatched. Aggregate it here such that
// if it gets finished within applyChangeInsets we still dispatch it to
// onProgress.
if (runningAnimation.startDispatched) {
- runningAnimations.add(control.getAnimation());
+ runningAnimations.add(runner.getAnimation());
}
- if (control.applyChangeInsets(state)) {
- mTmpFinishedControls.add(control);
+ if (((InternalInsetsAnimationController) runner).applyChangeInsets(state)) {
+ finishedAnimations.add(runner.getAnimation());
}
}
}
@@ -642,10 +651,9 @@
}
}
- for (int i = mTmpFinishedControls.size() - 1; i >= 0; i--) {
- dispatchAnimationEnd(mTmpFinishedControls.get(i).getAnimation());
+ for (int i = finishedAnimations.size() - 1; i >= 0; i--) {
+ dispatchAnimationEnd(finishedAnimations.get(i));
}
- mTmpFinishedControls.clear();
};
}
@@ -691,15 +699,13 @@
true /* excludeInvisibleIme */)) {
if (DEBUG) Log.d(TAG, "onStateChanged, notifyInsetsChanged");
mHost.notifyInsetsChanged();
+ startResizingAnimationIfNeeded(lastState);
}
return true;
}
private void updateState(InsetsState newState) {
- mState.setDisplayFrame(newState.getDisplayFrame());
- mState.setDisplayCutout(newState.getDisplayCutout());
- mState.setRoundedCorners(newState.getRoundedCorners());
- mState.setPrivacyIndicatorBounds(newState.getPrivacyIndicatorBounds());
+ mState.set(newState, 0 /* types */);
@InsetsType int disabledUserAnimationTypes = 0;
@InsetsType int[] cancelledUserAnimationTypes = {0};
for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
@@ -764,6 +770,39 @@
return false;
}
+ private void startResizingAnimationIfNeeded(InsetsState fromState) {
+ if (!fromState.getDisplayFrame().equals(mState.getDisplayFrame())) {
+ return;
+ }
+ @InsetsType int types = 0;
+ InsetsState toState = null;
+ final ArraySet<Integer> internalTypes = InsetsState.toInternalType(Type.systemBars());
+ for (int i = internalTypes.size() - 1; i >= 0; i--) {
+ final @InternalInsetsType int type = internalTypes.valueAt(i);
+ final InsetsSource fromSource = fromState.peekSource(type);
+ final InsetsSource toSource = mState.peekSource(type);
+ if (fromSource != null && toSource != null
+ && fromSource.isVisible() && toSource.isVisible()
+ && !fromSource.getFrame().equals(toSource.getFrame())
+ && (Rect.intersects(mFrame, fromSource.getFrame())
+ || Rect.intersects(mFrame, toSource.getFrame()))) {
+ types |= InsetsState.toPublicType(toSource.getType());
+ if (toState == null) {
+ toState = new InsetsState();
+ }
+ toState.addSource(new InsetsSource(toSource));
+ }
+ }
+ if (types == 0) {
+ return;
+ }
+ cancelExistingControllers(types);
+ final InsetsAnimationControlRunner runner = new InsetsResizeAnimationRunner(
+ mFrame, fromState, toState, RESIZE_INTERPOLATOR, ANIMATION_DURATION_RESIZE, types,
+ this);
+ mRunningAnimations.add(new RunningAnimation(runner, runner.getAnimationType()));
+ }
+
/**
* @see InsetsState#calculateInsets
*/
@@ -785,7 +824,7 @@
/**
* @see InsetsState#calculateVisibleInsets(Rect, int)
*/
- public Rect calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
+ public Insets calculateVisibleInsets(@SoftInputModeFlags int softInputMode) {
return mState.calculateVisibleInsets(mFrame, softInputMode);
}
@@ -1474,12 +1513,12 @@
@VisibleForTesting
@Override
- public void startAnimation(InsetsAnimationControlImpl controller,
- WindowInsetsAnimationControlListener listener, int types,
+ public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+ void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation, Bounds bounds) {
mHost.dispatchWindowInsetsAnimationPrepare(animation);
mHost.addOnPreDrawRunnable(() -> {
- if (controller.isCancelled()) {
+ if (runner.isCancelled()) {
if (WARN) Log.w(TAG, "startAnimation canceled before preDraw");
return;
}
@@ -1487,15 +1526,15 @@
"InsetsAnimation: " + WindowInsets.Type.toString(types), types);
for (int i = mRunningAnimations.size() - 1; i >= 0; i--) {
RunningAnimation runningAnimation = mRunningAnimations.get(i);
- if (runningAnimation.runner == controller) {
+ if (runningAnimation.runner == runner) {
runningAnimation.startDispatched = true;
}
}
Trace.asyncTraceEnd(TRACE_TAG_VIEW, "IC.pendingAnim", 0);
mHost.dispatchWindowInsetsAnimationStart(animation, bounds);
mStartingAnimation = true;
- controller.mReadyDispatched = true;
- listener.onReady(controller, types);
+ runner.setReadyDispatched(true);
+ listener.onReady(runner, types);
mStartingAnimation = false;
});
}
diff --git a/core/java/android/view/InsetsResizeAnimationRunner.java b/core/java/android/view/InsetsResizeAnimationRunner.java
new file mode 100644
index 0000000..e1352dd
--- /dev/null
+++ b/core/java/android/view/InsetsResizeAnimationRunner.java
@@ -0,0 +1,235 @@
+/*
+ * 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 android.view;
+
+import static android.view.InsetsAnimationControlImplProto.CURRENT_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.IS_CANCELLED;
+import static android.view.InsetsAnimationControlImplProto.IS_FINISHED;
+import static android.view.InsetsAnimationControlImplProto.PENDING_ALPHA;
+import static android.view.InsetsAnimationControlImplProto.PENDING_FRACTION;
+import static android.view.InsetsAnimationControlImplProto.PENDING_INSETS;
+import static android.view.InsetsAnimationControlImplProto.SHOWN_ON_FINISH;
+import static android.view.InsetsAnimationControlImplProto.TMP_MATRIX;
+import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ValueAnimator;
+import android.graphics.Insets;
+import android.graphics.Rect;
+import android.util.SparseArray;
+import android.util.proto.ProtoOutputStream;
+import android.view.InsetsState.InternalInsetsType;
+import android.view.WindowInsets.Type.InsetsType;
+import android.view.WindowInsetsAnimation.Bounds;
+import android.view.animation.Interpolator;
+
+/**
+ * Runs a fake animation of resizing insets to produce insets animation callbacks.
+ * @hide
+ */
+public class InsetsResizeAnimationRunner implements InsetsAnimationControlRunner,
+ InternalInsetsAnimationController, WindowInsetsAnimationControlListener {
+
+ private final InsetsState mFromState;
+ private final InsetsState mToState;
+ private final @InsetsType int mTypes;
+ private final WindowInsetsAnimation mAnimation;
+ private final InsetsAnimationControlCallbacks mController;
+ private ValueAnimator mAnimator;
+ private boolean mCancelled;
+ private boolean mFinished;
+
+ public InsetsResizeAnimationRunner(Rect frame, InsetsState fromState, InsetsState toState,
+ Interpolator interpolator, long duration, @InsetsType int types,
+ InsetsAnimationControlCallbacks controller) {
+ mFromState = fromState;
+ mToState = toState;
+ mTypes = types;
+ mController = controller;
+ mAnimation = new WindowInsetsAnimation(types, interpolator, duration);
+ mAnimation.setAlpha(1f);
+ final Insets fromInsets = fromState.calculateInsets(
+ frame, types, false /* ignoreVisibility */);
+ final Insets toInsets = toState.calculateInsets(
+ frame, types, false /* ignoreVisibility */);
+ controller.startAnimation(this, this, types, mAnimation,
+ new Bounds(Insets.min(fromInsets, toInsets), Insets.max(fromInsets, toInsets)));
+ }
+
+ @Override
+ public int getTypes() {
+ return mTypes;
+ }
+
+ @Override
+ public int getControllingTypes() {
+ return mTypes;
+ }
+
+ @Override
+ public WindowInsetsAnimation getAnimation() {
+ return mAnimation;
+ }
+
+ @Override
+ public int getAnimationType() {
+ return ANIMATION_TYPE_RESIZE;
+ }
+
+ @Override
+ public void cancel() {
+ if (mCancelled || mFinished) {
+ return;
+ }
+ mCancelled = true;
+ if (mAnimator != null) {
+ mAnimator.cancel();
+ }
+ }
+
+ @Override
+ public boolean isCancelled() {
+ return mCancelled;
+ }
+
+ @Override
+ public void onReady(WindowInsetsAnimationController controller, int types) {
+ if (mCancelled) {
+ return;
+ }
+ mAnimator = ValueAnimator.ofFloat(0f, 1f);
+ mAnimator.setDuration(mAnimation.getDurationMillis());
+ mAnimator.addUpdateListener(animation -> {
+ mAnimation.setFraction(animation.getAnimatedFraction());
+ mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
+ });
+ mAnimator.addListener(new AnimatorListenerAdapter() {
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mFinished = true;
+ mController.scheduleApplyChangeInsets(InsetsResizeAnimationRunner.this);
+ }
+ });
+ mAnimator.start();
+ }
+
+ @Override
+ public boolean applyChangeInsets(InsetsState outState) {
+ final float fraction = mAnimation.getInterpolatedFraction();
+ for (@InternalInsetsType int type = 0; type < InsetsState.SIZE; type++) {
+ final InsetsSource fromSource = mFromState.peekSource(type);
+ final InsetsSource toSource = mToState.peekSource(type);
+ if (fromSource == null || toSource == null) {
+ continue;
+ }
+ final Rect fromFrame = fromSource.getFrame();
+ final Rect toFrame = toSource.getFrame();
+ final Rect frame = new Rect(
+ (int) (fromFrame.left + fraction * (toFrame.left - fromFrame.left)),
+ (int) (fromFrame.top + fraction * (toFrame.top - fromFrame.top)),
+ (int) (fromFrame.right + fraction * (toFrame.right - fromFrame.right)),
+ (int) (fromFrame.bottom + fraction * (toFrame.bottom - fromFrame.bottom)));
+ final InsetsSource source = new InsetsSource(type);
+ source.setFrame(frame);
+ source.setVisible(toSource.isVisible());
+ outState.addSource(source);
+ }
+ if (mFinished) {
+ mController.notifyFinished(this, true /* shown */);
+ }
+ return mFinished;
+ }
+
+ @Override
+ public void dumpDebug(ProtoOutputStream proto, long fieldId) {
+ final long token = proto.start(fieldId);
+ proto.write(IS_CANCELLED, mCancelled);
+ proto.write(IS_FINISHED, mFinished);
+ proto.write(TMP_MATRIX, "null");
+ proto.write(PENDING_INSETS, "null");
+ proto.write(PENDING_FRACTION, mAnimation.getInterpolatedFraction());
+ proto.write(SHOWN_ON_FINISH, true);
+ proto.write(CURRENT_ALPHA, 1f);
+ proto.write(PENDING_ALPHA, 1f);
+ proto.end(token);
+ }
+
+ @Override
+ public Insets getHiddenStateInsets() {
+ return Insets.NONE;
+ }
+
+ @Override
+ public Insets getShownStateInsets() {
+ return Insets.NONE;
+ }
+
+ @Override
+ public Insets getCurrentInsets() {
+ return Insets.NONE;
+ }
+
+ @Override
+ public float getCurrentFraction() {
+ return 0;
+ }
+
+ @Override
+ public float getCurrentAlpha() {
+ return 0;
+ }
+
+ @Override
+ public void setInsetsAndAlpha(Insets insets, float alpha, float fraction) {
+ }
+
+ @Override
+ public void finish(boolean shown) {
+ }
+
+ @Override
+ public boolean isFinished() {
+ return false;
+ }
+
+ @Override
+ public void notifyControlRevoked(int types) {
+ }
+
+ @Override
+ public void updateSurfacePosition(SparseArray<InsetsSourceControl> controls) {
+ }
+
+ @Override
+ public boolean hasZeroInsetsIme() {
+ return false;
+ }
+
+ @Override
+ public void setReadyDispatched(boolean dispatched) {
+ }
+
+ @Override
+ public void onFinished(WindowInsetsAnimationController controller) {
+ }
+
+ @Override
+ public void onCancelled(WindowInsetsAnimationController controller) {
+ }
+}
diff --git a/core/java/android/view/InsetsSourceControl.java b/core/java/android/view/InsetsSourceControl.java
index 1506ee4..9d98a3e 100644
--- a/core/java/android/view/InsetsSourceControl.java
+++ b/core/java/android/view/InsetsSourceControl.java
@@ -185,6 +185,15 @@
return result;
}
+ @Override
+ public String toString() {
+ return "InsetsSourceControl: {"
+ + "type=" + InsetsState.typeToString(mType)
+ + ", mSurfacePosition=" + mSurfacePosition
+ + ", mInsetsHint=" + mInsetsHint
+ + "}";
+ }
+
public void dump(String prefix, PrintWriter pw) {
pw.print(prefix);
pw.print("InsetsSourceControl type="); pw.print(InsetsState.typeToString(mType));
diff --git a/core/java/android/view/InsetsState.java b/core/java/android/view/InsetsState.java
index f4444a1..75b69cb 100644
--- a/core/java/android/view/InsetsState.java
+++ b/core/java/android/view/InsetsState.java
@@ -301,7 +301,7 @@
return mPrivacyIndicatorBounds.inset(insetLeft, insetTop, insetRight, insetBottom);
}
- public Rect calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
+ public Insets calculateInsets(Rect frame, @InsetsType int types, boolean ignoreVisibility) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources[type];
@@ -314,10 +314,10 @@
}
insets = Insets.max(source.calculateInsets(frame, ignoreVisibility), insets);
}
- return insets.toRect();
+ return insets;
}
- public Rect calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
+ public Insets calculateVisibleInsets(Rect frame, @SoftInputModeFlags int softInputMode) {
Insets insets = Insets.NONE;
for (int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
InsetsSource source = mSources[type];
@@ -332,7 +332,7 @@
}
insets = Insets.max(source.calculateVisibleInsets(frame), insets);
}
- return insets.toRect();
+ return insets;
}
/**
diff --git a/core/java/android/view/InternalInsetsAnimationController.java b/core/java/android/view/InternalInsetsAnimationController.java
new file mode 100644
index 0000000..d7f3e20
--- /dev/null
+++ b/core/java/android/view/InternalInsetsAnimationController.java
@@ -0,0 +1,41 @@
+/*
+ * 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 android.view;
+
+/**
+ * An internal interface which provides methods that will be only used by the framework.
+ * @hide
+ */
+public interface InternalInsetsAnimationController extends WindowInsetsAnimationController {
+
+ /**
+ * Flags whether {@link WindowInsetsAnimationControlListener#onReady(
+ * WindowInsetsAnimationController, int)} has been invoked.
+ * @hide
+ */
+ void setReadyDispatched(boolean dispatched);
+
+ /**
+ * Returns the {@link InsetsState} based on the current animation progress.
+ *
+ * @param outState the insets state which matches the current animation progress.
+ * @return {@code true} if the animation has been finished; {@code false} otherwise.
+ * @hide
+ */
+ boolean applyChangeInsets(InsetsState outState);
+}
+
diff --git a/core/java/android/view/RemoteAnimationTarget.java b/core/java/android/view/RemoteAnimationTarget.java
index bd68401..3f71d4d 100644
--- a/core/java/android/view/RemoteAnimationTarget.java
+++ b/core/java/android/view/RemoteAnimationTarget.java
@@ -233,7 +233,7 @@
this.clipRect = new Rect(clipRect);
this.contentInsets = new Rect(contentInsets);
this.prefixOrderIndex = prefixOrderIndex;
- this.position = new Point(position);
+ this.position = position == null ? new Point() : new Point(position);
this.localBounds = new Rect(localBounds);
this.sourceContainerBounds = new Rect(screenSpaceBounds);
this.screenSpaceBounds = new Rect(screenSpaceBounds);
diff --git a/core/java/android/view/RoundedCorners.java b/core/java/android/view/RoundedCorners.java
index 623d969..6079d8e 100644
--- a/core/java/android/view/RoundedCorners.java
+++ b/core/java/android/view/RoundedCorners.java
@@ -27,9 +27,11 @@
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Point;
import android.os.Parcel;
import android.os.Parcelable;
+import android.util.DisplayUtils;
import android.util.Pair;
import android.view.RoundedCorner.Position;
@@ -94,8 +96,8 @@
* @android:dimen/rounded_corner_radius_top and @android:dimen/rounded_corner_radius_bottom
*/
public static RoundedCorners fromResources(
- Resources res, int displayWidth, int displayHeight) {
- return fromRadii(loadRoundedCornerRadii(res), displayWidth, displayHeight);
+ Resources res, String displayUniqueId, int displayWidth, int displayHeight) {
+ return fromRadii(loadRoundedCornerRadii(res, displayUniqueId), displayWidth, displayHeight);
}
/**
@@ -140,14 +142,16 @@
* Loads the rounded corner radii from resources.
*
* @param res
+ * @param displayUniqueId the display unique id.
* @return a Pair of radius. The first is the top rounded corner radius and second is the
* bottom corner radius.
*/
@Nullable
- private static Pair<Integer, Integer> loadRoundedCornerRadii(Resources res) {
- final int radiusDefault = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
- final int radiusTop = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top);
- final int radiusBottom = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom);
+ private static Pair<Integer, Integer> loadRoundedCornerRadii(
+ Resources res, String displayUniqueId) {
+ final int radiusDefault = getRoundedCornerRadius(res, displayUniqueId);
+ final int radiusTop = getRoundedCornerTopRadius(res, displayUniqueId);
+ final int radiusBottom = getRoundedCornerBottomRadius(res, displayUniqueId);
if (radiusDefault == 0 && radiusTop == 0 && radiusBottom == 0) {
return null;
}
@@ -158,6 +162,164 @@
}
/**
+ * Gets the default rounded corner radius of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerRadius(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerRadiusArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets the top rounded corner radius of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius_top} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerTopRadius(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopRadiusArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets the bottom rounded corner radius of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerBottomRadius(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerBottomRadiusArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets the rounded corner radius adjustment of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius_adjustment} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerRadiusAdjustment(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerRadiusAdjustmentArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_adjustment);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets the rounded corner top radius adjustment of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius_top_adjustment} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerRadiusTopAdjustment(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerTopRadiusAdjustmentArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_top_adjustment);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets the rounded corner bottom radius adjustment of a display which is determined by the
+ * given display unique id.
+ *
+ * Loads the default dimen{@link R.dimen#rounded_corner_radius_bottom_adjustment} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static int getRoundedCornerRadiusBottomAdjustment(
+ Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerBottomRadiusAdjustmentArray);
+ int radius;
+ if (index >= 0 && index < array.length()) {
+ radius = array.getDimensionPixelSize(index, 0);
+ } else {
+ radius = res.getDimensionPixelSize(R.dimen.rounded_corner_radius_bottom_adjustment);
+ }
+ array.recycle();
+ return radius;
+ }
+
+ /**
+ * Gets whether a built-in display is round.
+ *
+ * Loads the default config{@link R.bool#config_mainBuiltInDisplayIsRound} if
+ * {@link R.array#config_displayUniqueIdArray} is not set.
+ *
+ * @hide
+ */
+ public static boolean getBuiltInDisplayIsRound(Resources res, String displayUniqueId) {
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_builtInDisplayIsRoundArray);
+ boolean isRound;
+ if (index >= 0 && index < array.length()) {
+ isRound = array.getBoolean(index, false);
+ } else {
+ isRound = res.getBoolean(R.bool.config_mainBuiltInDisplayIsRound);
+ }
+ array.recycle();
+ return isRound;
+ }
+
+ /**
* Insets the reference frame of the rounded corners.
*
* @return a copy of this instance which has been inset
diff --git a/core/java/android/view/Surface.java b/core/java/android/view/Surface.java
index aaf53ee..904aa73 100644
--- a/core/java/android/view/Surface.java
+++ b/core/java/android/view/Surface.java
@@ -99,6 +99,7 @@
private static native int nativeSetFrameRate(
long nativeObject, float frameRate, int compatibility, int changeFrameRateStrategy);
+ private static native void nativeDestroy(long nativeObject);
public static final @android.annotation.NonNull Parcelable.Creator<Surface> CREATOR =
new Parcelable.Creator<Surface>() {
@@ -340,6 +341,9 @@
*/
@UnsupportedAppUsage
public void destroy() {
+ if (mNativeObject != 0) {
+ nativeDestroy(mNativeObject);
+ }
release();
}
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index a4e7a43..51910e0 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -903,7 +903,7 @@
mSurfaceAlpha = 1f;
synchronized (mSurfaceControlLock) {
- mSurface.release();
+ mSurface.destroy();
if (mBlastBufferQueue != null) {
mBlastBufferQueue.destroy();
mBlastBufferQueue = null;
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 04d65c0..4c36fc9 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -2467,7 +2467,7 @@
mAttachInfo.mContentInsets.set(mLastWindowInsets.getSystemWindowInsets().toRect());
mAttachInfo.mStableInsets.set(mLastWindowInsets.getStableInsets().toRect());
mAttachInfo.mVisibleInsets.set(mInsetsController.calculateVisibleInsets(
- mWindowAttributes.softInputMode));
+ mWindowAttributes.softInputMode).toRect());
}
return mLastWindowInsets;
}
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index f57e520..3ce3fab 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -3531,6 +3531,14 @@
public Insets providedInternalInsets = Insets.NONE;
/**
+ * If specified, the insets provided by this window for the IME will be our window frame
+ * minus the insets specified by providedInternalImeInsets.
+ *
+ * @hide
+ */
+ public Insets providedInternalImeInsets = Insets.NONE;
+
+ /**
* {@link LayoutParams} to be applied to the window when layout with a assigned rotation.
* This will make layout during rotation change smoothly.
*
@@ -3904,6 +3912,7 @@
out.writeInt(0);
}
providedInternalInsets.writeToParcel(out, 0 /* parcelableFlags */);
+ providedInternalImeInsets.writeToParcel(out, 0 /* parcelableFlags */);
if (paramsForRotation != null) {
checkNonRecursiveParams();
out.writeInt(paramsForRotation.length);
@@ -3983,6 +3992,7 @@
in.readIntArray(providesInsetsTypes);
}
providedInternalInsets = Insets.CREATOR.createFromParcel(in);
+ providedInternalImeInsets = Insets.CREATOR.createFromParcel(in);
int paramsForRotationLength = in.readInt();
if (paramsForRotationLength > 0) {
paramsForRotation = new LayoutParams[paramsForRotationLength];
@@ -4289,6 +4299,11 @@
changes |= LAYOUT_CHANGED;
}
+ if (!providedInternalImeInsets.equals(o.providedInternalImeInsets)) {
+ providedInternalImeInsets = o.providedInternalImeInsets;
+ changes |= LAYOUT_CHANGED;
+ }
+
if (!Arrays.equals(paramsForRotation, o.paramsForRotation)) {
paramsForRotation = o.paramsForRotation;
checkNonRecursiveParams();
@@ -4494,6 +4509,10 @@
sb.append(" providedInternalInsets=");
sb.append(providedInternalInsets);
}
+ if (!providedInternalImeInsets.equals(Insets.NONE)) {
+ sb.append(" providedInternalImeInsets=");
+ sb.append(providedInternalImeInsets);
+ }
if (paramsForRotation != null && paramsForRotation.length != 0) {
sb.append(System.lineSeparator());
sb.append(prefix).append(" paramsForRotation=");
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 91fc5a5..fe5eb08 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -740,6 +740,16 @@
}
@Override
+ public UserHandle getUser() {
+ return mContextForResources.getUser();
+ }
+
+ @Override
+ public int getUserId() {
+ return mContextForResources.getUserId();
+ }
+
+ @Override
public boolean isRestricted() {
// Override isRestricted and direct to resource's implementation. The isRestricted is
// used for determining the risky resources loading, e.g. fonts, thus direct to context
diff --git a/core/java/android/window/ITaskFragmentOrganizerController.aidl b/core/java/android/window/ITaskFragmentOrganizerController.aidl
index 0ca8a86..1ad0452 100644
--- a/core/java/android/window/ITaskFragmentOrganizerController.aidl
+++ b/core/java/android/window/ITaskFragmentOrganizerController.aidl
@@ -16,6 +16,7 @@
package android.window;
+import android.view.RemoteAnimationDefinition;
import android.window.ITaskFragmentOrganizer;
/** @hide */
@@ -30,4 +31,17 @@
* Unregisters a previously registered TaskFragmentOrganizer.
*/
void unregisterOrganizer(in ITaskFragmentOrganizer organizer);
+
+ /**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments.
+ */
+ void registerRemoteAnimations(in ITaskFragmentOrganizer organizer,
+ in RemoteAnimationDefinition definition);
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ */
+ void unregisterRemoteAnimations(in ITaskFragmentOrganizer organizer);
}
diff --git a/core/java/android/window/RemoteTransition.aidl b/core/java/android/window/RemoteTransition.aidl
new file mode 100644
index 0000000..f3c3f54
--- /dev/null
+++ b/core/java/android/window/RemoteTransition.aidl
@@ -0,0 +1,19 @@
+/*
+ * 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 android.window;
+
+parcelable RemoteTransition;
diff --git a/core/java/android/window/RemoteTransition.java b/core/java/android/window/RemoteTransition.java
new file mode 100644
index 0000000..b243b65
--- /dev/null
+++ b/core/java/android/window/RemoteTransition.java
@@ -0,0 +1,158 @@
+/*
+ * 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 android.window;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.os.IBinder;
+import android.os.Parcelable;
+
+import com.android.internal.util.DataClass;
+
+/**
+ * Represents a remote transition animation and information required to run it (eg. the app thread
+ * that needs to be boosted).
+ * @hide
+ */
+@DataClass(genToString = true, genSetters = true, genAidl = true)
+public class RemoteTransition implements Parcelable {
+
+ /** The actual remote-transition interface used to run the transition animation. */
+ private @NonNull IRemoteTransition mRemoteTransition;
+
+ /** Get the IBinder associated with the underlying IRemoteTransition. */
+ public @Nullable IBinder asBinder() {
+ return mRemoteTransition.asBinder();
+ }
+
+
+
+ // Code below generated by codegen v1.0.23.
+ //
+ // DO NOT MODIFY!
+ // CHECKSTYLE:OFF Generated code
+ //
+ // To regenerate run:
+ // $ codegen $ANDROID_BUILD_TOP/frameworks/base/core/java/android/window/RemoteTransition.java
+ //
+ // To exclude the generated code from IntelliJ auto-formatting enable (one-time):
+ // Settings > Editor > Code Style > Formatter Control
+ //@formatter:off
+
+
+ /**
+ * Creates a new RemoteTransition.
+ *
+ * @param remoteTransition
+ * The actual remote-transition interface used to run the transition animation.
+ */
+ @DataClass.Generated.Member
+ public RemoteTransition(
+ @NonNull IRemoteTransition remoteTransition) {
+ this.mRemoteTransition = remoteTransition;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRemoteTransition);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ /**
+ * The actual remote-transition interface used to run the transition animation.
+ */
+ @DataClass.Generated.Member
+ public @NonNull IRemoteTransition getRemoteTransition() {
+ return mRemoteTransition;
+ }
+
+ /**
+ * The actual remote-transition interface used to run the transition animation.
+ */
+ @DataClass.Generated.Member
+ public @NonNull RemoteTransition setRemoteTransition(@NonNull IRemoteTransition value) {
+ mRemoteTransition = value;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRemoteTransition);
+ return this;
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public String toString() {
+ // You can override field toString logic by defining methods like:
+ // String fieldNameToString() { ... }
+
+ return "RemoteTransition { " +
+ "remoteTransition = " + mRemoteTransition +
+ " }";
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public void writeToParcel(@NonNull android.os.Parcel dest, int flags) {
+ // You can override field parcelling by defining methods like:
+ // void parcelFieldName(Parcel dest, int flags) { ... }
+
+ dest.writeStrongInterface(mRemoteTransition);
+ }
+
+ @Override
+ @DataClass.Generated.Member
+ public int describeContents() { return 0; }
+
+ /** @hide */
+ @SuppressWarnings({"unchecked", "RedundantCast"})
+ @DataClass.Generated.Member
+ protected RemoteTransition(@NonNull android.os.Parcel in) {
+ // You can override field unparcelling by defining methods like:
+ // static FieldType unparcelFieldName(Parcel in) { ... }
+
+ IRemoteTransition remoteTransition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+
+ this.mRemoteTransition = remoteTransition;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mRemoteTransition);
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public static final @NonNull Parcelable.Creator<RemoteTransition> CREATOR
+ = new Parcelable.Creator<RemoteTransition>() {
+ @Override
+ public RemoteTransition[] newArray(int size) {
+ return new RemoteTransition[size];
+ }
+
+ @Override
+ public RemoteTransition createFromParcel(@NonNull android.os.Parcel in) {
+ return new RemoteTransition(in);
+ }
+ };
+
+ @DataClass.Generated(
+ time = 1630613039043L,
+ codegenVersion = "1.0.23",
+ sourceFile = "frameworks/base/core/java/android/window/RemoteTransition.java",
+ inputSignatures = "private @android.annotation.NonNull android.window.IRemoteTransition mRemoteTransition\npublic @android.annotation.Nullable android.os.IBinder asBinder()\nclass RemoteTransition extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+ @Deprecated
+ private void __metadata() {}
+
+
+ //@formatter:on
+ // End of generated code
+
+}
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index acf20d7..f14294e 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -59,6 +59,7 @@
import java.time.Duration;
import java.time.Instant;
+import java.util.function.Consumer;
/**
* <p>The view which allows an activity to customize its splash screen exit animation.</p>
@@ -144,6 +145,7 @@
private Bitmap mParceledBrandingBitmap;
private Instant mIconAnimationStart;
private Duration mIconAnimationDuration;
+ private Consumer<Runnable> mUiThreadInitTask;
public Builder(@NonNull Context context) {
mContext = context;
@@ -232,6 +234,15 @@
}
/**
+ * Set the Runnable that can receive the task which should be executed on UI thread.
+ * @param uiThreadInitTask
+ */
+ public Builder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+ mUiThreadInitTask = uiThreadInitTask;
+ return this;
+ }
+
+ /**
* Set the Drawable object and size for the branding view.
*/
public Builder setBrandingDrawable(@Nullable Drawable branding, int width, int height) {
@@ -262,7 +273,11 @@
// center icon
if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
|| mSurfacePackage != null) {
- view.mIconView = createSurfaceView(view);
+ if (mUiThreadInitTask != null) {
+ mUiThreadInitTask.accept(() -> view.mIconView = createSurfaceView(view));
+ } else {
+ view.mIconView = createSurfaceView(view);
+ }
view.initIconAnimation(mIconDrawable,
mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
view.mIconAnimationStart = mIconAnimationStart;
@@ -316,7 +331,9 @@
}
private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
- final SurfaceView surfaceView = new SurfaceView(view.getContext());
+ Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "SplashScreenView#createSurfaceView");
+ final Context viewContext = view.getContext();
+ final SurfaceView surfaceView = new SurfaceView(viewContext);
surfaceView.setPadding(0, 0, 0, 0);
surfaceView.setBackground(mIconBackground);
if (mSurfacePackage == null) {
@@ -326,10 +343,10 @@
+ Thread.currentThread().getId());
}
- SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext,
- mContext.getDisplay(),
+ SurfaceControlViewHost viewHost = new SurfaceControlViewHost(viewContext,
+ viewContext.getDisplay(),
surfaceView.getHostToken());
- ImageView imageView = new ImageView(mContext);
+ ImageView imageView = new ImageView(viewContext);
imageView.setBackground(mIconDrawable);
viewHost.setView(imageView, mIconSize, mIconSize);
SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
@@ -360,6 +377,7 @@
view.addView(surfaceView);
view.mSurfaceView = surfaceView;
+ Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
return surfaceView;
}
}
@@ -531,17 +549,14 @@
private void releaseAnimationSurfaceHost() {
if (mSurfaceHost != null && !mIsCopied) {
- final SurfaceControlViewHost finalSurfaceHost = mSurfaceHost;
+ if (DEBUG) {
+ Log.d(TAG,
+ "Shell removed splash screen."
+ + " Releasing SurfaceControlViewHost on thread #"
+ + Thread.currentThread().getId());
+ }
+ releaseIconHost(mSurfaceHost);
mSurfaceHost = null;
- finalSurfaceHost.getView().post(() -> {
- if (DEBUG) {
- Log.d(TAG,
- "Shell removed splash screen."
- + " Releasing SurfaceControlViewHost on thread #"
- + Thread.currentThread().getId());
- }
- finalSurfaceHost.release();
- });
} else if (mSurfacePackage != null && mSurfaceHost == null) {
mSurfacePackage = null;
mClientCallback.sendResult(null);
@@ -549,6 +564,18 @@
}
/**
+ * Release the host which hold the SurfaceView of the icon.
+ * @hide
+ */
+ public static void releaseIconHost(SurfaceControlViewHost host) {
+ final Drawable background = host.getView().getBackground();
+ if (background instanceof SplashScreenView.IconAnimateListener) {
+ ((SplashScreenView.IconAnimateListener) background).stopAnimation();
+ }
+ host.release();
+ }
+
+ /**
* Called when this view is attached to an activity. This also makes SystemUI colors
* transparent so the content of splash screen view can draw fully.
*
@@ -639,6 +666,11 @@
* @return true if this drawable object can also be animated and it can be played now.
*/
boolean prepareAnimate(long duration, Runnable startListener);
+
+ /**
+ * Stop animation.
+ */
+ void stopAnimation();
}
/**
diff --git a/core/java/android/window/TaskFragmentInfo.java b/core/java/android/window/TaskFragmentInfo.java
index dac420b..b55372b 100644
--- a/core/java/android/window/TaskFragmentInfo.java
+++ b/core/java/android/window/TaskFragmentInfo.java
@@ -55,8 +55,8 @@
/** Whether the TaskFragment contains any child Window Container. */
private final boolean mIsEmpty;
- /** Whether the TaskFragment contains any running Activity. */
- private final boolean mHasRunningActivity;
+ /** The number of the running activities in the TaskFragment. */
+ private final int mRunningActivityCount;
/** Whether this TaskFragment is visible on the window hierarchy. */
private final boolean mIsVisible;
@@ -74,13 +74,13 @@
/** @hide */
public TaskFragmentInfo(
@NonNull IBinder fragmentToken, @NonNull WindowContainerToken token,
- @NonNull Configuration configuration, boolean isEmpty, boolean hasRunningActivity,
+ @NonNull Configuration configuration, boolean isEmpty, int runningActivityCount,
boolean isVisible, @NonNull List<IBinder> activities, @NonNull Point positionInParent) {
mFragmentToken = requireNonNull(fragmentToken);
mToken = requireNonNull(token);
mConfiguration.setTo(configuration);
mIsEmpty = isEmpty;
- mHasRunningActivity = hasRunningActivity;
+ mRunningActivityCount = runningActivityCount;
mIsVisible = isVisible;
mActivities.addAll(activities);
mPositionInParent = requireNonNull(positionInParent);
@@ -106,7 +106,11 @@
}
public boolean hasRunningActivity() {
- return mHasRunningActivity;
+ return mRunningActivityCount > 0;
+ }
+
+ public int getRunningActivityCount() {
+ return mRunningActivityCount;
}
public boolean isVisible() {
@@ -141,7 +145,7 @@
return mFragmentToken.equals(that.mFragmentToken)
&& mToken.equals(that.mToken)
&& mIsEmpty == that.mIsEmpty
- && mHasRunningActivity == that.mHasRunningActivity
+ && mRunningActivityCount == that.mRunningActivityCount
&& mIsVisible == that.mIsVisible
&& getWindowingMode() == that.getWindowingMode()
&& mActivities.equals(that.mActivities)
@@ -153,7 +157,7 @@
mToken = in.readTypedObject(WindowContainerToken.CREATOR);
mConfiguration.readFromParcel(in);
mIsEmpty = in.readBoolean();
- mHasRunningActivity = in.readBoolean();
+ mRunningActivityCount = in.readInt();
mIsVisible = in.readBoolean();
in.readBinderList(mActivities);
mPositionInParent = requireNonNull(in.readTypedObject(Point.CREATOR));
@@ -166,7 +170,7 @@
dest.writeTypedObject(mToken, flags);
mConfiguration.writeToParcel(dest, flags);
dest.writeBoolean(mIsEmpty);
- dest.writeBoolean(mHasRunningActivity);
+ dest.writeInt(mRunningActivityCount);
dest.writeBoolean(mIsVisible);
dest.writeBinderList(mActivities);
dest.writeTypedObject(mPositionInParent, flags);
@@ -192,7 +196,7 @@
+ " fragmentToken=" + mFragmentToken
+ " token=" + mToken
+ " isEmpty=" + mIsEmpty
- + " hasRunningActivity=" + mHasRunningActivity
+ + " runningActivityCount=" + mRunningActivityCount
+ " isVisible=" + mIsVisible
+ " positionInParent=" + mPositionInParent
+ "}";
diff --git a/core/java/android/window/TaskFragmentOrganizer.java b/core/java/android/window/TaskFragmentOrganizer.java
index f22f0b2..337c5a1 100644
--- a/core/java/android/window/TaskFragmentOrganizer.java
+++ b/core/java/android/window/TaskFragmentOrganizer.java
@@ -23,6 +23,7 @@
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
+import android.view.RemoteAnimationDefinition;
import java.util.concurrent.Executor;
@@ -90,6 +91,34 @@
}
}
+ /**
+ * Registers remote animations per transition type for the organizer. It will override the
+ * animations if the transition only contains windows that belong to the organized
+ * TaskFragments.
+ * @hide
+ */
+ @CallSuper
+ public void registerRemoteAnimations(@NonNull RemoteAnimationDefinition definition) {
+ try {
+ getController().registerRemoteAnimations(mInterface, definition);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
+ /**
+ * Unregisters remote animations per transition type for the organizer.
+ * @hide
+ */
+ @CallSuper
+ public void unregisterRemoteAnimations() {
+ try {
+ getController().unregisterRemoteAnimations(mInterface);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+
/** Called when a TaskFragment is created and organized by this organizer. */
public void onTaskFragmentAppeared(
@NonNull TaskFragmentAppearedInfo taskFragmentAppearedInfo) {}
diff --git a/core/java/android/window/TransitionRequestInfo.java b/core/java/android/window/TransitionRequestInfo.java
index cc493ab..f770731 100644
--- a/core/java/android/window/TransitionRequestInfo.java
+++ b/core/java/android/window/TransitionRequestInfo.java
@@ -40,11 +40,11 @@
private @Nullable ActivityManager.RunningTaskInfo mTriggerTask;
/** If non-null, a remote-transition associated with the source of this transition. */
- private @Nullable IRemoteTransition mRemoteTransition;
+ private @Nullable RemoteTransition mRemoteTransition;
- // Code below generated by codegen v1.0.22.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -72,7 +72,7 @@
public TransitionRequestInfo(
@WindowManager.TransitionType int type,
@Nullable ActivityManager.RunningTaskInfo triggerTask,
- @Nullable IRemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition) {
this.mType = type;
com.android.internal.util.AnnotationValidations.validate(
WindowManager.TransitionType.class, null, mType);
@@ -103,7 +103,7 @@
* If non-null, a remote-transition associated with the source of this transition.
*/
@DataClass.Generated.Member
- public @Nullable IRemoteTransition getRemoteTransition() {
+ public @Nullable RemoteTransition getRemoteTransition() {
return mRemoteTransition;
}
@@ -121,7 +121,7 @@
* If non-null, a remote-transition associated with the source of this transition.
*/
@DataClass.Generated.Member
- public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull IRemoteTransition value) {
+ public @android.annotation.NonNull TransitionRequestInfo setRemoteTransition(@android.annotation.NonNull RemoteTransition value) {
mRemoteTransition = value;
return this;
}
@@ -151,7 +151,7 @@
dest.writeByte(flg);
dest.writeInt(mType);
if (mTriggerTask != null) dest.writeTypedObject(mTriggerTask, flags);
- if (mRemoteTransition != null) dest.writeStrongInterface(mRemoteTransition);
+ if (mRemoteTransition != null) dest.writeTypedObject(mRemoteTransition, flags);
}
@Override
@@ -168,7 +168,7 @@
byte flg = in.readByte();
int type = in.readInt();
ActivityManager.RunningTaskInfo triggerTask = (flg & 0x2) == 0 ? null : (ActivityManager.RunningTaskInfo) in.readTypedObject(ActivityManager.RunningTaskInfo.CREATOR);
- IRemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+ RemoteTransition remoteTransition = (flg & 0x4) == 0 ? null : (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR);
this.mType = type;
com.android.internal.util.AnnotationValidations.validate(
@@ -194,10 +194,10 @@
};
@DataClass.Generated(
- time = 1610060387917L,
- codegenVersion = "1.0.22",
+ time = 1629321632222L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/core/java/android/window/TransitionRequestInfo.java",
- inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.IRemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
+ inputSignatures = "private final @android.view.WindowManager.TransitionType int mType\nprivate @android.annotation.Nullable android.app.ActivityManager.RunningTaskInfo mTriggerTask\nprivate @android.annotation.Nullable android.window.RemoteTransition mRemoteTransition\nclass TransitionRequestInfo extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genToString=true, genSetters=true, genAidl=true)")
@Deprecated
private void __metadata() {}
diff --git a/core/java/com/android/internal/jank/FrameTracker.java b/core/java/com/android/internal/jank/FrameTracker.java
index aa7142e..c863292 100644
--- a/core/java/com/android/internal/jank/FrameTracker.java
+++ b/core/java/com/android/internal/jank/FrameTracker.java
@@ -51,6 +51,7 @@
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
+import java.util.concurrent.TimeUnit;
/**
* A class that allows the app to get the frame metrics from HardwareRendererObserver.
@@ -108,6 +109,7 @@
private boolean mCancelled = false;
private FrameTrackerListener mListener;
private boolean mTracingStarted = false;
+ private Runnable mWaitForFinishTimedOut;
private static class JankInfo {
long frameVsyncId;
@@ -174,52 +176,51 @@
// If the surface isn't valid yet, wait until it's created.
if (mViewRoot.getSurfaceControl().isValid()) {
mSurfaceControl = mViewRoot.getSurfaceControl();
- mSurfaceChangedCallback = null;
- } else {
- mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
- @Override
- public void surfaceCreated(SurfaceControl.Transaction t) {
- synchronized (FrameTracker.this) {
- if (mSurfaceControl == null) {
- mSurfaceControl = mViewRoot.getSurfaceControl();
- if (mBeginVsyncId != INVALID_ID) {
- mSurfaceControlWrapper.addJankStatsListener(
- FrameTracker.this, mSurfaceControl);
- postTraceStartMarker();
- }
+ }
+
+ mSurfaceChangedCallback = new ViewRootImpl.SurfaceChangedCallback() {
+ @Override
+ public void surfaceCreated(SurfaceControl.Transaction t) {
+ synchronized (FrameTracker.this) {
+ if (mSurfaceControl == null) {
+ mSurfaceControl = mViewRoot.getSurfaceControl();
+ if (mBeginVsyncId != INVALID_ID) {
+ mSurfaceControlWrapper.addJankStatsListener(
+ FrameTracker.this, mSurfaceControl);
+ postTraceStartMarker();
}
}
}
+ }
- @Override
- public void surfaceReplaced(SurfaceControl.Transaction t) {
- }
+ @Override
+ public void surfaceReplaced(SurfaceControl.Transaction t) {
+ }
- @Override
- public void surfaceDestroyed() {
+ @Override
+ public void surfaceDestroyed() {
- // Wait a while to give the system a chance for the remaining
- // frames to arrive, then force finish the session.
- mHandler.postDelayed(() -> {
- synchronized (FrameTracker.this) {
- if (DEBUG) {
- Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
- + ", finalized=" + mMetricsFinalized
- + ", info=" + mJankInfos.size()
- + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
- }
- if (!mMetricsFinalized) {
- end(REASON_END_SURFACE_DESTROYED);
- finish(mJankInfos.size() - 1);
- }
+ // Wait a while to give the system a chance for the remaining
+ // frames to arrive, then force finish the session.
+ mHandler.postDelayed(() -> {
+ synchronized (FrameTracker.this) {
+ if (DEBUG) {
+ Log.d(TAG, "surfaceDestroyed: " + mSession.getName()
+ + ", finalized=" + mMetricsFinalized
+ + ", info=" + mJankInfos.size()
+ + ", vsync=" + mBeginVsyncId + "-" + mEndVsyncId);
}
- }, 50);
- }
- };
- // This callback has a reference to FrameTracker,
- // remember to remove it to avoid leakage.
- mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback);
- }
+ if (!mMetricsFinalized) {
+ end(REASON_END_SURFACE_DESTROYED);
+ finish(mJankInfos.size() - 1);
+ }
+ }
+ }, 50);
+ }
+ };
+ // This callback has a reference to FrameTracker,
+ // remember to remove it to avoid leakage.
+ mViewRoot.addSurfaceChangedCallback(mSurfaceChangedCallback);
}
}
@@ -283,10 +284,17 @@
if (mListener != null) {
mListener.onCujEvents(mSession, ACTION_SESSION_END);
}
+
+ // We don't remove observer here,
+ // will remove it when all the frame metrics in this duration are called back.
+ // See onFrameMetricsAvailable for the logic of removing the observer.
+ // Waiting at most 10 seconds for all callbacks to finish.
+ mWaitForFinishTimedOut = () -> {
+ Log.e(TAG, "force finish cuj because of time out:" + mSession.getName());
+ finish(mJankInfos.size() - 1);
+ };
+ mHandler.postDelayed(mWaitForFinishTimedOut, TimeUnit.SECONDS.toMillis(10));
}
- // We don't remove observer here,
- // will remove it when all the frame metrics in this duration are called back.
- // See onFrameMetricsAvailable for the logic of removing the observer.
}
/**
@@ -423,7 +431,8 @@
}
private void finish(int indexOnOrAfterEnd) {
-
+ mHandler.removeCallbacks(mWaitForFinishTimedOut);
+ mWaitForFinishTimedOut = null;
mMetricsFinalized = true;
// The tracing has been ended, remove the observer, see if need to trigger perfetto.
@@ -509,7 +518,7 @@
}
}
if (DEBUG) {
- Log.i(TAG, "FrameTracker: CUJ=" + mSession.getName()
+ Log.i(TAG, "finish: CUJ=" + mSession.getName()
+ " (" + mBeginVsyncId + "," + mEndVsyncId + ")"
+ " totalFrames=" + totalFramesCount
+ " missedAppFrames=" + missedAppFramesCount
diff --git a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
index 52172cf..ec62839 100644
--- a/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
+++ b/core/java/com/android/internal/policy/ScreenDecorationsUtils.java
@@ -16,7 +16,9 @@
package com.android.internal.policy;
+import android.content.Context;
import android.content.res.Resources;
+import android.view.RoundedCorners;
import com.android.internal.R;
@@ -29,23 +31,28 @@
* Corner radius that should be used on windows in order to cover the display.
* These values are expressed in pixels because they should not respect display or font
* scaling, this means that we don't have to reload them on config changes.
+ *
+ * Note that if the context is not an UI context(not associated with Display), it will use
+ * default display.
*/
- public static float getWindowCornerRadius(Resources resources) {
+ public static float getWindowCornerRadius(Context context) {
+ final Resources resources = context.getResources();
if (!supportsRoundedCornersOnWindows(resources)) {
return 0f;
}
-
+ // Use Context#getDisplayNoVerify() in case the context is not an UI context.
+ final String displayUniqueId = context.getDisplayNoVerify().getUniqueId();
// Radius that should be used in case top or bottom aren't defined.
- float defaultRadius = resources.getDimension(R.dimen.rounded_corner_radius)
- - resources.getDimension(R.dimen.rounded_corner_radius_adjustment);
+ float defaultRadius = RoundedCorners.getRoundedCornerRadius(resources, displayUniqueId)
+ - RoundedCorners.getRoundedCornerRadiusAdjustment(resources, displayUniqueId);
- float topRadius = resources.getDimension(R.dimen.rounded_corner_radius_top)
- - resources.getDimension(R.dimen.rounded_corner_radius_top_adjustment);
+ float topRadius = RoundedCorners.getRoundedCornerTopRadius(resources, displayUniqueId)
+ - RoundedCorners.getRoundedCornerRadiusTopAdjustment(resources, displayUniqueId);
if (topRadius == 0f) {
topRadius = defaultRadius;
}
- float bottomRadius = resources.getDimension(R.dimen.rounded_corner_radius_bottom)
- - resources.getDimension(R.dimen.rounded_corner_radius_bottom_adjustment);
+ float bottomRadius = RoundedCorners.getRoundedCornerBottomRadius(resources, displayUniqueId)
+ - RoundedCorners.getRoundedCornerRadiusBottomAdjustment(resources, displayUniqueId);
if (bottomRadius == 0f) {
bottomRadius = defaultRadius;
}
diff --git a/core/java/com/android/internal/protolog/ProtoLogGroup.java b/core/java/com/android/internal/protolog/ProtoLogGroup.java
index ce3efd3..db019a67 100644
--- a/core/java/com/android/internal/protolog/ProtoLogGroup.java
+++ b/core/java/com/android/internal/protolog/ProtoLogGroup.java
@@ -80,6 +80,10 @@
Consts.TAG_WM),
WM_DEBUG_WINDOW_TRANSITIONS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
Consts.TAG_WM),
+ WM_DEBUG_WINDOW_INSETS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false,
+ Consts.TAG_WM),
+ WM_DEBUG_LAYER_MIRRORING(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, true,
+ Consts.TAG_WM),
TEST_GROUP(true, true, false, "WindowManagerProtoLogTest");
private final boolean mEnabled;
diff --git a/core/java/com/android/internal/protolog/ProtoLogImpl.java b/core/java/com/android/internal/protolog/ProtoLogImpl.java
index 10224a4..353c6c0 100644
--- a/core/java/com/android/internal/protolog/ProtoLogImpl.java
+++ b/core/java/com/android/internal/protolog/ProtoLogImpl.java
@@ -28,7 +28,7 @@
*/
public class ProtoLogImpl extends BaseProtoLogImpl {
private static final int BUFFER_CAPACITY = 1024 * 1024;
- private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.pb";
+ private static final String LOG_FILENAME = "/data/misc/wmtrace/wm_log.winscope";
private static final String VIEWER_CONFIG_FILENAME = "/system/etc/protolog.conf.json.gz";
private static ProtoLogImpl sServiceInstance = null;
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index 84a7f2f..b427e8b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -149,7 +149,7 @@
*/
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation, int userId,
- String opPackageName, long operationId, int multiSensorConfig);
+ long operationId, String opPackageName, long requestId, int multiSensorConfig);
/**
* Used to notify the authentication dialog that a biometric has been authenticated.
*/
diff --git a/core/java/com/android/internal/statusbar/IStatusBarService.aidl b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
index e7d6d6c..b3499db 100644
--- a/core/java/com/android/internal/statusbar/IStatusBarService.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBarService.aidl
@@ -110,7 +110,8 @@
// Used to show the authentication dialog (Biometrics, Device Credential)
void showAuthenticationDialog(in PromptInfo promptInfo, IBiometricSysuiReceiver sysuiReceiver,
in int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId, int multiSensorConfig);
+ int userId, long operationId, String opPackageName, long requestId,
+ int multiSensorConfig);
// Used to notify the authentication dialog that a biometric has been authenticated
void onBiometricAuthenticated();
diff --git a/core/jni/android_os_GraphicsEnvironment.cpp b/core/jni/android_os_GraphicsEnvironment.cpp
index b40491a..f44e829 100644
--- a/core/jni/android_os_GraphicsEnvironment.cpp
+++ b/core/jni/android_os_GraphicsEnvironment.cpp
@@ -50,8 +50,7 @@
}
void setAngleInfo_native(JNIEnv* env, jobject clazz, jstring path, jstring appName,
- jstring devOptIn, jobjectArray featuresObj, jobject rulesFd,
- jlong rulesOffset, jlong rulesLength) {
+ jstring devOptIn, jobjectArray featuresObj) {
ScopedUtfChars pathChars(env, path);
ScopedUtfChars appNameChars(env, appName);
ScopedUtfChars devOptInChars(env, devOptIn);
@@ -74,11 +73,8 @@
}
}
- int rulesFd_native = jniGetFDFromFileDescriptor(env, rulesFd);
-
android::GraphicsEnv::getInstance().setAngleInfo(pathChars.c_str(), appNameChars.c_str(),
- devOptInChars.c_str(), features,
- rulesFd_native, rulesOffset, rulesLength);
+ devOptInChars.c_str(), features);
}
bool shouldUseAngle_native(JNIEnv* env, jobject clazz, jstring appName) {
@@ -124,8 +120,7 @@
{"setInjectLayersPrSetDumpable", "()Z",
reinterpret_cast<void*>(setInjectLayersPrSetDumpable_native)},
{"setAngleInfo",
- "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;Ljava/io/"
- "FileDescriptor;JJ)V",
+ "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;[Ljava/lang/String;)V",
reinterpret_cast<void*>(setAngleInfo_native)},
{"getShouldUseAngle", "(Ljava/lang/String;)Z",
reinterpret_cast<void*>(shouldUseAngle_native)},
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 0957067..869b53d 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -449,6 +449,11 @@
int(changeFrameRateStrategy));
}
+static void nativeDestroy(JNIEnv* env, jclass clazz, jlong nativeObject) {
+ sp<Surface> surface(reinterpret_cast<Surface*>(nativeObject));
+ surface->destroy();
+}
+
// ----------------------------------------------------------------------------
static const JNINativeMethod gSurfaceMethods[] = {
@@ -477,6 +482,7 @@
{"nativeSetAutoRefreshEnabled", "(JZ)I", (void*)nativeSetAutoRefreshEnabled},
{"nativeSetFrameRate", "(JFII)I", (void*)nativeSetFrameRate},
{"nativeGetFromBlastBufferQueue", "(JJ)J", (void*)nativeGetFromBlastBufferQueue},
+ {"nativeDestroy", "(J)V", (void*)nativeDestroy},
};
int register_android_view_Surface(JNIEnv* env)
diff --git a/core/proto/android/providers/settings/global.proto b/core/proto/android/providers/settings/global.proto
index 6bc00e2..83e26f6 100644
--- a/core/proto/android/providers/settings/global.proto
+++ b/core/proto/android/providers/settings/global.proto
@@ -972,6 +972,7 @@
optional SettingProto usb_mass_storage_enabled = 127 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto use_google_mail = 128 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto use_open_wifi_package = 129 [ (android.privacy).dest = DEST_AUTOMATIC ];
+ optional SettingProto uwb_enabled = 155 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto vt_ims_enabled = 130 [ (android.privacy).dest = DEST_AUTOMATIC ];
optional SettingProto wait_for_debugger = 131 [ (android.privacy).dest = DEST_AUTOMATIC ];
@@ -1065,5 +1066,5 @@
// Please insert fields in alphabetical order and group them into messages
// if possible (to avoid reaching the method limit).
- // Next tag = 155;
+ // Next tag = 156;
}
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1704452..e53d379 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -4862,6 +4862,18 @@
<permission android:name="android.permission.WRITE_SETTINGS_HOMEPAGE_DATA"
android:protectionLevel="signature|privileged" />
+ <!-- An application needs this permission for
+ {@link android.provider.Settings#ACTION_SETTINGS_LARGE_SCREEN_DEEP_LINK} to show its
+ {@link android.app.Activity} in 2-pane of Settings app. -->
+ <permission android:name="android.permission.LAUNCH_TWO_PANE_SETTINGS_DEEP_LINK"
+ android:protectionLevel="signature|preinstalled" />
+
+ <!-- @SystemApi {@link android.app.Activity} should require this permission to ensure that only
+ the settings app can embed it in a 2-pane window.
+ @hide -->
+ <permission android:name="android.permission.ALLOW_PLACE_IN_TWO_PANE_SETTINGS"
+ android:protectionLevel="signature" />
+
<!-- @SystemApi Allows applications to set a live wallpaper.
@hide XXX Change to signature once the picker is moved to its
own apk as Ghod Intended. -->
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 6946b3c..39cd642 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik jou vingerafdruk of skermslot om voort te gaan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdrukikoon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Gesigslot"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Kwessie met Gesigslot"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik jou gesig of skermslot om voort te gaan"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Gesig-ikoon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lees sinkroniseer-instellings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Laat die program toe om die sinkroniseringinstellings van \'n rekening te lees. Byvoorbeeld, dit kan bepaal of die People-program met \'n rekening gesinkroniseer is."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wanneer die kortpad aan is, sal \'n toeganklikheidkenmerk begin word as albei volumeknoppies 3 sekondes lank gedruk word."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Skakel kortpad vir toeganklikheidskenmerke aan?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit toeganklikheidkenmerke aan. Dit kan verander hoe jou toestel werk.\n\nHuidige kenmerke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJy kan geselekteerde kenmerke in Instellings en Toeganklikheid verander."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Skakel <xliff:g id="SERVICE">%1$s</xliff:g>-kortpad aan?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"As jy albei volumesleutels vir \'n paar sekondes hou, skakel dit <xliff:g id="SERVICE">%1$s</xliff:g>, \'n toeganklikheidkenmerk, aan. Dit kan verander hoe jou toestel werk.\n\nJy kan hierdie kortpad na \'n ander kenmerk in Instellings en Toeganklikheid verander."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Skakel aan"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 9ab2f19..c747497 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ለመቀጠል የጣት አሻራዎን ወይም የማያ ገጽ ቁልፍዎን ይጠቀሙ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"የጣት አሻራ አዶ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"በመልክ መክፈት"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ከመልክ መክፈት ጋር በተያያዘ ችግር"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ለመቀጠል መልክዎን ወይም የማያ ገጽዎን መቆለፊያ ይጠቀሙ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"የፊት አዶ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"የሥምሪያ ቅንብሮች አንብብ"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"መተግበሪያው የአንድ መለያ የማመሳሰል ቅንብሮችን እንዲያነብ ይፈቅድለታል። ለምሳሌ ይህ የሰዎች መተግበሪያ ከመለያ ጋር መመሳሰሉን አለመመሳሰሉን ሊወስን ይችላል።"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"አቋራጩ ሲበራ ሁለቱንም የድምጽ አዝራሮች ለ3 ሰከንዶች ተጭኖ መቆየት የተደራሽነት ባህሪን ያስጀምረዋል።"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"የተደራሽነት ባህሪዎች አቋራጭ ይብራ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nየአሁን ባሕሪያት፦\n<xliff:g id="SERVICE">%1$s</xliff:g>\nበቅንብሮች > ተደራሽነት ውስጥ የተመረጡትን ባሕሪያት መለወጥ ይችላሉ።"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"የ<xliff:g id="SERVICE">%1$s</xliff:g> አቋራጭ ይብራ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ሁለቱንም የድምፅ ቁልፎች ወደ ታች ለጥቂት ሰከንዶች መያዝ የተደራሽነት ባሕሪያትን <xliff:g id="SERVICE">%1$s</xliff:g> ያበራል። ይህ የእርስዎ መሣሪያ እንዴት እንደሚሠራ ሊለውጥ ይችላል።\n\nበቅንብሮች > ተደራሽነት ውስጥ ወደ ሌላ ባሕሪ ይህን አቋራጭ መለወጥ ይችላሉ።"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"አብራ"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 14221dc..c1c7a61 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -621,6 +621,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"استخدام بصمة الإصبع أو قفل الشاشة للمتابعة"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"رمز بصمة الإصبع"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فتح الجهاز بالتعرف على الوجه"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشكلة متعلّقة بميزة \"فتح الجهاز بالتعرف على الوجه\""</string>
@@ -673,6 +675,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"استخدام ميزة \"فتح القفل بالوجه\" أو ميزة \"قفل الشاشة\" للمتابعة"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"رمز الوجه"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"قراءة إعدادات المزامنة"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"للسماح للتطبيق بقراءة الإعدادات المتزامنة لحساب ما. على سبيل المثال، يمكن أن يؤدي هذا إلى تحديد ما إذا تمت مزامنة تطبيق \"الأشخاص\" مع حساب ما."</string>
@@ -1779,7 +1783,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"عند تفعيل الاختصار، يؤدي الضغط على زرّي التحكّم في مستوى الصوت معًا لمدة 3 ثوانٍ إلى تفعيل إحدى ميزات إمكانية الوصول."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"هل تريد تفعيل الاختصار لميزات إمكانية الوصول؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"يؤدي الضغط مع الاستمرار على كلا مفتاحَي التحكّم في مستوى الصوت لبضع ثوانٍ إلى تفعيل ميزات إمكانية الوصول. قد يؤدي هذا الإجراء إلى تغيير طريقة عمل جهازك.\n\nالميزات الحالية:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nيمكنك تغيير الميزات المحددة في الإعدادات > إمكانية الوصول."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"هل تريد تفعيل اختصار <xliff:g id="SERVICE">%1$s</xliff:g>؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"يؤدي الضغط مع الاستمرار لبضع ثوانٍ على كلا مفتاحَي التحكّم في مستوى الصوت إلى تفعيل <xliff:g id="SERVICE">%1$s</xliff:g> وهي إحدى ميزات إمكانية الوصول. يمكن أن يؤدي هذا الإجراء إلى تغيير كيفية عمل جهازك.\n\nيمكنك تغيير هذا الاختصار لاستخدامه مع ميزة أخرى في الإعدادات > أدوات تمكين الوصول."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"تفعيل"</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 65e4664..59f84ed 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"অব্যাহত ৰাখিবলৈ আপোনাৰ ফিংগাৰপ্ৰিণ্ট অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ফিংগাৰপ্ৰিণ্ট আইকন"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেচ আনলক"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ফেচ আনলক ব্যৱহাৰ কৰোঁতে সমস্যা হৈছে"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"অব্যাহত ৰাখিবলৈ আপোনাৰ মুখাৱয়ব অথবা স্ক্ৰীন লক ব্যৱহাৰ কৰক"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"মুখমণ্ডলৰ আইকন"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ছিংকৰ ছেটিংসমূহ পঢ়ক"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"একাউণ্টৰ ছিংক ছেটিংবোৰ পঢ়িবলৈ এপক অনুমতি দিয়ে। যেনে, People এপ কোনো একাউণ্টত ছিংক কৰা হৈছে নে নাই সেয়া নির্ধাৰণ কৰিব পাৰে।"</string>
@@ -815,7 +819,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 +852,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 +1042,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>
@@ -1467,7 +1471,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শ্বৰ্টকাটটো অন হৈ থকাৰ সময়ত দুয়োটা ভলিউম বুটাম ৩ ছেকেণ্ডৰ বাবে হেঁচি ধৰি ৰাখিলে এটা সাধ্য সুবিধা আৰম্ভ হ’ব।"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"সাধ্য সুবিধাসমূহৰ বাবে শ্বৰ্টকাট অন কৰিবনে?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে সাধ্য-সুবিধাসমূহ অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nবর্তমানৰ সুবিধাসমূহ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nআপুনি ছেটিংসমূহ > সাধ্য-সুবিধাত কিছুমান নিৰ্দিষ্ট সুবিধা সলনি কৰিব পাৰে।"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>ৰ শ্বৰ্টকাট অন কৰিবনে?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"দুয়োটা ভলিউম কী কিছুসময়ৰ বাবে ধৰি থাকিলে এটা সাধ্য- সুবিধা <xliff:g id="SERVICE">%1$s</xliff:g> অন কৰে। এইটোৱে আপোনাৰ ডিভাইচটোৱে কাম কৰাৰ ধৰণ সলনি কৰিব পাৰে।\n\nআপুনি ছেটিংসমূহ > সাধ্য-সুবিধাসমূহত এই শ্বৰ্টকাটটো অন্য এটা সুবিধালৈ সলনি কৰিব পাৰে।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"অন কৰক"</string>
@@ -1972,7 +1977,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-az/strings.xml b/core/res/res/values-az/strings.xml
index bab05ad..6cf0459 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davam etmək üçün barmaq izi və ya ekran kilidinizdən istifadə edin"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmaq izi ikonası"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Üz ilə kiliddən çıxarma"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Üz ilə kiliddən çıxarma problemi"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davam etmək üçün üz və ya ekran kilidinizdən istifadə edin"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Üz işarəsi"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx ayarlarını oxu"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tətbiqə hesablar üçün sinxronizasiya nizamlarını oxuma icazəsi verir. Məsələn, bu Şəxslər tətbiqinin sinxronizə olunub-olunmadığını təyin edə bilər."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Qısayol aktiv olduqda, hər iki səs düyməsinə 3 saniyə basıb saxlamaqla əlçatımlılıq funksiyası başladılacaq."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Əlçatımlılıq funksiyaları üçün qısayol aktiv edilsin?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyaları aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nCari funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAyarlar və Əlçatımlılıq bölməsində seçilmiş funksiyaları dəyişə bilərsiniz."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> qısayolu aktiv edilsin?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hər iki səs səviyyəsi düyməsinə bir neçə saniyə basıb saxladıqda əlçatımlılıq funksiyası olan <xliff:g id="SERVICE">%1$s</xliff:g> aktiv olur. Cihazınızın işləmə qaydasını dəyişə bilər.\n\nAyarlar və Əlçatımlılıq bölməsində bu qısayolu başqa bir funksiyaya dəyişə bilərsiniz."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktiv edin"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 4179ab0..d333f99 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da biste nastavili"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem sa otključavanje licem"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da biste nastavili"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje podešavanja sinhronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Dozvoljava aplikaciji da čita podešavanja sinhronizacije za nalog. Na primer, ovako može da se utvrdi da li je aplikacija Ljudi sinhronizovana sa nalogom."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritisnite oba dugmeta za jačinu zvuka da biste pokrenuli funkciju pristupačnosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite da uključite prečicu za funkcije pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključiće se funkcije pristupačnosti. To može da promeni način rada uređaja.\n\nPostojeće funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nMožete da promenite izabrane funkcije u odeljku Podešavanja > Pristupačnost."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite da uključite prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako zadržite oba tastera za jačinu zvuka par sekundi, uključuje se <xliff:g id="SERVICE">%1$s</xliff:g>, funkcija pristupačnosti. To može da promeni način rada uređaja.\n\nMožete da promenite funkciju na koju se odnosi ova prečica u odeljku Podešavanja > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 2d94ffe..b09d29e 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Каб працягнуць, скарыстайце адбітак пальца ці сродак разблакіроўкі экрана"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок адбіткаў пальцаў"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Распазнаванне твару"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Праблема з распазнаваннем твару"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Каб працягнуць, скарыстайце распазнаванне твару ці сродак разблакіроўкі экрана"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Значок твару"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"чытаць параметры сінхранізацыі"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дазваляе прыкладанням чытаць параметры сінхранізацыі для ўліковага запісу. Напрыклад, яны могуць вызначыць, цi сiнхранiзавана з улiковым запiсам прыкладанне \"Кантакты\"."</string>
@@ -972,7 +976,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>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Калі хуткі доступ уключаны, вы можаце націснуць абедзве кнопкі гучнасці і ўтрымліваць іх 3 секунды, каб запусціць функцыю спецыяльных магчымасцей."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Уключыць хуткі доступ да спецыяльных магчымасцей?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае спецыяльныя магчымасці. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nБягучыя функцыі:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВыбраныя функцыі можна змяніць у меню \"Налады > Спецыяльныя магчымасці\"."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Уключыць хуткі доступ да сэрвісу \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Утрымліванне націснутымі абедзвюх клавіш гучнасці на працягу некалькіх секунд уключае службу \"<xliff:g id="SERVICE">%1$s</xliff:g>\", якая з\'яўляецца спецыяльнай магчымасцю. У выніку ваша прылада можа пачаць працаваць па-іншаму.\n\nВы можаце задаць гэта спалучэнне клавіш для іншай функцыі ў меню \"Налады > Спецыяльныя магчымасці\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Уключыць"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index 40807e5..9a6857f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Използвайте отпечатъка си или опцията за заключване на екрана, за да продължите"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатък"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отключване с лице"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем с отключването с лице"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Използвайте лицето си или опцията за заключване на екрана, за да продължите"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Икона на лице"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"четене на настройките за синхронизиране"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Разрешава на приложението да чете настройките за синхронизиране на профил. Например това може да определи дали приложението Хора е синхронизирано с даден профил."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Когато прекият път е включен, можете да стартирате дадена функция за достъпност, като натиснете двата бутона за силата на звука и ги задържите за 3 секунди."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Искате ли да включите прекия път за функциите за достъпност?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функциите за достъпност. Това може да промени начина, по който работи устройството ви.\n\nТекущи функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените избраните функции от „Настройки“ > „Достъпност“."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Искате ли да включите прекия път за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Натиснете двата бутона за силата на звука и ги задръжте за няколко секунди, за да включите функцията за достъпност <xliff:g id="SERVICE">%1$s</xliff:g>. Това може да промени начина, по който работи устройството ви.\n\nМожете да зададете друга функция за този пряк път от „Настройки“ > „Достъпност“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включване"</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index 2f68cda..c5092ff 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"চালিয়ে যেতে আপনার আঙুলের ছাপ বা স্ক্রিন লক ব্য়বহার করুন"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"আঙ্গুলের ছাপ আইকন"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ফেস আনলক"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"\'ফেস আনলক\' ফিচার ব্যবহার করার ক্ষেত্রে হওয়া সমস্যা"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"চালিয়ে যেতে আপনার ফেস বা স্ক্রিন লক ব্যবহার করুন"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ফেস আইকন"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"সিঙ্ক সেটিংস পড়ে"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"অ্যাপ্লিকেশানটিকে একটি অ্যাকাউন্টের জন্য সিঙ্ক সেটিংস পড়ার অনুমতি দেয়৷ উদাহরণস্বরূপ, \'পিপল\' অ্যাপ্লিকেশানটি কোনো অ্যাকাউন্টের সাথে সিঙ্ক করা আছে কিনা তা নির্ধারণ করতে পারে৷"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"শর্টকাট চালু করা থাকাকালীন দুটি ভলিউম বোতাম একসাথে ৩ সেকেন্ড টিপে ধরে রাখলে একটি অ্যাকসেসিবিলিটি ফিচার চালু হবে।"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"অ্যাক্সেসিবিলিটি ফিচারের শর্টকাট বন্ধ করতে চান?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে অ্যাক্সেসিবিলিটি ফিচার চালু হয়ে যাবে। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nবর্তমান ফিচার:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nসেটিংস > অ্যাক্সেসিবিলিটি বিকল্প থেকে আপনি বাছাই করা ফিচার পরিবর্তন করতে পারবেন।"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> শর্টকাট চালু করতে চান?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"উভয় ভলিউম কী কয়েক সেকেন্ড ধরে থাকলে <xliff:g id="SERVICE">%1$s</xliff:g> চালু হয়ে যাবে। এটি একটি অ্যাক্সেসিবিলিটি ফিচার। এর ফলে, আপনার ডিভাইস কীভাবে কাজ করবে সেটিতে পরিবর্তন হতে পারে।\n\nসেটিংস > অ্যাক্সেসিবিলিটি থেকে আপনি এই শর্টকাট পরিবর্তন করতে পারবেন।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"চালু করুন"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 3ebb7cc..45f1b01 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Koristite otisak prsta ili zaključavanje ekrana da nastavite"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona za otisak prsta"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem s otključavanjem licem"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Koristite lice ili zaključavanje ekrana da nastavite"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki za sinhroniziranje"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Omogućava aplikaciji čitanje postavki sinhroniziranja za račun. Naprimjer, ovim se može utvrditi da li je aplikacija People sinhronizirana sa računom."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kada je prečica uključena, pritiskom i držanjem oba dugmeta za jačinu zvuka u trajanju od 3 sekunde pokrenut će se funkcija pristupačnosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Uključiti prečicu za funkcije pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkcije pristupačnosti. Ovo može uticati na način rada uređaja.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane funkcije možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Uključiti prečicu za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako nekoliko sekundi držite pritisnute obje tipke za jačinu zvuka, uključit ćete funkciju pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Ovo može promijeniti način rada uređaja.\n\nOvu prečicu možete zamijeniti drugom funkcijom u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 880ad180..26fc4c7 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilitza l\'empremta digital o el bloqueig de pantalla per continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona d\'empremta digital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueig facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema amb Desbloqueig facial"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilitza la cara o el bloqueig de pantalla per continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Icona facial"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"llegir la configuració de sincronització"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet que l\'aplicació llegeixi la configuració de sincronització d\'un compte. Per exemple, això pot determinar que l\'aplicació Contactes estigui sincronitzada amb un compte."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si la drecera està activada, prem els dos botons de volum durant 3 segons per iniciar una funció d\'accessibilitat."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vols desactivar la drecera de les funcions d\'accessibilitat?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantens premudes les dues tecles de volum durant uns segons, s\'activaran les funcions d\'accessibilitat. Això podria canviar el funcionament del teu dispositiu.\n\nFuncions actuals:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPots canviar les funcions seleccionades a Configuració > Accessibilitat."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vols activar la drecera de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantens premudes les dues tecles de volum durant uns segons, la funció d\'accessibilitat <xliff:g id="SERVICE">%1$s</xliff:g> s\'activarà. Això podria canviar el funcionament del teu dispositiu.\n\nPots canviar la funció d\'aquesta drecera a Configuració > Accessibilitat."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activa"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a8ae213..23f9822 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte ověřením pomocí otisku prstu nebo zámku obrazovky"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otisku prstů"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odemknutí obličejem"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odemykáním obličejem"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte ověřením pomocí obličeje nebo zámku obrazovky"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona obličeje"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"čtení nastavení synchronizace"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikaci číst nastavení synchronizace v účtu. Může například určit, zda je s účtem synchronizována aplikace Lidé."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Když je tato zkratka zapnutá, můžete funkci přístupnosti spustit tím, že na tři sekundy podržíte obě tlačítka hlasitosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Zapnout zkratku funkcí pro usnadnění přístupu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkce pro usnadnění přístupu. Tato funkce může změnit fungování zařízení.\n\nAktuální funkce:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkce můžete změnit v Nastavení > Přístupnost."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Zapnout zkratku služby <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Podržením obou tlačítek hlasitosti po dobu několika sekund zapnete funkci pro usnadnění přístupu <xliff:g id="SERVICE">%1$s</xliff:g>. Tato funkce může změnit fungování zařízení.\n\nZkratku můžete nastavit na jinou funkci v Nastavení > Přístupnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnout"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 45f02e3..6835dcd 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Brug dit fingeraftryk eller din skærmlås for at fortsætte"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeraftryk"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansigtslås"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Der er et problem med Ansigtslås"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Brug din ansigts- eller skærmlås for at fortsætte"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ansigt"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"læse indstillinger for synkronisering"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillader, at appen kan læse synkroniseringsindstillingerne for en konto. Denne tilladelse kan f.eks. fastslå, om appen Personer er synkroniseret med en konto."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når genvejen er aktiveret, kan du starte en hjælpefunktion ved at trykke på begge lydstyrkeknapper i tre sekunder."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du aktivere genvejen til hjælpefunktioner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionerne. Det kan ændre på, hvordan din enhed fungerer.\n\nAktuelle funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ændre de valgte funktioner i Indstillinger > Hjælpefunktioner."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du aktivere <xliff:g id="SERVICE">%1$s</xliff:g>-genvejen?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder begge lydstyrkeknapperne nede i et par sekunder, aktiveres hjælpefunktionen <xliff:g id="SERVICE">%1$s</xliff:g>. Det kan ændre på, hvordan din enhed fungerer.\n\nDu kan ændre denne genvej til en anden funktion i Indstillinger > Hjælpefunktioner."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivér"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 865f026..09dd5a0 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Verwende deinen Fingerabdruck oder deine Display-Entsperrmethode, um fortzufahren"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerabdruck-Symbol"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Entsperrung per Gesichtserkennung"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem bei der Entsperrung per Gesichtserkennung"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Verwende die Gesichtserkennung oder deine Display-Entsperrmethode, um fortzufahren"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Gesichtssymbol"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"Synchronisierungseinstellungen lesen"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ermöglicht der App, die Synchronisierungseinstellungen eines Kontos zu lesen. Beispielsweise kann damit festgestellt werden, ob Kontakte mit einem Konto synchronisiert werden."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Wenn die Verknüpfung aktiviert ist, kannst du die beiden Lautstärketasten drei Sekunden lang gedrückt halten, um eine Bedienungshilfe zu starten."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Verknüpfung für Bedienungshilfen aktivieren?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfen. Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nAktuelle Funktionen:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kannst ausgewählte Funktionen unter \"Einstellungen\" > \"Bedienungshilfen\" ändern."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Verknüpfung für <xliff:g id="SERVICE">%1$s</xliff:g> aktivieren?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Wenn du beide Lautstärketasten einige Sekunden lang gedrückt hältst, aktivierst du die Bedienungshilfe \"<xliff:g id="SERVICE">%1$s</xliff:g>\". Dadurch kann sich die Funktionsweise deines Geräts ändern.\n\nUnter \"Einstellungen > \"Bedienungshilfen\" kannst du dieser Verknüpfung eine andere Funktion zuweisen."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivieren"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 67bd433..4e019dc 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Χρησιμοποιήστε το δακτυλικό σας αποτύπωμα ή το κλείδωμα οθόνης για να συνεχίσετε"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Εικονίδιο δακτυλικών αποτυπωμάτων"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ξεκλείδωμα με το πρόσωπο"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Πρόβλημα με το Ξεκλείδωμα με το πρόσωπο"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Χρησιμοποιήστε το πρόσωπό σας ή το κλείδωμα οθόνης για συνέχεια"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Εικ. προσ."</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"διαβάζει τις ρυθμίσεις συγχρονισμού"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Επιτρέπει στην εφαρμογή την ανάγνωση των ρυθμίσεων συγχρονισμού για έναν λογαριασμό. Για παράδειγμα, αυτό μπορεί να καθορίσει εάν η εφαρμογή \"Άτομα\" είναι συγχρονισμένη με έναν λογαριασμό."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Όταν η συντόμευση είναι ενεργοποιημένη, το πάτημα και των δύο κουμπιών έντασης ήχου για 3 δευτερόλεπτα θα ξεκινήσει μια λειτουργία προσβασιμότητας."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ενεργοποίηση συντόμευσης για λειτουργίες προσβασιμότητας;"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Για να ενεργοποιήσετε τις λειτουργίες προσβασιμότητας, πατήστε παρατεταμένα τα δύο πλήκτρα έντασης για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΤρέχουσες λειτουργίες:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nΜπορείτε να αλλάξετε τις επιλεγμένες λειτουργίες στις Ρυθμίσεις > Προσβασιμότητα."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ενεργοποίηση συντόμευσης <xliff:g id="SERVICE">%1$s</xliff:g>;"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Μπορείτε να ενεργοποιήσετε τη λειτουργία <xliff:g id="SERVICE">%1$s</xliff:g>, η οποία είναι μία από τις λειτουργίες προσβασιμότητας, πατώντας παρατεταμένα ταυτόχρονα τα δύο πλήκτρα έντασης ήχου για μερικά δευτερόλεπτα. Αυτό ενδέχεται να αλλάξει τον τρόπο λειτουργίας της συσκευής σας.\n\nΜπορείτε να αλλάξετε αυτή τη συντόμευση σε μια άλλη λειτουργία στις Ρυθμίσεις > Προσβασιμότητα."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ενεργοποίηση"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 8cf968d..04158b4 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index b772335..3b019f4 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index e1e8187..91d39a9 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index 892041c..fe23e63 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for three seconds will start an accessibility feature."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-en-rXC/strings.xml b/core/res/res/values-en-rXC/strings.xml
index a7ad2b6..787de9b 100644
--- a/core/res/res/values-en-rXC/strings.xml
+++ b/core/res/res/values-en-rXC/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use your fingerprint or screen lock to continue"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Something went wrong. Try again."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingerprint icon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Issue with Face Unlock"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use your face or screen lock to continue"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Something went wrong. Try again."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"read sync settings"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Allows the app to read the sync settings for an account. For example, this can determine whether the People app is synced with an account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"When the shortcut is on, pressing both volume buttons for 3 seconds will start an accessibility feature."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Turn on shortcut for accessibility features?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Turn on <xliff:g id="SERVICE">%1$s</xliff:g> shortcut?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Holding down both volume keys for a few seconds turns on <xliff:g id="SERVICE">%1$s</xliff:g>, an accessibility feature. This may change how your device works.\n\nYou can change this shortcut to another feature in Settings > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Turn on"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 5206c48..a820d25 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella dactilar o bloqueo de pantalla para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícono de huella dactilar"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con el Desbloqueo facial"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu rostro o bloqueo de pantalla para continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ícono cara"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Este permiso permite que la aplicación consulte la configuración de sincronización de una cuenta. Esto permite, por ejemplo, determinar si la aplicación Personas está sincronizada con una cuenta."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cuando la combinación de teclas está activada, puedes presionar los botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar la combinación de teclas para las funciones de accesibilidad?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si mantienes presionadas las dos teclas de volumen durante unos segundos, se activarán las funciones de accesibilidad. Esto puede cambiar el funcionamiento de tu dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Configuración > Accesibilidad."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo de <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si mantienes presionadas ambas teclas de volumen durante unos segundos, se activará la función de accesibilidad <xliff:g id="SERVICE">%1$s</xliff:g>. Esto podría cambiar la forma en que funciona tu dispositivo.\n\nPuedes cambiar este acceso directo a otra función en Configuración > Accesibilidad."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 9a29add..c653c31 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Usa tu huella digital o tu bloqueo de pantalla para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Se ha producido un error. Inténtalo de nuevo."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icono de huella digital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Desbloqueo facial"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Usa tu cara o tu bloqueo de pantalla para continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Se ha producido un error. Inténtalo de nuevo."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Icono cara"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"leer la configuración de sincronización"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que la aplicación consulte la configuración de sincronización de una cuenta. La aplicación puede utilizar este permiso, por ejemplo, para determinar si la aplicación Contactos está sincronizada con una cuenta."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Si el acceso directo está activado, pulsa los dos botones de volumen durante 3 segundos para iniciar una función de accesibilidad."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"¿Quieres activar el acceso directo a las funciones de accesibilidad?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Al mantener pulsadas las dos teclas de volumen durante unos segundos, se activan las funciones de accesibilidad, que pueden cambiar el funcionamiento del dispositivo.\n\nFunciones actuales:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuedes cambiar las funciones seleccionadas en Ajustes > Accesibilidad."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"¿Quieres activar el acceso directo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Al mantener pulsadas ambas teclas de volumen durante unos segundos se activa <xliff:g id="SERVICE">%1$s</xliff:g>, una función de accesibilidad. Esta función puede modificar el funcionamiento del dispositivo.\n\nPuedes asignar este acceso directo a otra función en Ajustes > Accesibilidad."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 4dd7d94..683026d 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jätkamiseks kasutage oma sõrmejälge või ekraanilukku"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sõrmejälje ikoon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Näoga avamine"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem funktsiooniga Näoga avamine"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jätkamiseks kasutage oma nägu või ekraanilukku"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Näoikoon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"loe sünkroonimisseadeid"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Võimaldab rakendusel lugeda konto sünkroonimisseadeid. Näiteks võib see määrata, kas rakendus Inimesed on kontoga sünkroonitud."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kui otsetee on sisse lülitatud, käivitab mõlema helitugevuse nupu kolm sekundit all hoidmine juurdepääsetavuse funktsiooni."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kas lülitada juurdepääsufunktsioonide otsetee sisse?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hoidke juurdepääsufunktsioonide sisselülitamiseks mõlemat helitugevuse klahvi mõni sekund all. See võib teie seadme tööviisi muuta.\n\nPraegused funktsioonid:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nValitud funktsioone saab muuta jaotises Seaded > Juurdepääsetavus."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kas lülitada teenuse <xliff:g id="SERVICE">%1$s</xliff:g> otsetee sisse?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Kui hoiate mõlemat helitugevuse klahvi mõni sekund all, lülitatakse juurdepääsufunktsioon <xliff:g id="SERVICE">%1$s</xliff:g> sisse. See võib teie seadme tööviisi muuta.\n\nSelle otsetee saab asendada muu otseteega jaotises Seaded > Juurdepääsetavus."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Lülita sisse"</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index d4705c1..9fd95de 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aurrera egiteko, erabili hatz-marka edo pantailaren blokeoa"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Hatz-markaren ikonoa"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Aurpegi bidez desblokeatzeko eginbidea"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arazoak ditugu aurpegi bidez desblokeatzeko eginbidearekin"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aurrera egiteko, erabili aurpegia edo pantailaren blokeoa"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Aurpegiaren ikonoa"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"irakurri sinkronizazio-ezarpenak"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Kontu baten sinkronizazio-ezarpenak irakurtzeko baimena ematen die aplikazioei. Adibidez, Jendea aplikazioa konturen batekin sinkronizatuta dagoen zehatz dezake."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Lasterbidea aktibatuta dagoenean, bi bolumen-botoiak hiru segundoz sakatuta abiaraziko da erabilerraztasun-eginbidea."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erabilerraztasun-eginbideetarako lasterbidea aktibatu nahi duzu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Eduki sakatuta bolumen-botoiak segundo batzuez erabilerraztasun-eginbideak aktibatzeko. Hori eginez gero, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nEginbideak:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nHautatutako eginbideak aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> zerbitzuaren lasterbidea aktibatu nahi duzu?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Eduki sakatuta bolumen-botoiak segundo batzuez <xliff:g id="SERVICE">%1$s</xliff:g> izeneko erabilerraztasun-eginbidea aktibatzeko. Honen bidez, baliteke zure mugikorraren funtzionamendua aldatzea.\n\nLasterbide hau beste eginbide batengatik aldatzeko, joan Ezarpenak > Erabilerraztasuna atalera."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktibatu"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index fcca1b39..823ef54 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"برای ادامه، از اثر انگشت یا قفل صفحه استفاده کنید"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"نماد اثر انگشت"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"قفلگشایی با چهره"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"مشکل در «قفلگشایی با چهره»"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"برای ادامه، از تشخیص چهره یا قفل صفحه استفاده کنید"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"نماد چهره"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"خواندن تنظیمات همگامسازی"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"به برنامه اجازه میدهد تنظیمات را برای یک حساب بخواند. بهعنوان مثال، این ویژگی میتواند تعیین کند آیا حساب «افراد» شما با یک حساب همگامسازی شده است."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"وقتی میانبر روشن باشد، با فشار دادن هردو دکمه صدا بهمدت ۳ ثانیه ویژگی دسترسپذیری فعال میشود."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"میانبر برای ویژگیهای دسترسپذیری روشن شود؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"با پایین نگه داشتن هردو کلید میزان صدا بهمدت چند ثانیه، ویژگیهای دسترسپذیری روشن میشود. با این کار نحوه عملکرد دستگاهتان تغییر میکند.\n\nویژگیهای فعلی:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nمیتوانید ویژگیهای انتخابی را در «تنظیمات > دسترسپذیری» تغییر دهید."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"میانبر <xliff:g id="SERVICE">%1$s</xliff:g> روشن شود؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"با پایین نگه داشتن هردو کلید میزان صدا بهمدت چند ثانیه، <xliff:g id="SERVICE">%1$s</xliff:g> (یکی از ویژگیهای دسترسپذیری) روشن میشود. با این کار نحوه عملکرد دستگاهتان تغییر میکند.\n\nمیتوانید در «تنظیمات > دسترسپذیری»،این میانبر را به ویژگی دیگری تغییر دهید."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"روشن شود"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 5998269..0a23c87 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jatka sormenjäljen tai näytön lukituksen avulla"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Sormenjälkikuvake"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kasvojentunnistusavaus"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Face Unlockiin liittyvä ongelma"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jatka kasvojentunnistuksen tai näytön lukituksen avulla"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Kasvokuvake"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lue synkronointiasetuksia"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Antaa sovelluksen lukea tilien synkronointiasetuksia. Sovellus voi esimerkiksi määrittää, onko Henkilöt-sovellus synkronoitu tilin kanssa."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kun pikanäppäin on käytössä, voit käynnistää esteettömyystoiminnon pitämällä molempia äänenvoimakkuuspainikkeita painettuna kolmen sekunnin ajan."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Laitetaanko esteettömyysominaisuuksien pikavalinta päälle?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Molempien äänenvoimakkuuspainikkeiden painaminen muutaman sekunnin ajan laittaa esteettömyysominaisuudet päälle. Tämä voi muuttaa laitteesi toimintaa.\n\nNykyiset ominaisuudet:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVoit muuttaa valittuja ominaisuuksia kohdassa Asetukset > Esteettömyys."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Laitetaanko pikavalinta (<xliff:g id="SERVICE">%1$s</xliff:g>) päälle?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Molempien äänenvoimakkuuspainikkeiden pitkään painaminen laittaa päälle esteettömyysominaisuuden <xliff:g id="SERVICE">%1$s</xliff:g>. Tämä voi muuttaa laitteesi toimintaa.\n\nVoit muuttaa tätä pikanäppäintä kohdassa Asetukset > Esteettömyys."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Laita päälle"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 860e10b..bc92fc6 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème avec la fonctionnalité de déverrouillage par reconnaissance faciale"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez votre visage ou le verrouillage de l\'écran pour continuer"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour lancer une fonctionnalité d\'accessibilité."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour les fonctionnalités d\'accessibilité?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez les fonctionnalités d\'accessibilité. Cela peut modifier le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, sélectionnez Paramètres > Accessibilité."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci pour <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous maintenez enfoncées les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut modifier le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, sélectionnez Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 55fa145..d5c7ff2 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilisez votre empreinte digitale ou le verrouillage de l\'écran pour continuer"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icône d\'empreinte digitale"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Déverrouillage par reconnaissance faciale"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problème lié au déverrouillage par reconnaissance faciale"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilisez la reconnaissance faciale ou le verrouillage de l\'écran pour continuer"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Icône visage"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lire les paramètres de synchronisation"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permet à l\'application d\'accéder aux paramètres de synchronisation d\'un compte. Par exemple, cette autorisation peut permettre de déterminer si l\'application Contacts est synchronisée avec un compte ou non."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quand le raccourci est activé, appuyez sur les deux boutons de volume pendant trois secondes pour démarrer une fonctionnalité d\'accessibilité."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activer le raccourci pour accéder aux fonctionnalités d\'accessibilité ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez des fonctionnalités d\'accessibilité. Cela peut affecter le fonctionnement de votre appareil.\n\nFonctionnalités actuellement utilisées :\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPour les modifier, accédez à Paramètres > Accessibilité."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activer le raccourci <xliff:g id="SERVICE">%1$s</xliff:g> ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Si vous appuyez sur les deux touches de volume pendant quelques secondes, vous activez la fonctionnalité d\'accessibilité <xliff:g id="SERVICE">%1$s</xliff:g>. Cela peut affecter le fonctionnement de votre appareil.\n\nPour attribuer ce raccourci à une autre fonctionnalité, accédez à Paramètres > Accessibilité."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activer"</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 76f54ff..6d2909a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Para continuar, utiliza a impresión dixital ou o bloqueo de pantalla"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona de impresión dixital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueo facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Produciuse un problema co desbloqueo facial"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Para continuar, utiliza o desbloqueo facial ou a credencial do dispositivo"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Icona cara"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler a configuración de vinculación"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite á aplicación ler a configuración de vinculación dunha conta. Por exemplo, esta acción pode determinar se a aplicación Contactos se vincula cunha conta."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Cando o atallo está activado, podes premer os dous botóns de volume durante 3 segundos para iniciar unha función de accesibilidade."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Queres activar as funcións de accesibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ao manter as dúas teclas de volume premidas durante uns segundos actívanse as funcións de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nFuncións activadas actualmente:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPodes cambiar as funcións seleccionadas en Configuración > Accesibilidade."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Queres activar o atallo a <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ao manter as dúas teclas de volume premidas durante uns segundos actívase <xliff:g id="SERVICE">%1$s</xliff:g>, unha función de accesibilidade. Esta acción pode cambiar o funcionamento do dispositivo.\n\nPodes cambiar o uso deste atallo para outra función en Configuración > Accesibilidade."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activar"</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index e473ab6..4babc58 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ચાલુ રાખવા માટે તમારા ફિંગરપ્રિન્ટ અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ફિંગરપ્રિન્ટ આયકન"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ફેસ અનલૉક"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ફેસ અનલૉકની સુવિધામાં સમસ્યા"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ચાલુ રાખવા માટે તમારા ફેસ લૉક અથવા સ્ક્રીન લૉકનો ઉપયોગ કરો"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ચહેરા આઇકન"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"સિંક સેટિંગ વાંચો"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ઍપને એકાઉન્ટ માટે સિંક સેટિંગને વાંચવાની મંજૂરી આપે છે. ઉદાહરણ તરીકે, આ એકાઉન્ટ સાથે લોકો ઍપ સિંક થઈ છે કે કેમ તે નિર્ધારિત કરી શકે છે."</string>
@@ -848,7 +852,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"જ્યારે શૉર્ટકટ ચાલુ હોય, ત્યારે બન્ને વૉલ્યૂમ બટનને 3 સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા શરૂ થઈ જશે."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ઍક્સેસિબિલિટી સુવિધાઓ માટે શૉર્ટકટ ચાલુ કરીએ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધાઓ ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nવર્તમાન સુવિધાઓ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nતમે સેટિંગ > ઍક્સેસિબિલિટીમાં જઈને પસંદ કરેલી સુવિધાઓને બદલી શકો છો."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> શૉર્ટકટ ચાલુ કરીએ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"બન્ને વૉલ્યૂમ કીને થોડી સેકન્ડ સુધી દબાવી રાખવાથી ઍક્સેસિબિલિટી સુવિધા એવી <xliff:g id="SERVICE">%1$s</xliff:g> ચાલુ થઈ જાય છે. આનાથી તમારા ડિવાઇસની કામ કરવાની રીત બદલાઈ શકે છે.\n\nતમે સેટિંગ > ઍક્સેસિબિલિટીમાં જઈને આ શૉર્ટકટને બીજી સુવિધામાં બદલી શકો છો."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ચાલુ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index dcf357b..62e1774 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -326,7 +326,7 @@
<string name="permgroupdesc_phone" msgid="270048070781478204">"फ़ोन कॉल करने और उन्हें प्रबंधित करने की अनुमति दें"</string>
<string name="permgrouplab_sensors" msgid="9134046949784064495">"बॉडी सेंसर"</string>
<string name="permgroupdesc_sensors" msgid="2610631290633747752">"अपने महत्वपूर्ण संकेतों के बारे में सेंसर डेटा को ऐक्सेस करें"</string>
- <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडो की सामग्री वापस पाएं"</string>
+ <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"विंडो का कॉन्टेंट वापस पाएं"</string>
<string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"उस विंडो की सामग्री की जाँच करें, जिसका आप इस्तेमाल कर रहे हैं."</string>
<string name="capability_title_canRequestTouchExploration" msgid="327598364696316213">"छूकर, किसी चीज़ से जुड़ी जानकारी सुनने की सुविधा चालू करें"</string>
<string name="capability_desc_canRequestTouchExploration" msgid="4394677060796752976">"जिन चीज़ों पर आप टैप करेंगे उन्हें ज़ोर से बोला जाएगा और स्क्रीन को जेस्चर के ज़रिए एक्सप्लोर किया जा सकेगा."</string>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी रखने के लिए, फ़िंगरप्रिंट या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फ़िंगरप्रिंट आइकॉन"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फ़ेस अनलॉक"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फ़ेस अनलॉक से जुड़ी समस्या"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी रखने के लिए, अपना चेहरा दिखाकर या स्क्रीन लॉक क्रेडेंशियल डालकर पुष्टि करें"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"चेहरे का आइकॉन"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"समन्वयन सेटिंग पढ़ें"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ऐप्स को किसी खाते की समन्वयन सेटिंग पढ़ने देता है. उदाहरण के लिए, इससे यह तय किया जा सकता है कि लोग ऐप्स किसी खाते के साथ समन्वयित है या नहीं."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट के चालू होने पर, दाेनाें वॉल्यूम बटन (आवाज़ कम या ज़्यादा करने वाले बटन) को तीन सेकंड तक दबाने से, सुलभता सुविधा शुरू हाे जाएगी."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"क्या आप सुलभता सुविधाओं के लिए शॉर्टकट चालू करना चाहते हैं?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से सुलभता सुविधाएं चालू हो जाती हैं. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nमौजूदा सुविधाएं:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nआप सेटिंग और सुलभता में जाकर चुनी हुई सुविधाएं बदल सकते हैं."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"क्या आप <xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट चालू करना चाहते हैं?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"आवाज़ कम और ज़्यादा करने वाले दोनों बटन को कुछ सेकंड तक दबाकर रखने से <xliff:g id="SERVICE">%1$s</xliff:g> चालू हो जाती है, जो एक सुलभता सुविधा है. ऐसा करने से आपके डिवाइस के काम करने के तरीके में बदलाव हो सकता है.\n\nआप सेटिंग और सुलभता में जाकर इस शॉर्टकट को किसी दूसरी सुविधा के लिए बदल सकते हैं."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"चालू करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index 9aa3350..c557b2f 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nastavak se identificirajte otiskom prsta ili vjerodajnicom zaključavanja zaslona"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona otiska prsta"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Otključavanje licem"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Poteškoće s otključavanjem licem"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nastavak se identificirajte licem ili vjerodajnicom zaključavanja zaslona"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona lica"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"čitanje postavki sinkronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogućuje čitanje postavki sinkronizacije za račun. Time se, primjerice, može utvrditi je li aplikacija Osobe sinkronizirana s računom."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad je taj prečac uključen, pritiskom na obje tipke za glasnoću na tri sekunde pokrenut će se značajka pristupačnosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite li uključiti prečac za značajke pristupačnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Značajke pristupačnosti uključuju se ako na nekoliko sekundi pritisnete obje tipke za glasnoću. Time se može promijeniti način na koji vaš uređaj radi.\n\nTrenutačne značajke:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nOdabrane značajke možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite li uključiti prečac za uslugu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ako na nekoliko sekundi pritisnete obje tipke za glasnoću, uključuje se značajka pristupačnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Time se može promijeniti način na koji vaš uređaj radi.\n\nZnačajku na koju se taj prečac odnosi možete promijeniti u odjeljku Postavke > Pristupačnost."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Uključi"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 908b779..39547b1 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"A folytatás ujjlenyomattal vagy a képernyőzár feloldásával lehetséges"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ujjlenyomat ikon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Arcalapú feloldás"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Arcalapú feloldással kapcsolatos problémák"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"A folytatás arcalapú feloldással vagy a képernyőzár feloldásával lehetséges"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Arcikon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"szinkronizálási beállítások olvasása"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lehetővé teszi az alkalmazás számára egy fiók szinkronizálási beállításainak beolvasását. Például ellenőrizheti, hogy a Személyek alkalmazás szinkronizálva van-e egy fiókkal."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ha a gyorsparancs aktív, akkor a két hangerőgomb három másodpercig tartó együttes lenyomásával kisegítő funkciót indíthat el."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bekapcsol gyorsparancsot a kisegítő lehetőségekhez?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"A kisegítő lehetőségek bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nJelenlegi funkciók:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nA kiválasztott funkciókat a Beállítások > Kisegítő lehetőségek pontban módosíthatja."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bekapcsolja a(z) <xliff:g id="SERVICE">%1$s</xliff:g> szolgáltatás gyorsparancsát?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"A(z) <xliff:g id="SERVICE">%1$s</xliff:g> kisegítő lehetőség bekapcsolásához tartsa nyomva néhány másodpercig mindkét hangerőgombot. Ez hatással lehet az eszköz működésére.\n\nEzt a gyorsparancsot a Beállítások > Kisegítő lehetőségek pontban módosíthatja másik funkció használatára."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bekapcsolom"</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index a7992f9..51a07dd 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Շարունակելու համար օգտագործեք ձեր մատնահետքը կամ էկրանի կողպումը"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Մատնահետքի պատկերակ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Դեմքով ապակողպում"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Դեմքով ապակողպման հետ կապված խնդիր"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Շարունակելու համար օգտագործեք ձեր դեմքը կամ էկրանի կողպումը"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Դեմքի պատկերակ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"կարդալ համաժամացման կարգավորումները"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Թույլ է տալիս հավելվածին կարդալ համաժամացման կարգավորումները հաշվի համար: Օրինակ՝ այն կարող է որոշել, արդյոք Մարդիկ հավելվածը համաժամացված է հաշվի հետ:"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Հատուկ գործառույթն օգտագործելու համար սեղմեք և 3 վայրկյան սեղմած պահեք ձայնի ուժգնության երկու կոճակները, երբ գործառույթը միացված է:"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Միացնե՞լ հատուկ գործառույթների դյուրանցումը"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք հատուկ գործառույթները։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԸնթացիկ գործառույթներ՝\n<xliff:g id="SERVICE">%1$s</xliff:g>\nԸնտրված գործառույթները փոխելու համար անցեք Կարգավորումներ > Հատուկ գործառույթներ։"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Միացնե՞լ <xliff:g id="SERVICE">%1$s</xliff:g>-ի դյուրանցումը"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ձայնի կարգավորման երկու կոճակները մի քանի վայրկյան սեղմած պահելով կմիացնեք <xliff:g id="SERVICE">%1$s</xliff:g> ծառայությունը, որը հատուկ գործառույթ է։ Դրա արդյունքում սարքի աշխատաեղանակը կարող է փոխվել։\n\nԱյս դյուրանցումը մեկ այլ գործառույթով փոխելու համար անցեք Կարգավորումներ > Հատուկ գործառույթներ։"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Միացնել"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 8ae4bc7..7f9dc7e 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -58,8 +58,8 @@
<string name="meid" msgid="3291227361605924674">"MEID"</string>
<string name="ClipMmi" msgid="4110549342447630629">"Nomor Penelepon Masuk"</string>
<string name="ClirMmi" msgid="6752346475055446417">"Menyembunyikan ID Penelepon untuk Panggilan Keluar"</string>
- <string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Tersambung"</string>
- <string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Tersambung"</string>
+ <string name="ColpMmi" msgid="4736462893284419302">"ID Saluran yang Terhubung"</string>
+ <string name="ColrMmi" msgid="5889782479745764278">"Batasan ID Saluran yang Terhubung"</string>
<string name="CfMmi" msgid="8390012691099787178">"Penerusan panggilan"</string>
<string name="CwMmi" msgid="3164609577675404761">"Nada tunggu"</string>
<string name="BaMmi" msgid="7205614070543372167">"Pemblokiran panggilan"</string>
@@ -162,7 +162,7 @@
<string name="httpErrorUnsupportedAuthScheme" msgid="3976195595501606787">"Skema autentikasi situs tidak didukung."</string>
<string name="httpErrorAuth" msgid="469553140922938968">"Tidak dapat mengautentikasi."</string>
<string name="httpErrorProxyAuth" msgid="7229662162030113406">"Autentikasi via proxy server gagal."</string>
- <string name="httpErrorConnect" msgid="3295081579893205617">"Tidak dapat tersambung ke server."</string>
+ <string name="httpErrorConnect" msgid="3295081579893205617">"Tidak dapat terhubung ke server."</string>
<string name="httpErrorIO" msgid="3860318696166314490">"Tidak dapat berkomunikasi dengan server. Coba lagi nanti."</string>
<string name="httpErrorTimeout" msgid="7446272815190334204">"Koneksi ke server terputus."</string>
<string name="httpErrorRedirectLoop" msgid="8455757777509512098">"Halaman ini berisi terlalu banyak pengalihan server."</string>
@@ -468,7 +468,7 @@
<string name="permlab_accessImsCallService" msgid="442192920714863782">"akses layanan panggilan IMS"</string>
<string name="permdesc_accessImsCallService" msgid="6328551241649687162">"Memungkinkan aplikasi menggunakan layanan IMS untuk melakukan panggilan tanpa campur tangan Anda."</string>
<string name="permlab_readPhoneState" msgid="8138526903259297969">"baca identitas dan status ponsel"</string>
- <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang tersambung oleh sebuah panggilan."</string>
+ <string name="permdesc_readPhoneState" msgid="7229063553502788058">"Memungkinkan aplikasi mengakses fitur telepon perangkat. Izin ini memungkinkan aplikasi menentukan nomor telepon dan ID perangkat, apakah suatu panggilan aktif atau tidak, dan nomor jarak jauh yang terhubung oleh sebuah panggilan."</string>
<string name="permlab_manageOwnCalls" msgid="9033349060307561370">"sambungkan panggilan telepon melalui sistem"</string>
<string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"Mengizinkan aplikasi menyambungkan panggilan telepon melalui sistem untuk menyempurnakan pengalaman menelepon."</string>
<string name="permlab_callCompanionApp" msgid="3654373653014126884">"melihat dan mengontrol panggilan melalui sistem."</string>
@@ -504,7 +504,7 @@
<string name="permdesc_getAccounts" product="tv" msgid="437604680436540822">"Mengizinkan aplikasi mendapatkan daftar akun yang dikenal oleh perangkat Android TV. Ini mungkin mencakup akun yang dibuat oleh aplikasi yang telah Anda instal."</string>
<string name="permdesc_getAccounts" product="default" msgid="2491273043569751867">"Memungkinkan aplikasi mendapatkan daftar akun yang dikenal oleh ponsel. Ini mungkin termasuk akun yang dibuat oleh aplikasi yang telah Anda instal."</string>
<string name="permlab_accessNetworkState" msgid="2349126720783633918">"lihat koneksi jaringan"</string>
- <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Memungkinkan aplikasi melihat informasi tentang koneksi jaringan, misalnya jaringan yang ada dan tersambung."</string>
+ <string name="permdesc_accessNetworkState" msgid="4394564702881662849">"Memungkinkan aplikasi melihat informasi tentang koneksi jaringan, misalnya jaringan yang ada dan terhubung."</string>
<string name="permlab_createNetworkSockets" msgid="3224420491603590541">"dapatkan akses jaringan penuh"</string>
<string name="permdesc_createNetworkSockets" msgid="7722020828749535988">"Memungkinkan aplikasi membuat soket jaringan dan menggunakan protokol jaringan khusus. Browser dan aplikasi lain menyediakan sarana untuk mengirim data ke internet sehingga izin ini tidak diperlukan untuk mengirim data ke internet."</string>
<string name="permlab_changeNetworkState" msgid="8945711637530425586">"ubah konektivitas jaringan"</string>
@@ -512,7 +512,7 @@
<string name="permlab_changeTetherState" msgid="9079611809931863861">"mengubah konektivitas yang tertambat"</string>
<string name="permdesc_changeTetherState" msgid="3025129606422533085">"Mengizinkan apl mengubah status konektivitas jaringan yang tertambat."</string>
<string name="permlab_accessWifiState" msgid="5552488500317911052">"lihat sambungan Wi-Fi"</string>
- <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Memungkinkan aplikasi melihat informasi tentang jaringan Wi-Fi, misalnya apakah Wi-Fi diaktifkan dan nama perangkat Wi-Fi yang tersambung."</string>
+ <string name="permdesc_accessWifiState" msgid="6913641669259483363">"Memungkinkan aplikasi melihat informasi tentang jaringan Wi-Fi, misalnya apakah Wi-Fi diaktifkan dan nama perangkat Wi-Fi yang terhubung."</string>
<string name="permlab_changeWifiState" msgid="7947824109713181554">"sambung dan putuskan Wi-Fi"</string>
<string name="permdesc_changeWifiState" msgid="7170350070554505384">"Memungkinkan aplikasi menyambung ke dan memutus dari titik akses Wi-Fi, dan mengubah konfigurasi perangkat untuk jaringan Wi-Fi."</string>
<string name="permlab_changeWifiMulticastState" msgid="285626875870754696">"Izinkan penerimaan Wi-Fi Multicast"</string>
@@ -524,14 +524,14 @@
<string name="permdesc_bluetoothAdmin" product="tv" msgid="1623992984547014588">"Mengizinkan aplikasi mengonfigurasi Bluetooth di perangkat Android TV, serta menemukan dan menyambungkan dengan perangkat jarak jauh."</string>
<string name="permdesc_bluetoothAdmin" product="default" msgid="7381341743021234863">"Mengizinkan apl mengonfigurasi ponsel Bluetooth lokal, dan menemukan serta menyandingkan dengan perangkat jarak jauh."</string>
<string name="permlab_accessWimaxState" msgid="7029563339012437434">"sambungkan dan putuskan dari WiMAX"</string>
- <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Memungkinkan aplikasi menentukan apakah WiMAX diaktifkan dan informasi tentang jaringan WiMAX apa saja yang tersambung."</string>
+ <string name="permdesc_accessWimaxState" msgid="5372734776802067708">"Memungkinkan aplikasi menentukan apakah WiMAX diaktifkan dan informasi tentang jaringan WiMAX apa saja yang terhubung."</string>
<string name="permlab_changeWimaxState" msgid="6223305780806267462">"Ganti status WiMAX"</string>
<string name="permdesc_changeWimaxState" product="tablet" msgid="4011097664859480108">"Memungkinkan aplikasi menyambungkan tablet ke dan memutus tablet dari jaringan WiMAX."</string>
<string name="permdesc_changeWimaxState" product="tv" msgid="5373274458799425276">"Mengizinkan aplikasi menghubungkan perangkat Android TV ke, dan memutuskan hubungan perangkat Android TV dari, jaringan WiMAX."</string>
<string name="permdesc_changeWimaxState" product="default" msgid="1551666203780202101">"Memungkinkan aplikasi menyambungkan ponsel ke dan memutus ponsel dari jaringan WiMAX."</string>
<string name="permlab_bluetooth" msgid="586333280736937209">"sambungkan dengan perangkat Bluetooth"</string>
<string name="permdesc_bluetooth" product="tablet" msgid="3053222571491402635">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di tablet, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
- <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Mengizinkan aplikasi melihat konfigurasi Bluetooth di perangkat Android TV, serta melakukan dan menerima sambungan dengan perangkat yang tersambung."</string>
+ <string name="permdesc_bluetooth" product="tv" msgid="8851534496561034998">"Mengizinkan aplikasi melihat konfigurasi Bluetooth di perangkat Android TV, serta melakukan dan menerima sambungan dengan perangkat yang terhubung."</string>
<string name="permdesc_bluetooth" product="default" msgid="2779606714091276746">"Memungkinkan aplikasi melihat konfigurasi Bluetooth di ponsel, dan membuat serta menerima sambungan dengan perangkat yang disandingkan."</string>
<string name="permlab_bluetooth_scan" msgid="5402587142833124594">"temukan & sambungkan perangkat Bluetooth di sekitar"</string>
<string name="permdesc_bluetooth_scan" product="default" msgid="6540723536925289276">"Mengizinkan aplikasi menemukan dan menyambungkan perangkat Bluetooth di sekitar"</string>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan sidik jari atau kunci layar untuk melanjutkan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon sidik jari"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Face Unlock"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Masalah pada Face Unlock"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan face lock atau kunci layar untuk melanjutkan"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"baca setelan sinkronisasi"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Memungkinkan aplikasi membaca setelan sinkronisasi untuk sebuah akun. Misalnya, izin ini dapat menentukan apakah aplikasi Orang disinkronkan dengan sebuah akun."</string>
@@ -1365,7 +1369,7 @@
<string name="usb_ptp_notification_title" msgid="5043437571863443281">"PTP via USB diaktifkan"</string>
<string name="usb_tether_notification_title" msgid="8828527870612663771">"Tethering USB diaktifkan"</string>
<string name="usb_midi_notification_title" msgid="7404506788950595557">"MIDI via USB diaktifkan"</string>
- <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Aksesori USB tersambung"</string>
+ <string name="usb_accessory_notification_title" msgid="1385394660861956980">"Aksesori USB terhubung"</string>
<string name="usb_notification_message" msgid="4715163067192110676">"Ketuk untuk opsi lainnya."</string>
<string name="usb_power_notification_message" msgid="7284765627437897702">"Mengisi daya perangkat yang terhubung. Ketuk untuk opsi lainnya."</string>
<string name="usb_unsupported_audio_accessory_title" msgid="2335775548086533065">"Aksesori audio analog terdeteksi"</string>
@@ -1497,9 +1501,9 @@
<string name="vpn_title" msgid="5906991595291514182">"VPN diaktifkan"</string>
<string name="vpn_title_long" msgid="6834144390504619998">"VPN diaktifkan oleh <xliff:g id="APP">%s</xliff:g>"</string>
<string name="vpn_text" msgid="2275388920267251078">"Ketuk untuk mengelola jaringan."</string>
- <string name="vpn_text_long" msgid="278540576806169831">"Tersambung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
+ <string name="vpn_text_long" msgid="278540576806169831">"Terhubung ke <xliff:g id="SESSION">%s</xliff:g>. Ketuk untuk mengelola jaringan."</string>
<string name="vpn_lockdown_connecting" msgid="6096725311950342607">"Menyambungkan VPN selalu aktif..."</string>
- <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN selalu aktif tersambung"</string>
+ <string name="vpn_lockdown_connected" msgid="2853127976590658469">"VPN selalu aktif terhubung"</string>
<string name="vpn_lockdown_disconnected" msgid="5573611651300764955">"Terputus dari VPN yang selalu aktif"</string>
<string name="vpn_lockdown_error" msgid="4453048646854247947">"Tidak dapat terhubung ke VPN yang selalu aktif"</string>
<string name="vpn_lockdown_config" msgid="8331697329868252169">"Ubah setelan jaringan atau VPN"</string>
@@ -1634,7 +1638,7 @@
<string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Setelan"</string>
<string name="media_route_controller_disconnect" msgid="7362617572732576959">"Putuskan koneksi"</string>
<string name="media_route_status_scanning" msgid="8045156315309594482">"Memindai..."</string>
- <string name="media_route_status_connecting" msgid="5845597961412010540">"Menyambung..."</string>
+ <string name="media_route_status_connecting" msgid="5845597961412010540">"Menghubungkan..."</string>
<string name="media_route_status_available" msgid="1477537663492007608">"Tersedia"</string>
<string name="media_route_status_not_available" msgid="480912417977515261">"Tidak tersedia"</string>
<string name="media_route_status_in_use" msgid="6684112905244944724">"Sedang digunakan"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Saat pintasan aktif, menekan kedua tombol volume selama 3 detik akan memulai fitur aksesibilitas."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Aktifkan pintasan untuk fitur aksesibilitas?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nFitur saat ini:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda dapat mengubah fitur yang dipilih di Setelan > Aksesibilitas."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Aktifkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Menahan kedua tombol volume selama beberapa detik akan mengaktifkan <xliff:g id="SERVICE">%1$s</xliff:g>, yang merupakan fitur aksesibilitas. Tindakan ini dapat mengubah cara kerja perangkat Anda.\n\nAnda dapat mengubah pintasan ini ke fitur lain di Setelan > Aksesibilitas."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktifkan"</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index 93e25a6..470a516 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Notaðu fingrafar eða skjálás til að halda áfram"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Fingrafaratákn"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Andlitskenni"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vandamál varðandi andlitskenni"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Notaðu andlitið eða skjálás til að halda áfram"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Andlitstákn"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lesa samstillingar"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leyfir forriti að lesa kosti samstillingar fyrir reikning. Þetta er til dæmis hægt að nota til að komast að því hvort forritið Fólk er samstillt við reikning."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Þegar flýtileiðin er virk er kveikt á aðgengiseiginleikanum með því að halda báðum hljóðstyrkshnöppunum inni í þrjár sekúndur."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Kveikja á flýtileið fyrir aðgangseiginleika?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Kveikt er á aðgengiseiginleikum þegar báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur. Þetta getur breytt því hvernig tækið virkar.\n\nNúverandi eiginleikar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÞú getur breytt völdum eiginleikum í Stillingar > Aðgengi."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Kveikja á flýtileið <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ef báðum hljóðstyrkstökkunum er haldið inni í nokkrar sekúndur er kveikt á aðgengiseiginleikanum <xliff:g id="SERVICE">%1$s</xliff:g>. Þetta getur breytt því hvernig tækið virkar.\n\nÞú getur breytt þessari flýtileið í annan eiginleika í Stillingar > Aðgengi."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Kveikja"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 316514e..f606643 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Per continuare devi usare la tua impronta o il tuo blocco schermo"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Si è verificato un errore. Riprova."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icona dell\'impronta"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Sblocco con il volto"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema con Sblocco con il volto"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Per continuare devi usare il tuo volto o il tuo blocco schermo"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Si è verificato un errore. Riprova."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Icona volto"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lettura impostazioni di sincronizz."</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Consente all\'applicazione di leggere le impostazioni di sincronizzazione per un account. Ad esempio, questa autorizzazione può determinare se l\'applicazione Persone è sincronizzata con un account."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando la scorciatoia è attiva, puoi premere entrambi i pulsanti del volume per tre secondi per avviare una funzione di accessibilità."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vuoi attivare la scorciatoia per le funzioni di accessibilità?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Se tieni premuti entrambi i tasti del volume per qualche secondo, vengono attivate le funzioni di accessibilità. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nFunzioni correnti:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuoi modificare le funzioni selezionate in Impostazioni > Accessibilità."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vuoi attivare la scorciatoia per <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Se tieni premuti entrambi i tasti del volume per qualche secondo verrà attivata la funzione di accessibilità <xliff:g id="SERVICE">%1$s</xliff:g>. Questa operazione potrebbe modificare il funzionamento del dispositivo.\n\nPuoi associare questa scorciatoia a un\'altra funzionalità in Impostazioni > Accessibilità."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Attiva"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 716e97c7..8a91d1b 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"יש להשתמש בטביעת האצבע או בנעילת המסך כדי להמשיך"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"סמל טביעת אצבע"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"פתיחה ע\"י זיהוי הפנים"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"בעיה בפתיחה ע\"י זיהוי הפנים"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"יש להשתמש בזיהוי הפנים או בנעילת המסך כדי להמשיך"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"סמל הפנים"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"קריאת הגדרות הסנכרון"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"מאפשרת לאפליקציה לקרוא את הגדרות הסנכרון של חשבון. לדוגמה, כך אפשר לדעת אם האפליקציה \'אנשים\' מסונכרנת עם חשבון כלשהו."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"כשקיצור הדרך מופעל, לחיצה על שני לחצני עוצמת הקול למשך שלוש שניות מפעילה את תכונת הנגישות."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"האם להפעיל את מקש הקיצור לתכונות הנגישות?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"לחיצה ארוכה על שני לחצני עוצמת הקול למשך מספר שניות מפעילה את תכונות הנגישות. בעקבות זאת, ייתכן שאופן הפעולה של המכשיר ישתנה.\n\nהתכונות הנוכחיות:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nניתן לשנות את התכונות שנבחרו ב\'הגדרות\' > \'נגישות\'."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"האם להפעיל את מקש הקיצור של <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"לחיצה על שני מקשי עוצמת הקול למשך מספר שניות מפעילה את תכונת הנגישות <xliff:g id="SERVICE">%1$s</xliff:g>. ייתכן שאופן הפעולה של המכשיר ישתנה בעקבות זאת.\n\nאפשר לשנות את מקשי הקיצור האלה לתכונה אחרת ב\'הגדרות\' > \'נגישות\'."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"אני רוצה להפעיל"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 30a62e3..8e78e30 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"続行するには、指紋認証または画面ロックを使用してください"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋アイコン"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"顔認証"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"顔認証に関する問題"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"続行するには、顔認証または画面ロックを使用してください"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"顔アイコン"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"同期設定の読み取り"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"アカウントの同期設定の読み取りをアプリに許可します。たとえば、連絡帳アプリがアカウントと同期しているかどうかをアプリから特定できるようになります。"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ショートカットが ON の場合、両方の音量ボタンを 3 秒ほど長押しするとユーザー補助機能が起動します。"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ユーザー補助機能のショートカットを ON にしますか?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\n現在の機能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n選択した機能は [設定] > [ユーザー補助] で変更できます。"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> のショートカットを ON にしますか?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"音量大と音量小の両方のボタンを数秒ほど長押しすると、ユーザー補助機能の <xliff:g id="SERVICE">%1$s</xliff:g> が ON になります。この機能が ON になると、デバイスの動作が変わることがあります。\n\nこのショートカットは [設定] > [ユーザー補助] で別の機能に変更できます。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ON にする"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index 789e279..58501aa 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"გასაგრძელებლად გამოიყენეთ თქვენი თითის ანაბეჭდი ან ეკრანის განბლოკვის ნიმუში"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"თითის ანაბეჭდის ხატულა"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"განბლოკვა სახით"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"პრობლემა სახით განბლოკვასთან დაკავშირებით"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"გასაგრძელებლად გამოიყენეთ თქვენი სახე ან ეკრანის განბლოკვის ნიმუში"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"სახის ხატულა"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"სინქრონიზაციის პარამეტრების წაკითხვა"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"აპს შეეძლება, წაიკითხოს ანგარიშის სინქრონიზაციის პარამეტრები. მაგალითად, მას შეეძლება განსაზღვროს, არის თუ არა People აპი სინქრონიზებული ანგარიშთან."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"თუ მალსახმობი ჩართულია, ხმის ორივე ღილაკზე 3 წამის განმავლობაში დაჭერით მარტივი წვდომის ფუნქცია ჩაირთვება."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ჩაირთოს მარტივი წვდომის ფუნქციების მალსახმობი?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ხმის ორივე ღილაკზე ხანგრძლივად დაჭერა რამდენიმე წამის განმავლობაში ჩართავს მარტივი წვდომის ფუნქციებს. ამ ქმედებამ შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამჟამინდელი ფუნქციები:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nარჩეული ფუნქციების შეცვლა შესაძლებელია აქ: პარამეტრები > მარტივი წვდომა."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ჩაირთოს <xliff:g id="SERVICE">%1$s</xliff:g>-ის მალსახმობი?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ხმის ორივე ღილაკზე რამდენიმე წამის განმავლობაში დაჭერით ჩაირთვება <xliff:g id="SERVICE">%1$s</xliff:g>, რომელიც მარტივი წვდომის ფუნქციაა. ამან შეიძლება შეცვალოს თქვენი მოწყობილობის მუშაობის პრინციპი.\n\nამ მალსახმობის შეცვლა სხვა ფუნქციით შეგიძლიათ აქ: პარამეტრები > აპები."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ჩართვა"</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index 6e82813..1b4b36f 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Жалғастыру үшін саусақ ізін немесе экран құлпын пайдаланыңыз."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Саусақ ізі белгішесі"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Бет тану"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Бет тану функциясына қатысты мәселе шықты"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Жалғастыру үшін бетті анықтау функциясын немесе экран құлпын пайдаланыңыз."</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Бет белгішесі"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"синх параметрлерін оқу"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Қолданбаға есептік жазба синхрондау параметрлерін оқу мүмкіндігін береді. Мысалы, бұл арқылы People қолданбасының есептік жазбамен сихрондалғаны анықталуы мүмкін."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Түймелер тіркесімі қосулы кезде, екі дыбыс түймесін 3 секунд басып тұрсаңыз, \"Арнайы мүмкіндіктер\" функциясы іске қосылады."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Арнайы мүмкіндіктердің жылдам пәрмені іске қосылсын ба?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, арнайы мүмкіндіктер іске қосылады. Бұл – құрылғының жұмысына әсер етуі мүмкін.\n\nҚазіргі функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТаңдалған функцияларды \"Параметрлер > Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> жылдам пәрмені іске қосылсын ба?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дыбыс деңгейі пернелерін бірнеше секунд басып тұрсаңыз, <xliff:g id="SERVICE">%1$s</xliff:g> арнайы қызметі іске қосылады. Бұл – құрылғының жүмысына әсер етуі мүмкін.\n\nБұл таңбашаны басқа функцияға \"Параметрлер > Арнайы мүмкіндіктер\" бөлімінен өзгерте аласыз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Қосылсын"</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index d56a55d..c7eea0b 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ប្រើការចាក់សោអេក្រង់ ឬស្នាមម្រាមដៃរបស់អ្នក ដើម្បីបន្ត"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"រូបស្នាមម្រាមដៃ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ដោះសោតាមទម្រង់មុខ"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"មានបញ្ហាពាក់ព័ន្ធនឹងមុខងារដោះសោតាមទម្រង់មុខ"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ប្រើការចាក់សោអេក្រង់ ឬមុខរបស់អ្នក ដើម្បីបន្ត"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"រូបផ្ទៃមុខ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"អានការកំណត់ធ្វើសមកាលកម្ម"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ឲ្យកម្មវិធីអានការកំណត់ធ្វើសមកាលកម្មសម្រាប់គណនី។ ឧទាហរណ៍ វាអាចកំណត់ថាតើកម្មវិធីត្រូវបានបើកជាមួយគណនីដែរឬទេ។"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"នៅពេលបើកផ្លូវកាត់ ការចុចប៊ូតុងកម្រិតសំឡេងទាំងពីររយៈពេល 3 វិនាទីនឹងចាប់ផ្តើមមុខងារភាពងាយប្រើ។"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"បើកផ្លូវកាត់សម្រាប់មុខងារភាពងាយស្រួលឬ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ការសង្កត់គ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលពីរបីវិនាទីនឹងបើកមុខងារភាពងាយប្រើ។ ការធ្វើបែបនេះអាចផ្លាស់ប្ដូររបៀបដែលឧបករណ៍របស់អ្នកដំណើរការ។\n\nមុខងារបច្ចុប្បន្ន៖\n<xliff:g id="SERVICE">%1$s</xliff:g>\nអ្នកអាចប្ដូរមុខងារដែលបានជ្រើសរើសនៅក្នុងការកំណត់ > ភាពងាយស្រួល។"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"បើកផ្លូវកាត់ <xliff:g id="SERVICE">%1$s</xliff:g> ឬ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ការសង្កត់គ្រាប់ចុចកម្រិតសំឡេងទាំងពីរឱ្យជាប់រយៈពេលពីរបីវិនាទីនឹងបើក <xliff:g id="SERVICE">%1$s</xliff:g> ដែលជាមុខងារភាពងាយប្រើ។ ការធ្វើបែបនេះអាចផ្លាស់ប្ដូររបៀបដែលឧបករណ៍របស់អ្នកដំណើរការ។\n\nអ្នកអាចប្ដូរផ្លូវកាត់នេះទៅមុខងារផ្សេងទៀតនៅក្នុងការកំណត់ > ភាពងាយស្រួល។"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"បើក"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index ed2f964..03ad2c5 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ಮುಂದುವರಿಸಲು ಫಿಂಗರ್ ಪ್ರಿಂಟ್ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಐಕಾನ್"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ಫೇಸ್ ಅನ್ಲಾಕ್"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ಫೇಸ್ ಅನ್ಲಾಕ್ ಕುರಿತು ಸಮಸ್ಯೆ ಇದೆ"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ಮುಂದುವರಿಸಲು ನಿಮ್ಮ ಮುಖ ಅಥವಾ ಸ್ಕ್ರೀನ್ ಲಾಕ್ ಅನ್ನು ಬಳಸಿ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ಮುಖದ ಐಕಾನ್"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ರೀಡ್ ಮಾಡು"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ಒಂದು ಖಾತೆಯ ಸಿಂಕ್ ಸೆಟ್ಟಿಂಗ್ಗಳನ್ನು ಓದಲು ಅಪ್ಲಿಕೇಶನ್ಗೆ ಅವಕಾಶ ನೀಡುತ್ತದೆ. ಉದಾಹರಣೆಗೆ, ಖಾತೆಯೊಂದಿಗೆ ಜನರ ಅಪ್ಲಿಕೇಶನ್ ಸಿಂಕ್ ಮಾಡಲಾಗಿದೆಯೇ ಎಂಬುದನ್ನು ಇದು ನಿರ್ಧರಿಸಬಹುದು."</string>
@@ -815,7 +819,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 +852,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 +1042,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>
@@ -1467,7 +1471,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಆಗಿರುವಾಗ, ಎರಡೂ ವಾಲ್ಯೂಮ್ ಬಟನ್ಗಳನ್ನು 3 ಸೆಕೆಂಡುಗಳ ಕಾಲ ಒತ್ತಿದರೆ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವೊಂದು ಪ್ರಾರಂಭವಾಗುತ್ತದೆ."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳಿಗಾಗಿ ಶಾರ್ಟ್ಕಟ್ ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯಗಳು ಆನ್ ಆಗುತ್ತವೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\n ಪ್ರಸ್ತುತ ವೈಶಿಷ್ಟ್ಯಗಳು:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಆ್ಯಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿ ಆಯ್ದ ವೈಶಿಷ್ಟ್ಯಗಳನ್ನು ನೀವು ಬದಲಾಯಿಸಬಹುದು."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ಶಾರ್ಟ್ಕಟ್ <xliff:g id="SERVICE">%1$s</xliff:g>ಆನ್ ಮಾಡಬೇಕೇ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ಎರಡೂ ವಾಲ್ಯೂಮ್ ಕೀಗಳನ್ನು ಕೆಲವು ಸೆಕೆಂಡುಗಳ ಕಾಲ ಹಿಡಿದಿಟ್ಟುಕೊಳ್ಳುವುದರಿಂದ ಪ್ರವೇಶಿಸುವಿಕೆ ವೈಶಿಷ್ಟ್ಯವಾದ <xliff:g id="SERVICE">%1$s</xliff:g> ಆನ್ ಆಗುತ್ತದೆ. ಇದು ನಿಮ್ಮ ಸಾಧನವು ಹೇಗೆ ಕಾರ್ಯನಿರ್ವಹಿಸುತ್ತದೆ ಎಂಬುದನ್ನು ಬದಲಾಯಿಸಬಹುದು.\n\nನೀವು ಈ ಶಾರ್ಟ್ಕಟ್ ಅನ್ನು ಸೆಟ್ಟಿಂಗ್ಗಳು ಮತ್ತು ಅಕ್ಸೆಸಿಬಿಲಿಟಿಯಲ್ಲಿನ ಮತ್ತೊಂದು ವೈಶಿಷ್ಟ್ಯಕ್ಕೆ ಬದಲಾಯಿಸಬಹುದು."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ಆನ್ ಮಾಡಿ"</string>
@@ -1972,7 +1977,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-ko/strings.xml b/core/res/res/values-ko/strings.xml
index ea8fe228..aa3df73 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"계속하려면 지문이나 화면 잠금을 사용하세요"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"지문 아이콘"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"얼굴 인식 잠금 해제"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"얼굴 인식 잠금 해제 문제"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"계속하려면 얼굴 또는 화면 잠금을 사용하세요"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"얼굴 아이콘"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"동기화 설정 읽기"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"앱이 계정의 동기화 설정을 읽을 수 있도록 허용합니다. 예를 들어, 계정에서 주소록 앱을 동기화할지 여부를 확인할 수 있습니다."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"단축키가 사용 설정된 경우 볼륨 버튼 두 개를 동시에 3초간 누르면 접근성 기능이 시작됩니다."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"접근성 기능 바로가기를 사용 설정하시겠습니까?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"볼륨 키 2개를 몇 초 동안 길게 누르면 접근성 기능이 사용 설정됩니다. 이때 기기 작동 방식이 달라질 수 있습니다.\n\n현재 기능:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n설정 > 접근성에서 선택한 기능을 변경할 수 있습니다."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> 바로가기를 사용 설정하시겠습니까?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"볼륨 키 2개를 몇 초 동안 길게 누르면 <xliff:g id="SERVICE">%1$s</xliff:g> 접근성 기능이 사용 설정됩니다. 이렇게 되면 기기 작동 방식이 달라질 수 있습니다.\n\n설정 > 접근성에서 이 단축키를 다른 기능으로 변경할 수 있습니다."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"사용"</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 4216086..cb6e3e4 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Улантуу үчүн манжа изин же экрандын кулпусун колдонуңуз"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Манжа изинин сүрөтчөсү"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Жүзүнөн таанып ачуу"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Жүзүнөн таанып ачуу функциясында маселе келип чыкты"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Улантуу үчүн жүзүңүздү же экрандын кулпусун колдонуңуз"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Жүздүн сүрөтчөсү"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"шайкештирүү жөндөөлөрүн окуу"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Колдонмого эсеп менен синхрондошуу тууралоолорун окуганга уруксат берет. Мисалы, Кишилер колдонмосу эсеп менен синхрондошкондугун аныктай алат."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Атайын мүмкүнчүлүктөр функциясын пайдалануу үчүн ал күйгүзүлгөндө, үндү катуулатып/акырындаткан эки баскычты тең 3 секунддай коё бербей басып туруңуз."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Атайын мүмкүнчүлүктөрдүн ыкчам баскычын иштетесизби?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Атайын мүмкүнчүлүктөр функциясын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nУчурдагы функциялар:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТандалган функцияларды өзгөртүү үчүн Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ыкчам баскычын иштетесизби?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> кызматын иштетүү үчүн үндү чоңойтуп/кичирейтүү баскычтарын бир нече секунд коё бербей басып туруңуз. Ушуну менен, түзмөгүңүз бир аз башкача иштеп калышы мүмкүн.\n\nБаскычтардын ушул айкалышын башка функцияга дайындоо үчүн, Жөндөөлөр > Атайын мүмкүнчүлүктөр бөлүмүнө өтүңүз."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ооба"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index b1c0d59..e27cc1e 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ໃຊ້ລາຍນິ້ວມື ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ໄອຄອນລາຍນິ້ວມື"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ປົດລັອກດ້ວຍໜ້າ"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ເກີດບັນຫາກັບການປົດລັອກດ້ວຍໜ້າ"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ໃຊ້ໃບໜ້າ ຫຼື ການລັອກໜ້າຈໍຂອງທ່ານເພື່ອດຳເນີນການຕໍ່"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ໄອຄອນໃບໜ້າ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ອ່ານການຕັ້ງຄ່າຊິ້ງຂໍ້ມູນ"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ອະນຸຍາດໃຫ້ແອັບຯ ອ່ານການຕັ້ງຄ່າການຊິ້ງຂໍ້ມູນຂອງບັນຊີໄດ້. ຕົວຢ່າງເຊັ່ນ: ມັນຈະສາມາດກວດສອບໄດ້ແອັບຯ People ຖືກຊິ້ງຂໍ້ມູນກັບບັນຊີໃດນຶ່ງແລ້ວຫຼືຍັງ."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ເມື່ອເປີດໃຊ້ທາງລັດແລ້ວ, ການກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ 3 ວິນາທີຈະເປັນການເລີ່ມຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ເປີດໃຊ້ທາງລັດສຳລັບຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງບໍ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nຄຸນສົມບັດປັດຈຸບັນ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nທ່ານສາມາດປ່ຽນຄຸນສົມບັດທີ່ເລືອກໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ເປີດໃຊ້ທາງລັດ <xliff:g id="SERVICE">%1$s</xliff:g> ບໍ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ກົດປຸ່ມລະດັບສຽງທັງສອງຄ້າງໄວ້ສອງສາມວິນາທີເພື່ອເປີດໃຊ້ <xliff:g id="SERVICE">%1$s</xliff:g>, ຄຸນສົມບັດການຊ່ວຍເຂົ້າເຖິງ. ນີ້ອາດປ່ຽນວິທີການເຮັດວຽກຂອງອຸປະກອນທ່ານ.\n\nທ່ານສາມາດປ່ຽນທາງລັດນີ້ເປັນຄຸນສົມບັດອື່ນໄດ້ໃນການຕັ້ງຄ່າ > ການຊ່ວຍເຂົ້າເຖິງ."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ເປີດໃຊ້"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 1879dcc..6b95757 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Jei norite tęsti, naudokite kontrolinį kodą arba ekrano užraktą"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Piršto antspaudo piktograma"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Atrakinimas pagal veidą"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Su atrakinimu pagal veidą susijusi problema"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Jei norite tęsti, naudokite veido atpažinimo funkciją arba ekrano užraktą"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Veido pkt."</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"skaityti sinchronizavimo nustatymus"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Leidžiama programai skaityti ir sinchronizuoti paskyros nustatymus. Pvz., taip gali būti nustatoma, ar su paskyra sinchronizuota Žmonių programa."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kai spartusis klavišas įjungtas, paspaudus abu garsumo mygtukus ir palaikius 3 sekundes bus įjungta pritaikymo neįgaliesiems funkcija."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Įjungti pritaikymo neįgaliesiems funkcijų spartųjį klavišą?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiamos pritaikymo neįgaliesiems funkcijos. Tai gali pakeisti įrenginio veikimą.\n\nDabartinės funkcijos:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPasirinktas funkcijas galite pakeisti skiltyje „Nustatymai“ > „Pritaikomumas“."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Įjungti „<xliff:g id="SERVICE">%1$s</xliff:g>“ spartųjį klavišą?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Paspaudus abu garsumo klavišus ir palaikius kelias sekundes įjungiama pritaikymo neįgaliesiems funkcija „<xliff:g id="SERVICE">%1$s</xliff:g>“. Tai gali pakeisti įrenginio veikimą.\n\nGalite pakeisti šį spartųjį klavišą į kitą funkciją skiltyje „Nustatymai“ > „Pritaikomumas“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Įjungti"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 15eda96..da39140 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Izmantojiet pirksta nospiedumu vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pirksta nospieduma ikona"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Autorizācija pēc sejas"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problēma ar autorizāciju pēc sejas"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Izmantojiet autorizāciju pēc sejas vai ekrāna bloķēšanas opciju, lai turpinātu"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Sejas ikona"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lasīt sinhronizācijas iestatījumus"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ļauj lietotnei lasīt konta sinhronizācijas iestatījumus. Piemēram, šādi var noteikt, vai lietotne Personas ir sinhronizēta ar kontu."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kad īsinājumtaustiņš ir ieslēgts, nospiežot abas skaļuma pogas un 3 sekundes turot tās, tiks aktivizēta pieejamības funkcija."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vai ieslēgt pieejamības funkciju saīsni?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgtas pieejamības funkcijas. Tas var mainīt ierīces darbību.\n\nPašreizējās funkcijas:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAtlasītās funkcijas varat mainīt šeit: Iestatījumi > Pieejamība."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vai ieslēgt <xliff:g id="SERVICE">%1$s</xliff:g> saīsni?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Turot nospiestus abus skaļuma taustiņus dažas sekundes, tiek ieslēgta pieejamības funkcija <xliff:g id="SERVICE">%1$s</xliff:g>. Tas var mainīt ierīces darbību.\n\nŠo saīsni uz citu funkciju varat mainīt šeit: Iestatījumi > Pieejamība."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ieslēgt"</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index b29d49e..e193c33 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користете го вашиот отпечаток или заклучување екран за да продолжите"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона за отпечатоци"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Отклучување со лик"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем со „Отклучување со лик“"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користете отклучување со лик или заклучување екран за да продолжите"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Икона"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"чита поставки за синхронизација"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Овозможува апликацијата да ги чита поставките за синхронизирање на сметка. На пример, така може да се утврди дали апликацијата „Луѓе“ е синхронизирана со сметка."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Кога е вклучена кратенката, ако ги притиснете двете копчиња за јачина на звук во времетраење од 3 секунди, ќе се стартува функција за пристапност."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Да се вклучи кратенка за функциите за пристапност?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучат функциите за пристапност. Ова може да го промени начинот на функционирање на уредот.\n\nТековни функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМоже да ги промените избраните функции во „Поставки > Пристапност“."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Да се вклучи кратенка за <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако ги задржите притиснати двете копчиња за јачина на звук неколку секунди, ќе се вклучи функцијата за пристапност <xliff:g id="SERVICE">%1$s</xliff:g>. Ова може да го промени начинот на функционирање на уредот.\n\nМоже да ја измените кратенкава да биде за друга функција во „Поставки > Пристапност“."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Вклучи"</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index 44172ea..2bbaa3a 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"തുടരാൻ നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ഫിംഗർപ്രിന്റ് ഐക്കൺ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ഫെയ്സ് അൺലോക്ക്"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ഫെയ്സ് അൺലോക്കുമായി ബന്ധപ്പെട്ട പ്രശ്നം"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"തുടരാൻ നിങ്ങളുടെ മുഖം അല്ലെങ്കിൽ സ്ക്രീൻ ലോക്ക് ഉപയോഗിക്കുക"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"മുഖത്തിന്റെ ഐക്കൺ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യുക"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ഒരു അക്കൗണ്ടിനായി സമന്വയ ക്രമീകരണങ്ങൾ റീഡുചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഉദാഹരണത്തിന്, ആളുകൾ അപ്ലിക്കേഷൻ ഒരു അക്കൗണ്ടിൽ സമന്വയിപ്പിച്ചിട്ടുണ്ടോയെന്നത് നിർണ്ണയിക്കാൻ ഇതിനാകും."</string>
@@ -815,7 +819,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 +1042,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>
@@ -1467,7 +1471,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"കുറുക്കുവഴി ഓണായിരിക്കുമ്പോൾ, രണ്ട് വോളിയം ബട്ടണുകളും 3 സെക്കൻഡ് നേരത്തേക്ക് അമർത്തുന്നത് ഉപയോഗസഹായി ഫീച്ചർ ആരംഭിക്കും."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ഉപയോഗസഹായി ഫീച്ചറുകൾക്കുള്ള കുറുക്കുവഴി ഓണാക്കണോ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത്, ഉപയോഗസഹായി ഫീച്ചറുകൾ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന രീതിയെ ഇത് മാറ്റിയേക്കാം.\n\nനിലവിലുള്ള ഫീച്ചറുകൾ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nതിരഞ്ഞെടുത്ത ഫീച്ചറുകൾ ക്രമീകരണം > ഉപയോഗസഹായി എന്നതിൽ മാറ്റാനാവും."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> കുറുക്കുവഴി ഓണാക്കണോ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"രണ്ട് വോളിയം കീകളും അൽപ്പ നേരത്തേക്ക് അമർത്തിപ്പിടിക്കുന്നത് ഉപയോഗസഹായി ഫീച്ചറായ <xliff:g id="SERVICE">%1$s</xliff:g> എന്നതിനെ ഓണാക്കുന്നു. നിങ്ങളുടെ ഉപകരണം പ്രവർത്തിക്കുന്ന വിധം ഇത് മാറ്റിയേക്കാം.\n\nക്രമീകരണം > ഉപയോഗസഹായി എന്നതിലെ മറ്റൊരു ഫീച്ചറിലേക്ക് നിങ്ങൾക്ക് ഈ കുറുക്കുവഴി മാറ്റാനാവും."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ഓണാക്കുക"</string>
@@ -1972,7 +1977,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-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4244015..bac7aa7 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Үргэлжлүүлэхийн тулд хурууны хээ эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Хурууны хээний дүрс"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Царайгаар түгжээ тайлах"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Царайгаар түгжээ тайлахтай холбоотой асуудал"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Үргэлжлүүлэхийн тулд царай эсвэл дэлгэцийн түгжээгээ ашиглана уу"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Царайны дүрс тэмдэг"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"синк тохиргоог унших"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Апп нь бүртгэлийн синк тохиргоог унших боломжтой. Жишээ нь энэ нь Хүмүүс апп бүртгэлтэй синк хийгдсэн эсэхийг тодорхойлох боломжтой."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Товчлол асаалттай үед дууны түвшний хоёр товчлуурыг хамтад нь 3 секунд дарснаар хандалтын онцлогийг эхлүүлнэ."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Хандалтын онцлогуудын товчлолыг асаах уу?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарснаар хандалтын онцлогууд асна. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nОдоогийн онцлогууд:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nТа сонгосон онцлогуудыг Тохиргоо > Хандалт хэсэгт өөрчлөх боломжтой."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g>-н товчлолыг асаах уу?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Дууны түвшний түлхүүрийг хэдэн секундийн турш зэрэг дарах нь хандалтын онцлог болох <xliff:g id="SERVICE">%1$s</xliff:g>-г асаадаг. Энэ нь таны төхөөрөмжийн ажиллах зарчмыг өөрчилж болзошгүй.\n\nТа Тохиргоо > Хандалт хэсэгт энэ товчлолыг өөр онцлогт оноож өөрчлөх боломжтой."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Асаах"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index 1747bdb..492c14d 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"पुढे सुरू ठेवण्यासाठी तुमचे फिंगरप्रिंट किंवा स्क्रीन लॉक वापरा"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिंट आयकन"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलॉक"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलॉकसंबंधित समस्या"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"पुढे सुरू ठेवण्यासाठी तुमचा चेहरा किंवा स्क्रीन लॉक वापरा"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"चेहरा आयकन"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"सिंक सेटिंग्ज वाचा"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"खात्याच्या सिंक सेटिंग्ज वाचण्यासाठी अॅप ला अनुमती देते. उदाहरणार्थ, हे खात्यासह लोकांचा अॅप संकालित केला आहे किंवा नाही हे निर्धारित करू शकते."</string>
@@ -815,7 +819,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>
@@ -1040,7 +1044,7 @@
<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="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>
@@ -1467,7 +1471,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"शॉर्टकट सुरू असताना, दोन्ही व्हॉल्यूम बटणे तीन सेकंदांसाठी दाबून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होईल."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"अॅक्सेसिबिलिटी वैशिष्ट्यांसाठी शॉर्टकट सुरू करायचा आहे का?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने अॅक्सेसिबिलिटी वैशिष्ट्ये सुरू होतात. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nसध्याची वैशिष्ट्ये:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतुम्ही हा शॉर्टकट सेटिंग्ज > अॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> शॉर्टकट सुरू करायचा आहे का?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"दोन्ही व्हॉल्यूम की काही सेकंद धरून ठेवल्याने <xliff:g id="SERVICE">%1$s</xliff:g>, एक अॅक्सेसिबिलिटी वैशिष्ट्य सुरू होते. यामुळे तुमचे डिव्हाइस कसे काम करते हे पूर्णपणे बदलते.\n\nतुम्ही हा शॉर्टकट सेटिंग्ज > अॅक्सेसिबिलिटी मध्ये बदलू शकता."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"सुरू करा"</string>
@@ -1972,7 +1977,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-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 0bf24d7..2af0cf0 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gunakan cap jari atau kunci skrin anda untuk meneruskan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon cap jari"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Buka Kunci Wajah"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isu dengan Buka Kunci Wajah"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gunakan wajah atau kunci skrin anda untuk meneruskan"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikon wajah"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"membaca tetapan penyegerakan"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Membenarkan apl membaca tetapan segerak untuk akaun. Sebagai contoh, ini boleh menentukan sama ada apl Orang disegerakkan dengan akaun."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Apabila pintasan dihidupkan, tindakan menekan kedua-dua butang kelantangan selama 3 saat akan memulakan ciri kebolehaksesan."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Hidupkan pintasan untuk ciri kebolehaksesan?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan ciri kebolehaksesan. Hal ini mungkin mengubah cara peranti anda berfungsi.\n\nCiri semasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nAnda boleh menukar ciri yang dipilih dalam Tetapan > Kebolehaksesan."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Hidupkan pintasan <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Tindakan menahan kedua-dua kekunci kelantangan selama beberapa saat akan menghidupkan <xliff:g id="SERVICE">%1$s</xliff:g>, iaitu satu ciri kebolehaksesan. Ini mungkin mengubah cara peranti anda berfungsi.\n\nAnda boleh menukar pintasan ini kepada ciri lain dalam Tetapan > Kebolehaksesan."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Hidupkan"</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 14409d8..10fd2e1 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ရှေ့ဆက်ရန် သင်၏ လက်ဗွေ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"လက်ဗွေ သင်္ကေတ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"‘မျက်နှာပြ လော့ခ်ဖွင့်ခြင်း’ ဆိုင်ရာ ပြဿနာ"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ရှေ့ဆက်ရန် သင်၏ မျက်နှာ (သို့) ဖန်သားပြင်လော့ခ်ကို သုံးပါ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"တစ်ခုခုမှားသွားသည်။ ထပ်စမ်းကြည့်ပါ။"</string>
<string name="face_icon_content_description" msgid="465030547475916280">"မျက်နှာသင်္ကေတ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ထပ်တူပြုအဆင်အပြင်အားဖတ်ခြင်း"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"အပလီကေးရှင်းအား အကောင့်တစ်ခုအတွက် ထပ်တူညီအောင် လုပ်ဆောင်မှု ဆက်တင်အား ကြည့်ခွင့် ပြုပါ။ ဥပမာ People အက်ပ်က အကောင့်တစ်ခုနဲ့ ထပ်တူညီအောင် လုပ်ရန် ဆက်သွယ်ထားမှု ရှိမရှိ သိရှိနိုင်ခြင်း"</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ဖြတ်လမ်းလင့်ခ်ကို ဖွင့်ထားစဉ် အသံထိန်းခလုတ် နှစ်ခုစလုံးကို ၃ စက္ကန့်ခန့် ဖိထားခြင်းဖြင့် အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုကို ဖွင့်နိုင်သည်။"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများအတွက် ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုများ ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nလက်ရှိ ဝန်ဆောင်မှုများ-\n<xliff:g id="SERVICE">%1$s</xliff:g>\n\'ဆက်တင်များ > အများသုံးစွဲနိုင်မှု\' တွင် ရွေးထားသည့် ဝန်ဆောင်မှုများကို ပြောင်းနိုင်သည်။"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ဖြတ်လမ်းကို ဖွင့်မလား။"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"အသံခလုတ်နှစ်ခုလုံးကို စက္ကန့်အနည်းငယ် ဖိထားခြင်းက အများသုံးစွဲနိုင်မှုဆိုင်ရာ ဝန်ဆောင်မှုဖြစ်သော <xliff:g id="SERVICE">%1$s</xliff:g> ကို ဖွင့်ပေးသည်။ ဤလုပ်ဆောင်ချက်က သင့်စက်အလုပ်လုပ်ပုံကို ပြောင်းလဲနိုင်သည်။\n\nဤဖြတ်လမ်းလင့်ခ်ကို \'ဆက်တင်များ > အများသုံးစွဲနိုင်မှု\' တွင် နောက်ဝန်ဆောင်မှုတစ်ခုသို့ ပြောင်းနိုင်သည်။"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ဖွင့်ရန်"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index d046447..ff76ed4 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Bruk fingeravtrykket eller skjermlåsen for å fortsette"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon for fingeravtrykk"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Bruk ansikts- eller skjermlåsen for å fortsette"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ansiktikon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lese synkroniseringsinnstillinger"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lar appen lese synkroniseringsinnstillingene for en konto. For eksempel kan den finne ut om Personer-appen er synkronisert med en konto."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Når snarveien er på, starter en tilgjengelighetsfunksjon når du trykker inn begge volumknappene i tre sekunder."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vil du slå på snarveien for tilgjengelighetsfunksjoner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hvis du holder inne volumtastene i noen sekunder, slås tilgjengelighetsfunksjoner på. Dette kan endre hvordan enheten din fungerer.\n\nNåværende funksjoner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan endre valgte funksjoner i Innstillinger > Tilgjengelighet."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vil du slå på <xliff:g id="SERVICE">%1$s</xliff:g>-snarveien?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hvis du holder inne begge volumtastene i noen sekunder, slår du på <xliff:g id="SERVICE">%1$s</xliff:g>, en tilgjengelighetsfunksjon. Dette kan endre hvordan enheten din fungerer.\n\nDu kan endre denne snarveien til en annen funksjon i Innstillinger > Tilgjengelighet."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Slå på"</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index 6da4072..f4f30a7 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"जारी राख्न आफ्नो फिंगरप्रिन्ट वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"फिंगरप्रिन्ट आइकन"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"फेस अनलक"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"फेस अनलक सुविधामा अनुहार दर्ता गर्ने क्रममा त्रुटि भयो"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"जारी राख्न आफ्नो फेस वा स्क्रिन लक प्रयोग गरी पुष्टि गर्नुहोस्"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"अनुहारको आइकन"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"समीकरण सेटिङहरू पढ्नुहोस्"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"एपलाई खाताको लागि सिंक सेटिङहरू पढ्न अनुमति दिन्छ। उदाहरणको लागि यसले व्यक्तिहरको एप खातासँग सिंक भएको नभएको निर्धारण गर्न सक्दछ।"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"यो सर्टकट सक्रिय हुँदा, ३ सेकेन्डसम्म दुवै भोल्युम बटन थिच्नुले पहुँचसम्बन्धी कुनै सुविधा सुरु गर्ने छ।"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"एक्सेसिबिलिटीसम्बन्धी सुविधा प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"केही सेकेन्डसम्म दुवै भोल्युम की थिचिराख्नुभयो भने पहुँचसम्बन्धी सुविधाहरू सक्रिय हुन्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nहालका सुविधाहरू:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nतपाईं सेटिङ > पहुँचमा गएर चयन गरिएका सुविधाहरू परिवर्तन गर्न सक्नुहुन्छ।"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> प्रयोग गर्न सर्टकट अन गर्ने हो?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"केही सेकेन्डसम्म दुवै भोल्युम की थिचिराख्नुले <xliff:g id="SERVICE">%1$s</xliff:g> नामक पहुँचसम्बन्धी सुविधा सक्रिय गर्छ। यसले तपाईंको यन्त्रले काम गर्ने तरिका परिवर्तन गर्न सक्छ।\n\nतपाईं सेटिङ > पहुँचमा गई यो सर्टकटमार्फत अर्को सुविधा खुल्ने बनाउन सक्नुहुन्छ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"सक्रिय गरियोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 75857ff..fd26929 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gebruik je vingerafdruk of schermvergrendeling om door te gaan"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Vingerafdruk-icoon"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ontgrendelen via gezichtsherkenning"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Probleem met Ontgrendelen via gezichtsherkenning"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gebruik je gezicht of schermvergrendeling om door te gaan"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Gezichtspictogram"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"synchronisatie-instellingen lezen"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Hiermee kan de app de synchronisatie-instellingen voor een account lezen. Dit kan bijvoorbeeld bepalen of de app Personen wordt gesynchroniseerd met een account."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Als de snelkoppeling aanstaat, houd je beide volumeknoppen 3 seconden ingedrukt om een toegankelijkheidsfunctie te starten."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Snelkoppeling voor toegankelijkheidsfuncties aanzetten?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, zet je de toegankelijkheidsfuncties aan. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nHuidige functies:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nJe kunt de geselecteerde functies wijzigen via Instellingen > Toegankelijkheid."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Snelkoppeling voor <xliff:g id="SERVICE">%1$s</xliff:g> aanzetten?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Als je beide volumetoetsen een paar seconden ingedrukt houdt, wordt de toegankelijkheidsfunctie <xliff:g id="SERVICE">%1$s</xliff:g> aangezet. Hierdoor kan de manier veranderen waarop je apparaat werkt.\n\nJe kunt deze sneltoets op een andere functie instellen via Instellingen > Toegankelijkheid."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aanzetten"</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index 11d6e7f..1c836f1 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଟିପଚିହ୍ନ କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ଟିପଚିହ୍ନ ଆଇକନ୍"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ଫେସ୍ ଅନଲକ୍"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ଫେସ୍ ଅନଲକ୍ ସହ ସମସ୍ୟା"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ଜାରି ରଖିବାକୁ ଆପଣଙ୍କ ଚେହେରା କିମ୍ବା ସ୍କ୍ରିନ୍ ଲକ୍ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ଫେସ୍ ଆଇକନ୍"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ସିଙ୍କ ସେଟିଙ୍ଗକୁ ପଢ଼ନ୍ତୁ"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ଏକ ଆକାଉଣ୍ଟ ପାଇଁ ସିଙ୍କ ସେଟିଙ୍ଗ ପଢ଼ିବାକୁ ଆପ୍ଟିକୁ ଅନୁମତି ଦିଏ। ଉଦାହରଣସ୍ୱରୂପ, ଲୋକଙ୍କ ଆପ୍ ଏକ ଆକାଉଣ୍ଟରେ ସିଙ୍କ ହୋଇଛି କି ନାହିଁ ଏହା ଜାଣିପାରେ।"</string>
@@ -1038,9 +1042,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>
@@ -1467,7 +1471,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ସର୍ଟକଟ୍ ଚାଲୁ ଥିବା ବେଳେ, ଉଭୟ ଭଲ୍ୟୁମ୍ ବଟନ୍ 3 ସେକେଣ୍ଡ ପାଇଁ ଦବାଇବା ଦ୍ୱାରା ଏକ ଆକ୍ସେସବିଲିଟି ଫିଚର୍ ଆରମ୍ଭ ହେବ।"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ପାଇଁ ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଆକ୍ସେସିବିଲିଟୀ ଫିଚରଗୁଡ଼ିକ ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nବର୍ତ୍ତମାନର ଫିଚରଗୁଡ଼ିକ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n ଆପଣ ସେଟିଂସ୍ &gt ଆକ୍ସେସିବିଲିଟୀରେ ଚୟନିତ ଫିଚରଗୁଡ଼ିକୁ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> ସର୍ଟକଟ୍ ଚାଲୁ କରିବେ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"କିଛି ସେକେଣ୍ଡ ପାଇଁ ଉଭୟ ଭଲ୍ୟୁମ୍ କୀ’କୁ ଧରି ରଖିବା ଫଳରେ ଏକ ଆକ୍ସେସିବିଲିଟୀ ଫିଚର୍ <xliff:g id="SERVICE">%1$s</xliff:g> ଚାଲୁ ହୁଏ। ଏହା ଆପଣଙ୍କ ଡିଭାଇସ୍ କିପରି କାମ କରେ ତାହା ପରିବର୍ତ୍ତନ କରିପାରେ।\n\nଆପଣ ସେଟିଂସ୍ &gt ଆକ୍ସେସିବିଲିଟୀରେ ଏହି ସର୍ଚକଟକୁ ଅନ୍ୟ ଏକ ଫିଚରରେ ପରିବର୍ତ୍ତନ କରିପାରିବେ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ଚାଲୁ କରନ୍ତୁ"</string>
@@ -1972,7 +1977,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 2648296..7788bf3 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਫਿੰਗਰਪ੍ਰਿੰਟ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ਫਿੰਗਰਪ੍ਰਿੰਟ ਪ੍ਰਤੀਕ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ਫ਼ੇਸ ਅਣਲਾਕ"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ਫ਼ੇਸ ਅਣਲਾਕ ਨਾਲ ਸਮੱਸਿਆ"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ਜਾਰੀ ਰੱਖਣ ਲਈ ਆਪਣਾ ਚਿਹਰਾ ਜਾਂ ਸਕ੍ਰੀਨ ਲਾਕ ਵਰਤੋ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ਚਿਹਰਾ ਪ੍ਰਤੀਕ"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ਸਿੰਕ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹੋ"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ਐਪ ਨੂੰ ਕਿਸੇ ਖਾਤੇ ਲਈ ਸਮਕਾਲੀਕਰਨ ਸੈਟਿੰਗਾਂ ਪੜ੍ਹਨ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ। ਉਦਾਹਰਨ ਲਈ, ਇਹ ਪਤਾ ਕਰ ਸਕਦਾ ਹੈ ਕਿ People ਐਪ ਦਾ ਕਿਸੇ ਖਾਤੇ ਨਾਲ ਸਮਕਾਲੀਕਿਰਤ ਕੀਤਾ ਗਿਆ ਹੈ ਜਾਂ ਨਹੀਂ।"</string>
@@ -815,7 +819,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਹੋਣ \'ਤੇ, ਕਿਸੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਸ਼ੁਰੂ ਕਰਨ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ ਬਟਨਾਂ ਨੂੰ 3 ਸਕਿੰਟ ਲਈ ਦਬਾ ਕੇ ਰੱਖੋ।"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ਕੀ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਲਈ ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ, ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਮੌਜੂਦਾ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਚੁਣੀਆਂ ਗਈਆਂ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਨੂੰ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"ਕੀ <xliff:g id="SERVICE">%1$s</xliff:g> ਸ਼ਾਰਟਕੱਟ ਚਾਲੂ ਕਰਨਾ ਹੈ?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"ਕੁਝ ਸਕਿੰਟਾਂ ਲਈ ਦੋਵੇਂ ਅਵਾਜ਼ੀ ਕੁੰਜੀਆਂ ਨੂੰ ਦਬਾਈ ਰੱਖਣਾ <xliff:g id="SERVICE">%1$s</xliff:g>, ਇੱਕ ਪਹੁੰਚਯੋਗਤਾ ਵਿਸ਼ੇਸ਼ਤਾ ਨੂੰ ਚਾਲੂ ਕਰ ਦਿੰਦਾ ਹੈ। ਇਹ ਤੁਹਾਡੇ ਡੀਵਾਈਸ ਦੇ ਕੰਮ ਕਰਨ ਦੇ ਤਰੀਕੇ ਨੂੰ ਬਦਲ ਸਕਦਾ ਹੈ।\n\nਸੈਟਿੰਗਾਂ ਅਤੇ ਪਹੁੰਚਯੋਗਤਾ ਵਿੱਚ ਤੁਸੀਂ ਇਸ ਸ਼ਾਰਟਕੱਟ ਨੂੰ ਕਿਸੇ ਹੋਰ ਵਿਸ਼ੇਸ਼ਤਾ ਵਿੱਚ ਬਦਲ ਸਕਦੇ ਹੋ।"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ਚਾਲੂ ਕਰੋ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index b72b000..3b90bc4 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Aby kontynuować, użyj odcisku palca lub blokady ekranu"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odcisku palca"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Rozpoznawanie twarzy"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem z rozpoznawaniem twarzy"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Aby kontynuować, użyj rozpoznawania twarzy lub blokady ekranu"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona twarzy"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"czytanie ustawień synchronizacji"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Zezwala aplikacji na odczyt ustawień synchronizacji konta. Pozwala to na przykład określić, czy aplikacja Ludzie jest zsynchronizowana z kontem."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Gdy skrót jest włączony, jednoczesne naciskanie przez trzy sekundy obu przycisków głośności uruchamia funkcję ułatwień dostępu."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Włączyć skrót ułatwień dostępu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza ułatwienia dostępu. Może to zmienić sposób działania urządzenia.\n\nBieżące funkcje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\naby zmienić wybrane funkcje, kliknij Ustawienia > Ułatwienia dostępu."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Włączyć skrót <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Przytrzymanie obu klawiszy głośności przez kilka sekund włącza usługę <xliff:g id="SERVICE">%1$s</xliff:g>, stanowiącą ułatwienie dostępu. Może to zmienić sposób działania urządzenia.\n\nAby zmienić ten skrót i wskazać inną funkcję, kliknij Ustawienia > Ułatwienia dostępu."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Włącz"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 8198ae9..a38c6c6 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. > Acessibilidade\"."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index 5a336ae..0f5ddd9 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Utilize a impressão digital ou o bloqueio de ecrã para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo correu mal. Tente novamente."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Utilize o rosto ou o bloqueio de ecrã para continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo correu mal. Tente novamente."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone de rosto"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler definições de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que a app leia as definições de sincronização de uma conta. Por exemplo, pode determinar se a app Pessoas está sincronizada com uma conta."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho está ativado, premir ambos os botões de volume durante 3 segundos inicia uma funcionalidade de acessibilidade."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Pretende ativar o atalho das funcionalidades de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter premidas ambas as teclas de volume durante alguns segundos ativa as funcionalidades de acessibilidade. Estas podem alterar a forma como o seu dispositivo funciona.\n\nFuncionalidades atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\npode alterar as funcionalidades selecionadas em Definições > Acessibilidade."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Pretende ativar o atalho do serviço <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter premidas ambas as teclas de volume durante alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, uma funcionalidade de acessibilidade. Esta pode alterar a forma como o seu dispositivo funciona.\n\nPode alterar este atalho para outra funcionalidade em Definições > Acessibilidade."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 8198ae9..a38c6c6 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Use sua impressão digital ou o bloqueio de tela para continuar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Algo deu errado. Tente de novo."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ícone de impressão digital"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Desbloqueio facial"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problema com o Desbloqueio facial"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Use seu rosto ou o bloqueio de tela para continuar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Algo deu errado. Tente de novo."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Ícone facial"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ler as configurações de sincronização"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite que o app leia as configurações de sincronização de uma conta. Por exemplo, pode determinar se o app People está sincronizado com uma conta."</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Quando o atalho estiver ativado, pressione os dois botões de volume por três segundos para iniciar um recurso de acessibilidade."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ativar atalho para recursos de acessibilidade?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Manter as duas teclas de volume pressionadas por alguns segundos ativa os recursos de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nRecursos atuais:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nÉ possível mudar os recursos selecionados em \"Config. > Acessibilidade\"."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ativar atalho para <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Manter as duas teclas de volume pressionadas por alguns segundos ativa o serviço <xliff:g id="SERVICE">%1$s</xliff:g>, um recurso de acessibilidade. Isso pode mudar a forma como seu dispositivo funciona.\n\nÉ possível trocar o uso desse atalho para outro recurso em \"Config. > Acessibilidade\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Ativar"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index ae0a629..02a5a56 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Folosiți amprenta sau blocarea ecranului pentru a continua"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Pictograma amprentă"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Deblocare facială"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problemă cu Deblocarea facială"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Folosiți-vă chipul sau blocarea ecranului pentru a continua"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Pictograma chip"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"citire setări sincronizare"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Permite aplicației să citească setările de sincronizare ale unui cont. De exemplu, cu această permisiune aplicația poate determina dacă aplicația Persoane este sincronizată cu un anumit cont."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Atunci când comanda rapidă este activată, dacă apăsați ambele butoane de volum timp de trei secunde, veți lansa o funcție de accesibilitate."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Activați comanda rapidă pentru funcțiile de accesibilitate?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Dacă apăsați ambele taste de volum câteva secunde, activați funcțiile de accesibilitate. Acest lucru poate schimba funcționarea dispozitivului.\n\nFuncțiile actuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuteți schimba funcțiile selectate din Setări > Accesibilitate."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Activați comanda rapidă <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Dacă apăsați ambele taste de volum câteva secunde, activați funcția de accesibilitate <xliff:g id="SERVICE">%1$s</xliff:g>. Acest lucru poate schimba funcționarea dispozitivului.\n\nPuteți alege altă funcție pentru această comandă în Setări > Accesibilitate."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Activați"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 8d3edf1..f78bba2 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Чтобы продолжить, используйте отпечаток пальца или данные для разблокировки экрана."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок отпечатка пальца"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Ошибка фейсконтроля"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Чтобы продолжить, посмотрите на экран или используйте данные для разблокировки."</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Значок лица"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"Просмотр настроек синхронизации"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Приложение сможет просматривать настройки синхронизации аккаунта, например определять, включена ли синхронизация для приложения \"Контакты\"."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Чтобы использовать функцию специальных возможностей, когда она включена, нажмите и удерживайте обе кнопки регулировки громкости в течение трех секунд."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Использовать быстрое включение?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Чтобы включить специальные возможности, нажмите обе кнопки регулировки громкости и удерживайте несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nТекущие функции:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nЧтобы изменить выбранные функции, перейдите в настройки и нажмите \"Специальные возможности\"."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Использовать быстрое включение сервиса \"<xliff:g id="SERVICE">%1$s</xliff:g>\"?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Чтобы включить функцию \"<xliff:g id="SERVICE">%1$s</xliff:g>\", нажмите обе кнопки регулировки громкости на несколько секунд. Обратите внимание, что в работе устройства могут произойти изменения.\n\nЧтобы назначить это сочетание клавиш другой функции, перейдите в настройки и выберите \"Специальные возможности\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Включить"</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 132ee6f..0fdb547 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ඉදිරියට යාමට ඔබගේ ඇඟිලි සලකුණ හෝ තිර අගුල භාවිත කරන්න"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ඇඟිලි සලකුණු නිරූපකය"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"මුහුණෙන් අගුළු හැරීම"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"මුහුණෙන් අගුලු හැරීම සම්බන්ධව ගැටලුවකි"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ඉදිරියට යාමට ඔබගේ මුහුණු හෝ තිර අගුල භාවිත කරන්න"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"මුහුණ නිරූපකය"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"සමමුහුර්ත සැකසීම් කියවන්න"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ගිණුම සඳහා සමමුහුර්ත සැකසීම් කියවීමට යෙදුමට අවසර දෙන්න. උදාහරණයක් ලෙස, ගිණුමක් සමඟ පුද්ගල යෙදුම සමමුහුර්ත දැයි මෙයට හඳුනා ගත හැක."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"කෙටිමග ක්රියාත්මක විට, හඬ පරිමා බොත්තම් දෙකම තත්පර 3ක් තිස්සේ එබීමෙන් ප්රවේශ්යතා විශේෂාංගය ආරම්භ වනු ඇත."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ප්රවේශ්යතා විශේෂාංග සඳහා කෙටි මග ක්රියාත්මක කරන්නද?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්රවේශ්යතා විශේෂාංග ක්රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nවත්මන් විශේෂාංග:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nඔබට තේරූ විශේෂාංග සැකසීම් > ප්රවේශ්යතාව හි වෙනස් කළ හැකිය."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> කෙටි මග ක්රියාත්මක කරන්නද?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"හඬ පරිමා යතුරු දෙකම තත්පර කීපයකට පහළට අල්ලාගෙන සිටීම ප්රවේශ්යතා විශේෂාංගයක් වන <xliff:g id="SERVICE">%1$s</xliff:g> ක්රියාත්මක කරයි. මෙය ඔබේ උපාංගය ක්රියා කරන ආකාරය වෙනස් කළ හැකිය.\n\nඔබට මෙම කෙටිමග සැකසීම් > ප්රවේශ්යතාව හි තවත් විශේෂාංගයකට වෙනස් කළ හැකිය."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ක්රියාත්මක කරන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 67b0ce0..b626cc8 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>
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Pokračujte použitím odtlačku prsta alebo zámky obrazovky"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona odtlačku prsta"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odomknutie tvárou"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problém s odomknutím tvárou"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Pokračujte použitím tváre alebo zámky obrazovky"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona tváre"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"čítať nastavenia synchronizácie"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Umožňuje aplikácii čítať nastavenia synchronizácie v účte. Môže napríklad určiť, či je s účtom synchronizovaná aplikácia Ľudia."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Keď je skratka zapnutá, stlačením obidvoch tlačidiel hlasitosti na tri sekundy spustíte funkciu dostupnosti."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Chcete zapnúť skratku pre funkcie dostupnosti?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Pridržaním oboch tlačidiel hlasitosti na niekoľko sekúnd zapnete funkcie dostupnosti. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nAktuálne funkcie:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nVybrané funkcie môžete zmeniť v časti Nastavenia > Dostupnosť."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Chcete zapnúť skratku na službu <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Pridržaním oboch klávesov hlasitosti na niekoľko sekúnd zapnete funkciu dostupnosti <xliff:g id="SERVICE">%1$s</xliff:g>. Môže sa tým zmeniť spôsob fungovania vášho zariadenia.\n\nTúto skratku môžete zmeniť na inú funkciu v časti Nastavenia > Dostupnosť."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Zapnúť"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index d632e0c..9619cf1 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -615,6 +615,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Za nadaljevanje uporabite prstni odtis ali odklepanje s poverilnico."</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona prstnih odtisov"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Odklepanje z obrazom"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Težava z odklepanjem z obrazom"</string>
@@ -667,6 +669,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Za nadaljevanje uporabite obraz ali odklepanje s poverilnico."</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona obraza"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"branje nastavitev sinhronizacije"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Aplikaciji omogoča branje nastavitev sinhronizacije za račun. S tem lahko aplikacija na primer ugotovi, ali je aplikacija Ljudje sinhronizirana z računom."</string>
@@ -1735,7 +1739,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Ko je bližnjica vklopljena, pritisnite gumba za glasnost in ju pridržite tri sekunde, če želite zagnati funkcijo za ljudi s posebnimi potrebami."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Želite vklopiti bližnjico za funkcije za ljudi s posebnimi potrebami?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili funkcije za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTrenutne funkcije:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nIzbrane funkcije lahko spremenite v meniju »Nastavitve« > »Funkcije za ljudi s posebnimi potrebami«."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Želite vklopiti bližnjico za <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Če za nekaj sekund pridržite obe tipki za glasnost, boste vklopili storitev <xliff:g id="SERVICE">%1$s</xliff:g>, ki je funkcija za ljudi s posebnimi potrebami. To lahko spremeni način delovanja naprave.\n\nTo bližnjico lahko v meniju »Nastavitve« > »Funkcije za ljudi s posebnimi potrebami« spremenite, da bo uporabljena za drugo funkcijo."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vklopi"</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 239c9f8..7319628 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Përdor gjurmën tënde të gishtit ose kyçjen e ekranit për të vazhduar"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikona e gjurmës së gishtit"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Shkyçja me fytyrë"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem me \"Shkyçjen me fytyrë\""</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Përdor fytyrën tënde ose kyçjen e ekranit për të vazhduar"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ikona e fytyrës"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"lexo cilësimet e sinkronizimit"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Lejon aplikacionin të lexojë cilësimet e sinkronizimit për një llogari. Për shembull, kjo mund të përcaktojë nëse aplikacioni \"Kontaktet\" është i sinkronizuar me një llogari."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kur shkurtorja është e aktivizuar, shtypja e të dy butonave për 3 sekonda do të nisë një funksion qasshmërie."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Të aktivizohet shkurtorja për veçoritë e qasshmërisë?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon veçoritë e qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nVeçoritë aktuale:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nKe ndryshuar veçoritë e zgjedhura te Cilësimet > Qasshmëria."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Të aktivizohet shkurtorja për <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mbajtja shtypur e dy tasteve të volumit për pak sekonda aktivizon <xliff:g id="SERVICE">%1$s</xliff:g>, një veçori të qasshmërisë. Kjo mund të ndryshojë mënyrën se si funksionon pajisja jote.\n\nMund të ndryshosh këtë shkurtore te një veçori tjetër te Cilësimet > Qasshmëria."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivizo"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index cd03394..76076aa 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -612,6 +612,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Користите отисак прста или закључавање екрана да бисте наставили"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Икона отиска прста"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Откључавање лицем"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Проблем са откључавање лицем"</string>
@@ -664,6 +666,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Користите лице или закључавање екрана да бисте наставили"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Икона лица"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"читање подешавања синхронизације"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозвољава апликацији да чита подешавања синхронизације за налог. На пример, овако може да се утврди да ли је апликација Људи синхронизована са налогом."</string>
@@ -1713,7 +1717,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Када је пречица укључена, притисните оба дугмета за јачину звука да бисте покренули функцију приступачности."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Желите да укључите пречицу за функције приступачности?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ако задржите оба тастера за јачину звука пар секунди, укључиће се функције приступачности. То може да промени начин рада уређаја.\n\nПостојеће функције:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nМожете да промените изабране функције у одељку Подешавања > Приступачност."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Желите да укључите пречицу за услугу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ако задржите оба тастера за јачину звука пар секунди, укључује се <xliff:g id="SERVICE">%1$s</xliff:g>, функција приступачности. То може да промени начин рада уређаја.\n\nМожете да промените функцију на коју се односи ова пречица у одељку Подешавања > Приступачност."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Укључи"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 940ee56..3c41779 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Fortsätt med hjälp av ditt fingeravtryck eller skärmlåset"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Ikon för fingeravtryck"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ansiktslås"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Problem med ansiktslås"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Fortsätt med hjälp av ditt ansikte eller skärmlåset"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Ansikte"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"läsa synkroniseringsinställningar"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Tillåter att appen läser synkroniseringsinställningarna för ett konto. Detta kan användas till exempel för att avgöra om appen Personer är synkroniserad med ett konto."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"När kortkommandot har aktiverats startar du en tillgänglighetsfunktion genom att trycka ned båda volymknapparna i tre sekunder."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vill du aktivera genvägen till tillgänglighetsfunktioner?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras tillgänglighetsfunktionerna. Det kan få enheten ett fungera annorlunda.\n\nAktuella funktioner:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nDu kan ändra vilka funktioner som aktiveras under Inställningar > Tillgänglighet."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vill du aktivera genvägen till <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Om du trycker ned båda volymknapparna i ett par sekunder aktiveras <xliff:g id="SERVICE">%1$s</xliff:g>, en tillgänglighetsfunktion. Det kan leda till att enheten fungerar annorlunda.\n\nDu kan ändra vilken funktion som ska aktiveras med genvägen under Inställningar > Tillgänglighet."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Aktivera"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index fbee2c3..d5536ab 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Tumia alama ya kidole au mbinu yako ya kufunga skrini ili uendelee"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Aikoni ya alama ya kidole"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Kufungua kwa Uso"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Hitilafu imetokea kwenye kipengele cha Kufungua kwa Uso"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Tumia uso au mbinu yako ya kufunga skrini ili uendelee"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Aikoni ya uso"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"kusoma mipangilio ya usawazishaji"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Inaruhusu programu kusoma mipangilio ya upatanishi wa akaunti. Kwa mfano, huku kunaweza kuamua kama programu ya Watu imepatanishwa na akaunti."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Unapowasha kipengele cha njia ya mkato, hatua ya kubonyeza vitufe vyote viwili vya sauti kwa sekunde tatu itafungua kipengele cha ufikivu."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Ungependa kuwasha njia ya mkato ya vipengele vya ufikivu?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha vipengele vya ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nVipengele vya sasa:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUnaweza kubadilisha vipengele ulivyochagua katika Mipangilio > Ufikivu."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Ungependa kuwasha njia ya mkato ya <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Hatua ya kushikilia chini vitufe vyote viwili vya sauti kwa sekunde chache huwasha <xliff:g id="SERVICE">%1$s</xliff:g>, kipengele cha ufikivu. Huenda hatua hii ikabadilisha jinsi kifaa chako kinavyofanya kazi.\n\nUnaweza kubadilisha njia hii ya mkato iwe kipengele kingine katika Mipangilio > Ufikivu."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Washa"</string>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 34b6a54..861e329 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -51,5 +51,10 @@
<!-- If true, show multiuser switcher by default unless the user specifically disables it. -->
<bool name="config_showUserSwitcherByDefault">true</bool>
+
+ <!-- Enable dynamic keyguard positioning for large-width screens. This will cause the keyguard
+ to be aligned to one side of the screen when in landscape mode. -->
+ <bool name="config_enableDynamicKeyguardPositioning">true</bool>
+
</resources>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 4a5be62..481a69d 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>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"தொடர, உங்கள் கைரேகையையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"கைரேகை ஐகான்"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"முகம் காட்டித் திறத்தல்"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"முகம் காட்டித் திறத்தல் அம்சத்தில் சிக்கல்"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"தொடர, உங்கள் முகத்தையோ திரைப் பூட்டையோ பயன்படுத்துங்கள்"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"முக ஐகான்"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"ஒத்திசைவு அமைப்புகளைப் படித்தல்"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"கணக்கிற்கான ஒத்திசைவு அமைப்புகளைப் படிக்க ஆப்ஸை அனுமதிக்கிறது. எடுத்துக்காட்டாக, பீப்பிள் ஆப்ஸ் கணக்குடன் ஒத்திசைக்கப்பட்டுள்ளதா என்பதை இது தீர்மானிக்கலாம்."</string>
@@ -815,7 +819,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 +852,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"ஷார்ட்கட் இயக்கத்தில் இருக்கும்போது ஒலியளவு பட்டன்கள் இரண்டையும் 3 வினாடிகளுக்கு அழுத்தினால் அணுகல்தன்மை அம்சம் இயக்கப்படும்."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"அணுகல்தன்மை அம்சங்களுக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருந்தால் அணுகல்தன்மை அம்சங்கள் ஆன் செய்யப்படும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nதற்போதைய அம்சங்கள்:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nதேர்ந்தெடுத்த அம்சங்களை அமைப்புகள் > அணுகல்தன்மைக்குச் சென்று உங்களால் மாற்ற முடியும்."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> அம்சத்துக்கான ஷார்ட்கட்டை ஆன் செய்யவா?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"இரண்டு ஒலியளவு விசைகளையும் சில விநாடிகள் பிடித்திருப்பதால் அணுகல்தன்மை அம்சமான <xliff:g id="SERVICE">%1$s</xliff:g> ஆன் ஆகும். இதனால் உங்கள் சாதனம் வேலை செய்யும் முறை மாறக்கூடும்.\n\nஅமைப்புகள் > அணுகல்தன்மைக்குச் சென்று இந்த ஷார்ட்கட்டை வேறு அம்சத்திற்கு மாற்ற முடியும்."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ஆன் செய்"</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 3e4f65c..a96b6bf 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>
@@ -305,8 +305,8 @@
<string name="permgrouplab_contacts" msgid="4254143639307316920">"కాంటాక్ట్లు"</string>
<string name="permgroupdesc_contacts" msgid="9163927941244182567">"మీ కాంటాక్ట్లను యాక్సెస్ చేయడానికి"</string>
<string name="permgrouplab_location" msgid="1858277002233964394">"లొకేషన్"</string>
- <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర స్థానాన్ని యాక్సెస్ చేయడానికి"</string>
- <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
+ <string name="permgroupdesc_location" msgid="1995955142118450685">"ఈ పరికర లొకేషన్ను యాక్సెస్ చేయడానికి"</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>
@@ -410,11 +410,11 @@
<string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్ను అనుమతిస్తుంది. అత్యధిక వినియోగం వలన టాబ్లెట్ నెమ్మదిగా పని చేయవచ్చు లేదా అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన అస్థిరంగా మారవచ్చు."</string>
<string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్ని అనుమతిస్తుంది. ఎక్కువగా వినియోగిస్తే అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన టీవీ నెమ్మదిగా పని చేయవచ్చు లేదా అస్థిరంగా మారవచ్చు."</string>
<string name="permdesc_broadcastSticky" product="default" msgid="134529339678913453">"ప్రసారం ముగిసిన తర్వాత భద్రపరచబడే ప్రసారాలను పంపడానికి యాప్ను అనుమతిస్తుంది. అత్యధిక వినియోగం వలన ఫోన్ నెమ్మదిగా పని చేయవచ్చు లేదా అధిక పరిమాణంలో మెమరీని ఉపయోగించడం వలన అస్థిరంగా మారవచ్చు."</string>
- <string name="permlab_readContacts" msgid="8776395111787429099">"మీ పరిచయాలను చదవడం"</string>
+ <string name="permlab_readContacts" msgid="8776395111787429099">"మీ కాంటాక్ట్లను చదవడం"</string>
<string name="permdesc_readContacts" product="tablet" msgid="6430093481659992692">"టాబ్లెట్లో నిల్వ చేసిన మీ కాంటాక్ట్లకు సంబంధించిన డేటాను చదవడానికి యాప్ను అనుమతిస్తుంది. కాంటాక్ట్లను సృష్టించిన మీ టాబ్లెట్లోని ఖాతాలకు కూడా యాప్లకు యాక్సెస్ ఉంటుంది. ఇందులో మీరు ఇన్స్టాల్ చేసిన యాప్ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్లను అనుమతిస్తుంది, హానికరమైన యాప్లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
<string name="permdesc_readContacts" product="tv" msgid="8400138591135554789">"మీ Android TV పరికరంలో నిల్వ చేసిన కాంటాక్ట్లకు సంబంధించిన డేటాను చదవడానికి యాప్ను అనుమతిస్తుంది. కాంటాక్ట్లను సృష్టించిన మీ Android TV పరికరంలోని ఖాతాలకు కూడా యాప్లకు యాక్సెస్ ఉంటుంది. ఇందులో మీరు ఇన్స్టాల్ చేసిన యాప్ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్లను అనుమతిస్తుంది, హానికరమైన యాప్లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
<string name="permdesc_readContacts" product="default" msgid="4911989776203207644">"ఫోన్లో నిల్వ చేసిన మీ కాంటాక్ట్లకు సంబంధించిన డేటాను చదవడానికి యాప్ను అనుమతిస్తుంది. కాంటాక్ట్లను సృష్టించిన మీ ఫోన్లోని ఖాతాలను కూడా యాప్లు యాక్సెస్ చేయగలవు. ఇందులో మీరు ఇన్స్టాల్ చేసిన యాప్ల ద్వారా సృష్టించబడిన ఖాతాలు ఉండవచ్చు. ఈ అనుమతి, మీ కాంటాక్ట్ డేటాను సేవ్ చేయడానికి యాప్లను అనుమతిస్తుంది, హానికరమైన యాప్లు మీకు తెలియకుండానే కాంటాక్ట్ డేటాను షేర్ చేయవచ్చు."</string>
- <string name="permlab_writeContacts" msgid="8919430536404830430">"మీ పరిచయాలను సవరించడం"</string>
+ <string name="permlab_writeContacts" msgid="8919430536404830430">"మీ కాంటాక్ట్లను సవరించడం"</string>
<string name="permdesc_writeContacts" product="tablet" msgid="6422419281427826181">"మీ టాబ్లెట్లో నిల్వ చేసి ఉన్న కాంటాక్ట్లకు సంబంధించిన డేటాను సవరించడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్లను అనుమతిస్తుంది."</string>
<string name="permdesc_writeContacts" product="tv" msgid="6488872735379978935">"మీ Android TV పరికరంలో నిల్వ చేసి ఉన్న కాంటాక్ట్లకు సంబంధించిన డేటాను సవరించడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్లను అనుమతిస్తుంది."</string>
<string name="permdesc_writeContacts" product="default" msgid="8304795696237065281">"మీ ఫోన్లో నిల్వ చేసి ఉన్న కాంటాక్ట్లకు సంబంధించిన డేటాను సవరించడానికి యాప్ను అనుమతిస్తుంది. ఈ అనుమతి, కాంటాక్ట్ డేటాను తొలగించడానికి యాప్లను అనుమతిస్తుంది."</string>
@@ -434,13 +434,13 @@
<string name="permdesc_writeCalendar" product="tablet" msgid="8722230940717092850">"ఈ యాప్ మీ టాబ్లెట్లో క్యాలెండర్ ఈవెంట్లను జోడించగలదు, తీసివేయగలదు లేదా మార్చగలదు. ఈ యాప్ క్యాలెండర్ యజమానుల నుండి వచ్చినట్లుగా మెసేజ్లను పంపగలదు లేదా ఈవెంట్లను వాటి యజమానులకు తెలియకుండానే మార్చగలదు."</string>
<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="permlab_accessLocationExtraCommands" msgid="5162339812057983988">"అదనపు లొకేషన్ ప్రొవైడర్ కమాండ్లను యాక్సెస్ చేయడం"</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>
- <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"నేపథ్యంలో స్థానాన్ని యాక్సెస్ చేయి"</string>
+ <string name="permlab_accessBackgroundLocation" msgid="1721164702777366138">"బ్యాక్గ్రౌండ్లో లొకేషన్ను యాక్సెస్ చేయి"</string>
<string name="permdesc_accessBackgroundLocation" msgid="8264885066095638105">"యాప్ ఉపయోగంలో లేనప్పటికీ కూడా, ఈ యాప్, లొకేషన్ను ఎప్పుడైనా యాక్సెస్ చేయగలదు."</string>
<string name="permlab_modifyAudioSettings" msgid="6129039778010031815">"మీ ఆడియో సెట్టింగ్లను మార్చడం"</string>
<string name="permdesc_modifyAudioSettings" msgid="8687227609663124921">"వాల్యూమ్ మరియు అవుట్పుట్ కోసం ఉపయోగించాల్సిన స్పీకర్ వంటి సార్వజనీన ఆడియో సెట్టింగ్లను సవరించడానికి యాప్ను అనుమతిస్తుంది."</string>
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"కొనసాగించడానికి మీ వేలిముద్ర లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"వేలిముద్ర చిహ్నం"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"ఫేస్ అన్లాక్"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"ఫేస్ అన్లాక్తో సమస్య"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"కొనసాగించడానికి మీ ముఖం లేదా స్క్రీన్ లాక్ను ఉపయోగించండి"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ముఖ చిహ్నం"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"సింక్ సెట్టింగ్లను చదవగలగడం"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ఖాతా యొక్క సింక్ సెట్టింగ్లను చదవడానికి యాప్ను అనుమతిస్తుంది. ఉదాహరణకు, వ్యక్తుల యాప్ ఖాతాతో సమకాలీకరించబడాలా లేదా అనే విషయాన్ని ఇది నిశ్చయించవచ్చు."</string>
@@ -848,7 +852,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 +920,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>
@@ -1006,7 +1010,7 @@
<string name="permlab_readHistoryBookmarks" msgid="9102293913842539697">"మీ వెబ్ బుక్మార్క్లు మరియు చరిత్రను చదవడం"</string>
<string name="permdesc_readHistoryBookmarks" msgid="2323799501008967852">"బ్రౌజర్ సందర్శించిన అన్ని URLల చరిత్ర గురించి మరియు అన్ని బ్రౌజర్ బుక్మార్క్ల గురించి చదవడానికి యాప్ను అనుమతిస్తుంది. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
<string name="permlab_writeHistoryBookmarks" msgid="6090259925187986937">"వెబ్ బుక్మార్క్లు మరియు చరిత్రను వ్రాయడం"</string>
- <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"మీ టాబ్లెట్లో నిల్వ చేయబడిన బ్రౌజర్ చరిత్రను లేదా బుక్మార్క్లను సవరించడానికి యాప్ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా సవరించడానికి యాప్ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
+ <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="573341025292489065">"మీ టాబ్లెట్లో నిల్వ చేయబడిన బ్రౌజర్ హిస్టరీని, బుక్మార్క్లను ఎడిట్ చేయడానికి యాప్ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా ఎడిట్ చేయడానికి యాప్ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతిని థర్డ్ పార్టీ బ్రౌజర్లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్లు అమలు చేయకపోవచ్చు."</string>
<string name="permdesc_writeHistoryBookmarks" product="tv" msgid="88642768580408561">"మీ Android TV పరికరంలో నిల్వ చేసిన బ్రౌజర్ చరిత్ర లేదా బుక్మార్క్లను సవరించడానికి యాప్ని అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను తీసివేయడానికి లేదా సవరించడానికి యాప్ని అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ-పక్ష బ్రౌజర్లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్ల ద్వారా అమలు కాకపోవచ్చు."</string>
<string name="permdesc_writeHistoryBookmarks" product="default" msgid="2245203087160913652">"మీ ఫోన్లో నిల్వ చేయబడిన బ్రౌజర్ చరిత్రను లేదా బుక్మార్క్లను సవరించడానికి యాప్ను అనుమతిస్తుంది. ఇది బ్రౌజర్ డేటాను ఎరేజ్ చేయడానికి లేదా సవరించడానికి యాప్ను అనుమతించవచ్చు. గమనిక: ఈ అనుమతి మూడవ పక్షం బ్రౌజర్లు లేదా వెబ్ బ్రౌజింగ్ సామర్థ్యాలు గల ఇతర యాప్ల ద్వారా అమలు చేయబడకపోవచ్చు."</string>
<string name="permlab_setAlarm" msgid="1158001610254173567">"అలారం సెట్ చేయడం"</string>
@@ -1014,7 +1018,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 +1043,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>
@@ -1197,7 +1201,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>
@@ -1208,9 +1212,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>
@@ -1274,7 +1278,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>
@@ -1293,7 +1297,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>
@@ -1385,9 +1389,9 @@
<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="sharing_remote_bugreport_notification_title" msgid="3077385149217638550">"బగ్ రిపోర్ట్ను భాగస్వామ్యం చేస్తోంది..."</string>
- <string name="share_remote_bugreport_notification_message_finished" msgid="7325635795739260135">"మీ నిర్వాహకులు ఈ పరికరం సమస్యకు పరిష్కారాన్ని కనుగొనడంలో సహాయం కోసం బగ్ రిపోర్ట్ను అభ్యర్థించారు. యాప్లు మరియు డేటా భాగస్వామ్యం చేయబడవచ్చు."</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>
<string name="decline_remote_bugreport_action" msgid="4040894777519784346">"తిరస్కరిస్తున్నాను"</string>
<string name="select_input_method" msgid="3971267998568587025">"ఇన్పుట్ పద్ధతిని ఎంచుకోండి"</string>
@@ -1419,7 +1423,7 @@
<string name="ext_media_unmountable_notification_message" product="automotive" msgid="2274596120715020680">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది. తొలగించడానికి ట్యాప్ చేయండి"</string>
<string name="ext_media_unsupported_notification_title" msgid="4358280700537030333">"<xliff:g id="NAME">%s</xliff:g>కి మద్దతు లేదు"</string>
<string name="ext_media_unsupported_notification_title" product="automotive" msgid="6004193172658722381">"<xliff:g id="NAME">%s</xliff:g> పని చేయటం లేదు"</string>
- <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"ఈ పరికరం ఈ <xliff:g id="NAME">%s</xliff:g>కి మద్దతు ఇవ్వదు. మద్దతు కలిగిన ఆకృతిలో సెటప్ చేయడానికి నొక్కండి."</string>
+ <string name="ext_media_unsupported_notification_message" msgid="917738524888367560">"ఈ పరికరం ఈ <xliff:g id="NAME">%s</xliff:g>కు సపోర్ట్ ఇవ్వదు. సపోర్ట్ ఉన్న ఫార్మాట్లో సెటప్ చేయడానికి నొక్కండి."</string>
<string name="ext_media_unsupported_notification_message" product="tv" msgid="1595482802187036532">"సపోర్ట్ చేసే ఫార్మాట్లో <xliff:g id="NAME">%s</xliff:g>ను సెటప్ చేయడానికి ఎంచుకోండి."</string>
<string name="ext_media_unsupported_notification_message" product="automotive" msgid="3412494732736336330">"మీరు పరికరాన్ని తిరిగి ఫార్మాట్ చేయాల్సి ఉంటుంది"</string>
<string name="ext_media_badremoval_notification_title" msgid="4114625551266196872">"<xliff:g id="NAME">%s</xliff:g> ఊహించని విధంగా తీసివేయబడింది"</string>
@@ -1525,8 +1529,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>
@@ -1675,12 +1679,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>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"షార్ట్కట్ ఆన్ చేసి ఉన్నప్పుడు, రెండు వాల్యూమ్ బటన్లను 3 సెకన్ల పాటు నొక్కి ఉంచితే యాక్సెస్ సౌలభ్య ఫీచర్ ప్రారంభం అవుతుంది."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"యాక్సెస్ సౌలభ్య ఫీచర్ల కోసం షార్ట్కట్ను ఆన్ చేయాలా?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"రెండు వాల్యూమ్ కీలను కొంత సేపు నొక్కి పట్టుకుంటే యాక్సెసిబిలిటీ ఫీచర్లు ఆన్ అవుతాయి. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nప్రస్తుత ఫీచర్లు:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nఎంపిక చేసిన ఫీచర్లను మీరు సెట్టింగ్లు>యాక్సెసిబిలిటీలో మార్చవచ్చు."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> షార్ట్కట్ను ఆన్ చేయాలా?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"రెండు వాల్యూమ్ కీలను కొన్ని సెకన్ల పాటు నొక్కి పట్టుకోవడం ద్వారా యాక్సెసిబిలిటీ అయిన <xliff:g id="SERVICE">%1$s</xliff:g> ఆన్ అవుతుంది. ఇది మీ పరికరం పని చేసే విధానాన్ని మార్చవచ్చు.\n\nసెట్టింగ్లు > యాక్సెసిబిలిటీలో, వేరొక ఫీచర్ను ప్రారంభించేలా ఈ షార్ట్ కట్ను మీరు మార్చవచ్చు."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"ఆన్ చేయి"</string>
@@ -2139,7 +2144,7 @@
<string name="accessibility_system_action_back_label" msgid="4205361367345537608">"వెనుకకు"</string>
<string name="accessibility_system_action_recents_label" msgid="4782875610281649728">"ఇటీవలి యాప్లు"</string>
<string name="accessibility_system_action_notifications_label" msgid="6083767351772162010">"నోటిఫికేషన్లు"</string>
- <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"శీఘ్ర సెట్టింగ్లు"</string>
+ <string name="accessibility_system_action_quick_settings_label" msgid="4583900123506773783">"క్విక్ సెట్టింగ్లు"</string>
<string name="accessibility_system_action_power_dialog_label" msgid="8095341821683910781">"పవర్ డైలాగ్ను తెరువు"</string>
<string name="accessibility_system_action_lock_screen_label" msgid="5484190691945563838">"స్క్రీన్ను లాక్ చేయి"</string>
<string name="accessibility_system_action_screenshot_label" msgid="3581566515062741676">"స్క్రీన్షాట్"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 379830a..b427b9e 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"ใช้ลายนิ้วมือหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"ไอคอนลายนิ้วมือ"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"การปลดล็อกด้วยใบหน้า"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"มีปัญหาเกี่ยวกับฟีเจอร์ปลดล็อกด้วยใบหน้า"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"ใช้ใบหน้าหรือการล็อกหน้าจอเพื่อดำเนินการต่อ"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"ไอคอนใบหน้า"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"อ่านการตั้งค่าการซิงค์"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"อนุญาตให้แอปพลิเคชันอ่านการตั้งค่าการซิงค์ของบัญชี ตัวอย่างเช่น การอนุญาตนี้สามารถระบุได้ว่าแอปพลิเคชัน People ซิงค์กับบัญชีหรือไม่"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"เมื่อทางลัดเปิดอยู่ การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มนาน 3 วินาทีจะเริ่มฟีเจอร์การช่วยเหลือพิเศษ"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"เปิดใช้ทางลัดสำหรับฟีเจอร์การช่วยเหลือพิเศษใช่ไหม"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิดฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nฟีเจอร์ปัจจุบัน:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nคุณจะเปลี่ยนฟีเจอร์ที่เลือกไว้ได้ในการตั้งค่า > การช่วยเหลือพิเศษ"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"เปิดใช้ทางลัด <xliff:g id="SERVICE">%1$s</xliff:g> ใช่ไหม"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"การกดปุ่มปรับระดับเสียงทั้ง 2 ปุ่มค้างไว้ 2-3 วินาทีจะเปิด <xliff:g id="SERVICE">%1$s</xliff:g> ซึ่งเป็นฟีเจอร์การช่วยเหลือพิเศษ การดำเนินการนี้อาจเปลี่ยนแปลงลักษณะการทำงานของอุปกรณ์\n\nคุณแก้ไขทางลัดนี้ให้เปิดฟีเจอร์อื่นได้ในการตั้งค่า > การช่วยเหลือพิเศษ"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"เปิด"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 73848a3..c62da4a 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Gamitin ang iyong fingerprint o lock ng screen para magpatuloy"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Icon ng fingerprint"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Pag-unlock Gamit ang Mukha"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Isyu sa Pag-unlock Gamit ang Mukha"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Gamitin ang iyong mukha o lock ng screen para magpatuloy"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Face icon"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"basahin ang mga setting ng sync"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Pinapayagan ang app na basahin ang mga setting ng pag-sync para sa isang account. Halimbawa, matutukoy nito kung naka-sync ang app na Mga Tao sa isang account."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kapag naka-on ang shortcut, magsisimula ang isang feature ng pagiging naa-access kapag pinindot ang parehong button ng volume."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"I-on ang shortcut para sa mga feature ng pagiging naa-access?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Mao-on ang mga feature ng accessibility kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nMga kasalukuyang feature:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nPuwede mong baguhin ang mga napiling feature sa Mga Setting > Accessibility."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"I-on ang shortcut ng <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Mao-on ang feature ng accessibility na <xliff:g id="SERVICE">%1$s</xliff:g> kapag pinindot nang matagal ang parehong volume key nang ilang segundo. Posibleng mabago nito ang paggana ng iyong device.\n\nPuwede mong palitan ng ibang feature ang shortcut na ito sa Mga Setting > Accessibility."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"I-on"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 3325e7e..46d0409 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Devam etmek için parmak izi veya ekran kilidinizi kullanın"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Parmak izi simgesi"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yüz Tanıma Kilidi"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yüz Tanıma Kilidi sorunu"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Devam etmek için yüz veya ekran kilidinizi kullanın"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Yüz simgesi"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"senk. ayarlarını okuma"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Uygulamaya bir hesaba ait senkronizasyon ayarlarını okuma izni verir. Örneğin, bu izne sahip bir uygulama Kişiler uygulamasının bir hesapla senkronize olup olmadığını belirleyebilir."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Kısayol açıkken ses düğmelerinin ikisini birden 3 saniyeliğine basılı tutmanız bir erişilebilirlik özelliğini başlatır."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Erişilebilirlik özellikleri için kısayol açılsın mı?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak, erişilebilirlik özelliklerini açar. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nGeçerli özellikler:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nSeçilen özellikleri Ayarlar > Erişilebilirlik\'te değiştirebilirsiniz."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> kısayolu açılsın mı?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ses tuşlarının ikisini birden birkaç saniyeliğine basılı tutmak <xliff:g id="SERVICE">%1$s</xliff:g> erişilebilirlik özelliğini etkinleştirir. Bu, cihazınızın çalışma şeklini değiştirebilir.\n\nBu kısayolu, Ayarlar > Erişilebilirlik\'te başka bir özellikle değiştirebilirsiniz."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Etkinleştir"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 4912be8..b70cee0 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -615,6 +615,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Щоб продовжити, скористайтеся відбитком пальця або даними для розблокування екрана"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"Сталася помилка. Повторіть спробу."</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Значок відбитка пальця"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Фейсконтроль"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Сталася помилка з фейсконтролем"</string>
@@ -667,6 +668,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Щоб продовжити, скористайтеся фейсконтролем або даними для розблокування екрана"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"Сталася помилка. Повторіть спробу."</string>
<string name="face_icon_content_description" msgid="465030547475916280">"Значок обличчя"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"читати налаштування синхронізації"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Дозволяє програмі читати налаштування синхронізації для облікового запису, наприклад, визначати, чи програма Люди синхронізується з обліковим записом."</string>
@@ -1735,7 +1737,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Якщо цей засіб увімкнено, ви можете активувати спеціальні можливості, утримуючи обидві кнопки гучності протягом трьох секунд."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Увімкнути засіб спеціальних можливостей?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, вмикаються спеціальні можливості. Це впливає на роботу пристрою.\n\nПоточні функції:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nВибрані функції можна змінити в налаштуваннях у меню спеціальних можливостей."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Увімкнути засіб швидкого доступу до сервісу <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Якщо втримувати обидві клавіші гучності впродовж кількох секунд, буде ввімкнено спеціальні можливості – <xliff:g id="SERVICE">%1$s</xliff:g>. Це може вплинути на роботу пристрою.\n\nДля цієї комбінації клавіш можна вибрати іншу функцію в меню \"Налаштування > Спеціальні можливості\"."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Увімкнути"</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 2936a08..29f3540 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"جاری رکھنے کے لیے اپنے فنگر پرنٹ یا اسکرین لاک کا استعمال کریں"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"فنگر پرنٹ آئیکن"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"فیس اَنلاک"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"فیس اَنلاک میں مسئلہ"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"جاری رکھنے کے لیے اپنے چہرے یا اسکرین لاک کا استعمال کریں"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"چہرے کا آئیکن"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"مطابقت پذیری کی ترتیبات پڑھیں"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"ایپ کو کسی اکاؤنٹ کیلئے مطابقت پذیری کی ترتیبات پڑھنے کی اجازت دیتا ہے۔ مثلا، یہ تعین کرسکتا ہے کہ آیا People ایپ کسی اکاؤنٹ کے ساتھ مطابقت پذیر ہے۔"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"شارٹ کٹ آن ہونے پر، 3 سیکنڈ تک دونوں والیوم بٹنز کو دبانے سے ایک ایکسیسبیلٹی خصوصیت شروع ہو جائے گی۔"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"ایکسیسبیلٹی خصوصیات کے لیے شارٹ کٹ آن کریں؟"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"دونوں والیوم کی کلیدوں کو کچھ سیکنڈز تک دبائیں رکھنے سے ایکسیسبیلٹی خصوصیات آن ہو جاتی ہیں۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nموجودہ خصوصیات:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nآپ ترتیبات اور ایکسیسبیلٹی میں منتخب کردہ خصوصیات کو تبدیل کر سکتے ہیں۔"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> شارٹ کٹ آن کریں؟"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"والیوم کی دونوں کلیدوں کو کچھ سیکنڈز تک دبائے رکھنے سے <xliff:g id="SERVICE">%1$s</xliff:g> ایکسیسبیلٹی خصوصیت آن ہو جاتی ہے۔ اس سے آپ کے آلے کے کام کرنے کا طریقہ تبدیل ہو سکتا ہے۔\n\nآپ ترتیبات اور ایکسیسبیلٹی میں دیگر خصوصیت کے لیے اس شارٹ کٹ کو تبدیل کر سکتے ہیں۔"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"آن کریں"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index df7d467..8838d2e 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Davom etish uchun barmoq izi yoki ekran qulfidan foydalaning"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Barmoq izi belgisi"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Yuz bilan ochish"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Yuz bilan ochishda muammo bor"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Davom etish uchun yuz tekshiruvi yoki ekran qulfidan foydalaning"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Yuz belgisi"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"sinx-sh sozlamalarini o‘qish"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ilovaga hisobning sinxronlash sozlamalarini o‘qish uchun ruxsat beradi. Masalan, bu \"Odamlar\" ilovasi hisob bilan sinxronlangan yoki aksini aniqlay oladi."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Maxsus imkoniyatlar funksiyasidan foydalanish uchun u yoniqligida ikkala tovush tugmasini 3 soniya bosib turing."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Maxsus imkoniyatlar uchun tezkor tugma yoqilsinmi?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Maxsus imkoniyatlarni yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nJoriy funksiyalar:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nTanlangan funksiyalarni Sozlamalar ichidagi Maxsus imkoniyatlar ustiga bosib oʻzgartirishingiz mumkin."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"<xliff:g id="SERVICE">%1$s</xliff:g> tezkor tugmasi yoqilsinmi?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"<xliff:g id="SERVICE">%1$s</xliff:g> funksiyasini yoqish uchun ikkala tovush tugmalarini bir necha soniya bosib turing. Qurilmangiz ishlashida oʻzgarish yuz berishi mumkin.\n\nBu tezkor tugmalarni boshqa funksiyaga Sozlamalar ichidagi Maxsus imkoniyatlar orqali tayinlash mumkin."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Yoqilsin"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 259696d..f66a21c 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Dùng vân tay của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Biểu tượng vân tay"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Mở khóa bằng khuôn mặt"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Vấn đề với tính năng Mở khóa bằng khuôn mặt"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Dùng khuôn mặt của bạn hoặc phương thức khóa màn hình để tiếp tục"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Biểu tượng khuôn mặt"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"đọc cài đặt đồng bộ hóa"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Cho phép ứng dụng đọc cài đặt đồng bộ hóa cho tài khoản. Ví dụ: việc này có thể xác định liệu ứng dụng Mọi người đã được đồng bộ hóa với tài khoản chưa."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Khi phím tắt này đang bật, thao tác nhấn cả hai nút âm lượng trong 3 giây sẽ mở tính năng hỗ trợ tiếp cận."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Bật phím tắt cho các tính năng hỗ trợ tiếp cận?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật các tính năng hỗ trợ tiếp cận. Việc bật các tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nCác tính năng hiện tại:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nBạn có thể thay đổi những tính năng đã chọn trong phần Cài đặt > Hỗ trợ tiếp cận."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Bật phím tắt cho <xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Thao tác nhấn và giữ cả hai phím âm lượng trong vài giây sẽ bật <xliff:g id="SERVICE">%1$s</xliff:g>, một tính năng hỗ trợ tiếp cận. Việc bật tính năng này có thể thay đổi cách thiết bị của bạn hoạt động.\n\nBạn có thể chuyển phím tắt này thành một tính năng khác trong phần Cài đặt > Hỗ trợ tiếp cận."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Bật"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index cc38de2..3eaf7c7 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"使用指纹解锁或屏幕锁定凭据验证身份,才能继续操作"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指纹图标"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人脸解锁"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人脸解锁存在问题"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"使用人脸解锁或屏幕锁定凭据验证身份,才能继续操作"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"面孔图标"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"读取同步设置"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允许该应用读取某个帐号的同步设置。例如,此权限可确定“联系人”应用是否与某个帐号同步。"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"启用这项快捷方式后,同时按下两个音量按钮 3 秒钟即可启动无障碍功能。"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要开启无障碍功能快捷方式吗?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同时按住两个音量键几秒钟,即可开启无障碍功能。这样做可能会改变您设备的工作方式。\n\n当前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可以在“设置”>“无障碍”中更改所选功能。"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要开启<xliff:g id="SERVICE">%1$s</xliff:g>快捷方式吗?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同时按住两个音量键几秒钟,即可开启<xliff:g id="SERVICE">%1$s</xliff:g>无障碍功能。这样做可能会改变您设备的工作方式。\n\n您可以在“设置”>“无障碍”中将此快捷方式更改为开启另一项功能。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"开启"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index fa2fee5..deae9a3 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -609,6 +609,7 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <string name="fingerprint_error_vendor_unknown" msgid="4170002184907291065">"發生錯誤,請再試一次。"</string>
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"面孔解鎖"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"「面孔解鎖」功能發生問題"</string>
@@ -661,6 +662,7 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用面孔解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string-array name="face_error_vendor">
</string-array>
+ <string name="face_error_vendor_unknown" msgid="7387005932083302070">"發生錯誤,請再試一次。"</string>
<string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步設定,例如確定「通訊錄」應用程式是否和某個帳戶保持同步。"</string>
@@ -1691,7 +1693,7 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用快速鍵後,同時按住音量按鈕 3 秒便可啟用無障礙功能。"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能捷徑嗎?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按下兩個音量鍵幾秒,以開啟無障礙功能。這可能會變更裝置的運作。\n\n目前功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n您可在「設定」>「無障礙功能」中變更所選功能。"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <string name="accessibility_shortcut_multiple_service_list" msgid="2128323171922023762">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 捷徑嗎?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按下兩個音量鍵幾秒,以開啟 <xliff:g id="SERVICE">%1$s</xliff:g> 無障礙功能。這可能會變更裝置的運作。\n\n您可在「設定」>「無障礙功能」中變更此快速鍵。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 1c02c6b..7cecc4b 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"請使用指紋解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"指紋圖示"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"人臉解鎖"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"人臉解鎖功能發生問題"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"請使用人臉解鎖或螢幕鎖定功能驗證身分,才能繼續操作"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"臉孔圖示"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"讀取同步處理設定"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"允許應用程式讀取帳戶的同步處理設定,例如判斷「使用者」應用程式是否和某個帳戶進行同步處理。"</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"啟用捷徑功能,只要同時按下兩個音量按鈕 3 秒,就能啟動無障礙功能。"</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"要開啟無障礙功能快速鍵嗎?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"同時按住音量調高鍵和調低鍵數秒,即可開啟無障礙功能。這麼做可能會改變裝置的運作方式。\n\n目前的功能:\n<xliff:g id="SERVICE">%1$s</xliff:g>\n你可以在 [設定] > [無障礙設定] 中變更選取的功能。"</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"要開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」快速鍵嗎?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"同時按住音量調高鍵和調低鍵數秒,即可開啟「<xliff:g id="SERVICE">%1$s</xliff:g>」無障礙功能。這麼做可能會改變裝置的運作方式。\n\n你可以在 [設定] > [無障礙設定] 中變更這個快速鍵觸發的功能。"</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"開啟"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index f93b844..f02eced 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -609,6 +609,8 @@
<string name="fingerprint_or_screen_lock_dialog_default_subtitle" msgid="5195808203117992200">"Sebenzisa izigxivizo zakho zomunwe noma ukukhiya isikrini ukuze uqhubeke"</string>
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- no translation found for fingerprint_error_vendor_unknown (4170002184907291065) -->
+ <skip />
<string name="fingerprint_icon_content_description" msgid="4741068463175388817">"Isithonjana sezigxivizo zeminwe"</string>
<string name="face_recalibrate_notification_name" msgid="7311163114750748686">"Ukuvula ubuso"</string>
<string name="face_recalibrate_notification_title" msgid="2524791952735579082">"Inkinga Ngokuvula ngobuso"</string>
@@ -661,6 +663,8 @@
<string name="face_or_screen_lock_dialog_default_subtitle" msgid="5006381531158341844">"Sebenzisa ubuso bakho noma ukukhiya isikrini ukuze uqhubeke"</string>
<string-array name="face_error_vendor">
</string-array>
+ <!-- no translation found for face_error_vendor_unknown (7387005932083302070) -->
+ <skip />
<string name="face_icon_content_description" msgid="465030547475916280">"Isithonjana sobuso"</string>
<string name="permlab_readSyncSettings" msgid="6250532864893156277">"funda izilungiselelo zokuvumelanisa"</string>
<string name="permdesc_readSyncSettings" msgid="1325658466358779298">"Ivumela uhlelo lokusebenza ukufunda izilungiselelo zokuvumelanisa ze-akhawunti. Isibonelo, lokhu kungacacisa ukuthi noma ngabe uhlelo lokusebenza le-People livumelanisiwe ne-akhawunti."</string>
@@ -1691,7 +1695,8 @@
<string name="accessibility_shortcut_toogle_warning" msgid="4161716521310929544">"Uma isinqamuleli sivuliwe, ukucindezela zombili izinkinobho zevolumu amasekhondi angu-3 kuzoqalisa isici sokufinyelela."</string>
<string name="accessibility_shortcut_multiple_service_warning_title" msgid="3135860819356676426">"Vula isinqamuleli sezici zokufinyeleleka?"</string>
<string name="accessibility_shortcut_multiple_service_warning" msgid="3740723309483706911">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula izici zokufinyelela. Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nIzici zamanje:\n<xliff:g id="SERVICE">%1$s</xliff:g>\nUngashintsha izici ezikhethiwe Kuzilungiselelo > Ukufinyeleleka."</string>
- <string name="accessibility_shortcut_multiple_service_list" msgid="6935581470716541531">" • <xliff:g id="SERVICE">%1$s</xliff:g>\n"</string>
+ <!-- no translation found for accessibility_shortcut_multiple_service_list (2128323171922023762) -->
+ <skip />
<string name="accessibility_shortcut_single_service_warning_title" msgid="1909518473488345266">"Vula isinqamuleli se-<xliff:g id="SERVICE">%1$s</xliff:g>?"</string>
<string name="accessibility_shortcut_single_service_warning" msgid="6363127705112844257">"Ukubambela phansi bobabili okhiye bevolumu amasekhondi ambalwa kuvula i-<xliff:g id="SERVICE">%1$s</xliff:g>, eyisici sokufinyelela Lokhu kungashintsha indlela idivayisi yakho esebenza ngayo.\n\nUngashintshela lesi sinqamuleli kwesinye isici Kuzilungiselelo > Ukufinyeleleka."</string>
<string name="accessibility_shortcut_on" msgid="5463618449556111344">"Vula"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a4954e3..797ff86 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -660,6 +660,9 @@
<!-- Indicates whether to enable an animation when unfolding a device or not -->
<bool name="config_unfoldTransitionEnabled">false</bool>
+ <!-- Indicates whether to enable hinge angle sensor when using unfold animation -->
+ <bool name="config_unfoldTransitionHingeAngle">false</bool>
+
<!-- Indicates that the device supports having more than one internal display on at the same
time. Only applicable to devices with more than one internal display. If this option is
set to false, DisplayManager will make additional effort to ensure no more than 1 internal
@@ -5092,6 +5095,14 @@
- config_fillBuiltInDisplayCutoutArray
- config_maskBuiltInDisplayCutoutArray
- config_waterfallCutoutArray
+ - config_roundedCornerRadiusArray
+ - config_roundedCornerTopRadiusArray
+ - config_roundedCornerBottomRadiusArray
+ - config_builtInDisplayIsRoundArray (config in SystemUI resource)
+ - config_roundedCornerMultipleRadiusArray (config in SystemUI resource)
+ - config_roundedCornerDrawableArray (config in SystemUI resource)
+ - config_roundedCornerTopDrawableArray (config in SystemUI resource)
+ - config_roundedCornerBottomDrawableArray (config in SystemUI resource)
Leave this array empty for single display device and the system will load the default main
built-in related configs.
@@ -5153,4 +5164,48 @@
This flag should be enabled only when the product does not have any UI to toggle airplane
mode like automotive devices.-->
<bool name="config_autoResetAirplaneMode">false</bool>
+
+ <bool name="config_secondaryBuiltInDisplayIsRound">@bool/config_windowIsRound</bool>
+
+ <!-- The display round config for each display in a multi-display device. -->
+ <array name="config_builtInDisplayIsRoundArray" translatable="false">
+ <item>@bool/config_mainBuiltInDisplayIsRound</item>
+ <item>@bool/config_secondaryBuiltInDisplayIsRound</item>
+ </array>
+
+ <!-- The rounded corner radius for each display in a multi-display device. -->
+ <array name="config_roundedCornerRadiusArray" translatable="false">
+ <item>@dimen/rounded_corner_radius</item>
+ <item>@dimen/secondary_rounded_corner_radius</item>
+ </array>
+
+ <!-- The top rounded corner radius for each display in a multi-display device. -->
+ <array name="config_roundedCornerTopRadiusArray" translatable="false">
+ <item>@dimen/rounded_corner_radius_top</item>
+ <item>@dimen/secondary_rounded_corner_radius_top</item>
+ </array>
+
+ <!-- The bottom rounded corner radius for each display in a multi-display device. -->
+ <array name="config_roundedCornerBottomRadiusArray" translatable="false">
+ <item>@dimen/rounded_corner_radius_bottom</item>
+ <item>@dimen/secondary_rounded_corner_radius_bottom</item>
+ </array>
+
+ <!-- The rounded corner radius adjustment for each display in a multi-display device. -->
+ <array name="config_roundedCornerRadiusAdjustmentArray" translatable="false">
+ <item>@dimen/rounded_corner_radius_adjustment</item>
+ <item>@dimen/secondary_rounded_corner_radius_adjustment</item>
+ </array>
+
+ <!-- The rounded corner radius top adjustment for each display in a multi-display device. -->
+ <array name="config_roundedCornerTopRadiusAdjustmentArray" translatable="false">
+ <item>@dimen/rounded_corner_radius_top_adjustment</item>
+ <item>@dimen/secondary_rounded_corner_radius_top_adjustment</item>
+ </array>
+
+ <!-- The rounded corner radius bottom adjustment for each display in a multi-display device. -->
+ <array name="config_roundedCornerBottomRadiusAdjustmentArray" translatable="false">
+ <item>@dimen/rounded_corner_radius_bottom_adjustment</item>
+ <item>@dimen/secondary_rounded_corner_radius_bottom_adjustment</item>
+ </array>
</resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index e8bb606..9ed4e65 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -55,6 +55,8 @@
<dimen name="navigation_bar_height_landscape">48dp</dimen>
<!-- Width of the navigation bar when it is placed vertically on the screen -->
<dimen name="navigation_bar_width">48dp</dimen>
+ <!-- Height of the bottom taskbar not including decorations like rounded corners. -->
+ <dimen name="taskbar_frame_height">60dp</dimen>
<!-- How much we expand the touchable region of the status bar below the notch to catch touches
that just start below the notch. -->
<dimen name="display_cutout_touchable_region_size">12dp</dimen>
@@ -952,4 +954,12 @@
<dimen name="secondary_waterfall_display_top_edge_size">0px</dimen>
<dimen name="secondary_waterfall_display_right_edge_size">0px</dimen>
<dimen name="secondary_waterfall_display_bottom_edge_size">0px</dimen>
+
+ <!-- Rounded corner settings for secondary built-in display -->
+ <dimen name="secondary_rounded_corner_radius">0px</dimen>
+ <dimen name="secondary_rounded_corner_radius_top">0px</dimen>
+ <dimen name="secondary_rounded_corner_radius_bottom">0px</dimen>
+ <dimen name="secondary_rounded_corner_radius_adjustment">0px</dimen>
+ <dimen name="secondary_rounded_corner_radius_top_adjustment">0px</dimen>
+ <dimen name="secondary_rounded_corner_radius_bottom_adjustment">0px</dimen>
</resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index a99a220..bb56b8d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1650,6 +1650,8 @@
<!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
<string-array name="fingerprint_error_vendor">
</string-array>
+ <!-- Default error message to use when fingerprint_error_vendor does not contain a message. [CHAR LIMIT=NONE] -->
+ <string name="fingerprint_error_vendor_unknown">Something went wrong. Try again.</string>
<!-- Content description which should be used for the fingerprint icon. -->
<string name="fingerprint_icon_content_description">Fingerprint icon</string>
@@ -1760,6 +1762,8 @@
<!-- Array containing custom error messages from vendor. Vendor is expected to add and translate these strings -->
<string-array name="face_error_vendor">
</string-array>
+ <!-- Default error message to use when face_error_vendor does not contain a message. [CHAR LIMIT=NONE] -->
+ <string name="face_error_vendor_unknown">Something went wrong. Try again.</string>
<!-- Content description which should be used for the face icon. [CHAR LIMIT=10] -->
<string name="face_icon_content_description">Face icon</string>
@@ -4554,7 +4558,7 @@
<string name="accessibility_shortcut_multiple_service_warning">Holding down both volume keys for a few seconds turns on accessibility features. This may change how your device works.\n\nCurrent features:\n<xliff:g id="service" example="TalkBack">%1$s</xliff:g>\nYou can change selected features in Settings > Accessibility.</string>
<!-- Used in multiple service warning to list current features. [CHAR LIMIT=none] -->
- <string name="accessibility_shortcut_multiple_service_list">\t• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
+ <string name="accessibility_shortcut_multiple_service_list">\u0020• <xliff:g id="service" example="TalkBack">%1$s</xliff:g>\n</string>
<!-- Dialog title for dialog shown when this accessibility shortcut is activated, and we want to confirm that the user understands what's going to happen. [CHAR LIMIT=none] -->
<string name="accessibility_shortcut_single_service_warning_title">Turn on <xliff:g id="service" example="TalkBack">%1$s</xliff:g> shortcut?</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 77a45f9..a26963a 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1741,6 +1741,7 @@
<java-symbol type="dimen" name="navigation_bar_height_car_mode" />
<java-symbol type="dimen" name="navigation_bar_height_landscape_car_mode" />
<java-symbol type="dimen" name="navigation_bar_width_car_mode" />
+ <java-symbol type="dimen" name="taskbar_frame_height" />
<java-symbol type="dimen" name="status_bar_height" />
<java-symbol type="dimen" name="display_cutout_touchable_region_size" />
<java-symbol type="dimen" name="quick_qs_offset_height" />
@@ -2526,6 +2527,7 @@
<java-symbol type="string" name="fingerprint_error_no_space" />
<java-symbol type="string" name="fingerprint_error_timeout" />
<java-symbol type="array" name="fingerprint_error_vendor" />
+ <java-symbol type="string" name="fingerprint_error_vendor_unknown" />
<java-symbol type="string" name="fingerprint_acquired_partial" />
<java-symbol type="string" name="fingerprint_acquired_insufficient" />
<java-symbol type="string" name="fingerprint_acquired_imager_dirty" />
@@ -2565,6 +2567,7 @@
<java-symbol type="string" name="face_error_no_space" />
<java-symbol type="string" name="face_error_timeout" />
<java-symbol type="array" name="face_error_vendor" />
+ <java-symbol type="string" name="face_error_vendor_unknown" />
<java-symbol type="string" name="face_error_canceled" />
<java-symbol type="string" name="face_error_user_canceled" />
<java-symbol type="string" name="face_error_lockout" />
@@ -3842,6 +3845,7 @@
<java-symbol type="string" name="config_foldedArea" />
<java-symbol type="bool" name="config_supportsConcurrentInternalDisplays" />
<java-symbol type="bool" name="config_unfoldTransitionEnabled" />
+ <java-symbol type="bool" name="config_unfoldTransitionHingeAngle" />
<java-symbol type="array" name="config_perDeviceStateRotationLockDefaults" />
@@ -4449,4 +4453,19 @@
<java-symbol type="array" name="config_mainBuiltInDisplayWaterfallCutout" />
<java-symbol type="array" name="config_secondaryBuiltInDisplayWaterfallCutout" />
<java-symbol type="array" name="config_waterfallCutoutArray" />
+
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius" />
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius_top" />
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius_bottom" />
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius_adjustment" />
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius_top_adjustment" />
+ <java-symbol type="dimen" name="secondary_rounded_corner_radius_bottom_adjustment" />
+ <java-symbol type="array" name="config_roundedCornerRadiusArray" />
+ <java-symbol type="array" name="config_roundedCornerTopRadiusArray" />
+ <java-symbol type="array" name="config_roundedCornerBottomRadiusArray" />
+ <java-symbol type="array" name="config_roundedCornerRadiusAdjustmentArray" />
+ <java-symbol type="array" name="config_roundedCornerTopRadiusAdjustmentArray" />
+ <java-symbol type="array" name="config_roundedCornerBottomRadiusAdjustmentArray" />
+ <java-symbol type="bool" name="config_secondaryBuiltInDisplayIsRound" />
+ <java-symbol type="array" name="config_builtInDisplayIsRoundArray" />
</resources>
diff --git a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
index 3d820ac..6884f13d 100644
--- a/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
+++ b/core/tests/coretests/src/android/app/appsearch/external/app/GenericDocumentTest.java
@@ -62,18 +62,4 @@
assertThat(outDoc.getPropertyDocument("propDocument").getPropertyBytesArray("propBytes"))
.isEqualTo(new byte[][] {{3, 4}});
}
-
- @Test
- public void testPutLargeDocument_exceedLimit() throws Exception {
- // Create a String property that has a very large property.
- char[] chars = new char[10_000_000];
- String property = new StringBuilder().append(chars).append("the end.").toString();
-
- GenericDocument doc =
- new GenericDocument.Builder<>("namespace", "id1", "schema1")
- .setPropertyString("propString", property)
- .build();
-
- assertThat(doc.getPropertyString("propString")).isEqualTo(property);
- }
}
diff --git a/core/tests/coretests/src/android/graphics/FontListParserTest.java b/core/tests/coretests/src/android/graphics/FontListParserTest.java
index 22f6ec0..701e619 100644
--- a/core/tests/coretests/src/android/graphics/FontListParserTest.java
+++ b/core/tests/coretests/src/android/graphics/FontListParserTest.java
@@ -27,6 +27,7 @@
import static junit.framework.Assert.fail;
+import android.graphics.fonts.FontCustomizationParser;
import android.graphics.fonts.FontStyle;
import android.os.LocaleList;
import android.text.FontConfig;
@@ -46,6 +47,7 @@
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
+import java.util.List;
@SmallTest
@RunWith(AndroidJUnit4.class)
@@ -318,6 +320,52 @@
}
}
+ @Test
+ public void alias() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font>test.ttf</font>"
+ + " </family>"
+ + " <family name='custom-family'>"
+ + " <font>missing.ttf</font>"
+ + " </family>"
+ + " <alias name='custom-alias' to='sans-serif'/>"
+ + "</familyset>";
+ FontConfig config = readFamilies(xml, true /* include non-existing font files */);
+ List<FontConfig.Alias> aliases = config.getAliases();
+ assertThat(aliases.size()).isEqualTo(1);
+ assertThat(aliases.get(0).getName()).isEqualTo("custom-alias");
+ assertThat(aliases.get(0).getOriginal()).isEqualTo("sans-serif");
+ }
+
+ @Test
+ public void dropped_FamilyAlias() throws Exception {
+ String xml = "<?xml version='1.0' encoding='UTF-8'?>"
+ + "<familyset>"
+ + " <family name='sans-serif'>"
+ + " <font>test.ttf</font>"
+ + " </family>"
+ + " <family name='custom-family'>"
+ + " <font>missing.ttf</font>"
+ + " </family>"
+ + " <alias name='custom-alias' to='custom-family'/>"
+ + "</familyset>";
+ FontConfig config = readFamilies(xml, false /* exclude not existing file */);
+ assertThat(config.getAliases()).isEmpty();
+ }
+
+ private FontConfig readFamilies(String xml, boolean allowNonExisting)
+ throws IOException, XmlPullParserException {
+ ByteArrayInputStream buffer = new ByteArrayInputStream(
+ xml.getBytes(StandardCharsets.UTF_8));
+ XmlPullParser parser = Xml.newPullParser();
+ parser.setInput(buffer, "UTF-8");
+ parser.nextTag();
+ return FontListParser.readFamilies(parser, "", new FontCustomizationParser.Result(), null,
+ 0L /* last modified date */, 0 /* config version */, allowNonExisting);
+ }
+
private FontConfig.FontFamily readFamily(String xml)
throws IOException, XmlPullParserException {
ByteArrayInputStream buffer = new ByteArrayInputStream(
diff --git a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
index dfc9013..149f58f 100644
--- a/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
+++ b/core/tests/coretests/src/android/hardware/display/DisplayManagerGlobalTest.java
@@ -32,6 +32,7 @@
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Captor;
+import org.mockito.InOrder;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
@@ -121,6 +122,46 @@
Mockito.verifyZeroInteractions(mListener);
}
+ @Test
+ public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreNoOtherListeners()
+ throws RemoteException {
+ mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks();
+ Mockito.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(ALL_DISPLAY_EVENTS));
+
+ mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks();
+ Mockito.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L));
+
+ }
+
+ @Test
+ public void testDisplayManagerGlobalRegistersWithDisplayManager_WhenThereAreListeners()
+ throws RemoteException {
+ mDisplayManagerGlobal.registerDisplayListener(mListener, mHandler,
+ DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS);
+ InOrder inOrder = Mockito.inOrder(mDisplayManager);
+
+ inOrder.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+ mDisplayManagerGlobal.registerNativeChoreographerForRefreshRateCallbacks();
+ inOrder.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+ eq(ALL_DISPLAY_EVENTS | DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+ mDisplayManagerGlobal.unregisterNativeChoreographerForRefreshRateCallbacks();
+ inOrder.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(),
+ eq(DisplayManager.EVENT_FLAG_DISPLAY_BRIGHTNESS));
+
+ mDisplayManagerGlobal.unregisterDisplayListener(mListener);
+ inOrder.verify(mDisplayManager)
+ .registerCallbackWithEventMask(mCallbackCaptor.capture(), eq(0L));
+
+ }
+
private void waitForHandler() {
mHandler.runWithScissors(() -> { }, 0);
}
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 8fd1af8..4f1da1b2 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -111,7 +111,7 @@
new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
mMockController, 10 /* durationMs */, new LinearInterpolator(),
0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */);
- mController.mReadyDispatched = true;
+ mController.setReadyDispatched(true);
}
@Test
@@ -197,7 +197,7 @@
@Test
public void testCancelled_beforeReadyDispatched() {
- mController.mReadyDispatched = false;
+ mController.setReadyDispatched(false);
mController.cancel();
assertFalse(mController.isReady());
assertFalse(mController.isFinished());
diff --git a/core/tests/coretests/src/android/view/InsetsControllerTest.java b/core/tests/coretests/src/android/view/InsetsControllerTest.java
index 507638e..227a8657 100644
--- a/core/tests/coretests/src/android/view/InsetsControllerTest.java
+++ b/core/tests/coretests/src/android/view/InsetsControllerTest.java
@@ -19,13 +19,17 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
import static android.view.InsetsController.ANIMATION_TYPE_NONE;
+import static android.view.InsetsController.ANIMATION_TYPE_RESIZE;
import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
+import static android.view.InsetsController.AnimationType;
import static android.view.InsetsSourceConsumer.ShowResult.IME_SHOW_DELAYED;
import static android.view.InsetsSourceConsumer.ShowResult.SHOW_IMMEDIATELY;
+import static android.view.InsetsState.FIRST_TYPE;
import static android.view.InsetsState.ITYPE_CAPTION_BAR;
import static android.view.InsetsState.ITYPE_IME;
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
+import static android.view.InsetsState.LAST_TYPE;
import static android.view.WindowInsets.Type.ime;
import static android.view.WindowInsets.Type.navigationBars;
import static android.view.WindowInsets.Type.statusBars;
@@ -662,6 +666,97 @@
}
@Test
+ public void testResizeAnimation_insetsTypes() {
+ for (@InternalInsetsType int type = FIRST_TYPE; type <= LAST_TYPE; type++) {
+ final @AnimationType int expectedAnimationType =
+ (InsetsState.toPublicType(type) & Type.systemBars()) != 0
+ ? ANIMATION_TYPE_RESIZE
+ : ANIMATION_TYPE_NONE;
+ doTestResizeAnimation_insetsTypes(type, expectedAnimationType);
+ }
+ }
+
+ private void doTestResizeAnimation_insetsTypes(@InternalInsetsType int type,
+ @AnimationType int expectedAnimationType) {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final InsetsState state1 = new InsetsState();
+ state1.getSource(type).setVisible(true);
+ state1.getSource(type).setFrame(0, 0, 500, 50);
+ final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+ state2.getSource(type).setFrame(0, 0, 500, 60);
+ final String message = "Animation type of " + InsetsState.typeToString(type) + ":";
+
+ // New insets source won't cause the resize animation.
+ mController.onStateChanged(state1);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing frame might cause the resize animation. This depends on the insets type.
+ mController.onStateChanged(state2);
+ assertEquals(message, expectedAnimationType, mController.getAnimationType(type));
+
+ // Cancel the existing animations for the next iteration.
+ mController.cancelExistingAnimations();
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testResizeAnimation_displayFrame() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final @InternalInsetsType int type = ITYPE_STATUS_BAR;
+ final InsetsState state1 = new InsetsState();
+ state1.setDisplayFrame(new Rect(0, 0, 500, 1000));
+ state1.getSource(type).setFrame(0, 0, 500, 50);
+ final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+ state2.setDisplayFrame(new Rect(0, 0, 500, 1010));
+ state2.getSource(type).setFrame(0, 0, 500, 60);
+ final String message = "There must not be resize animation.";
+
+ // New insets source won't cause the resize animation.
+ mController.onStateChanged(state1);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing frame won't cause the resize animation if the display frame is also changed.
+ mController.onStateChanged(state2);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
+ public void testResizeAnimation_visibility() {
+ InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+ final @InternalInsetsType int type = ITYPE_STATUS_BAR;
+ final InsetsState state1 = new InsetsState();
+ state1.getSource(type).setVisible(true);
+ state1.getSource(type).setFrame(0, 0, 500, 50);
+ final InsetsState state2 = new InsetsState(state1, true /* copySources */);
+ state2.getSource(type).setVisible(false);
+ state2.getSource(type).setFrame(0, 0, 500, 60);
+ final InsetsState state3 = new InsetsState(state2, true /* copySources */);
+ state3.getSource(type).setVisible(true);
+ state3.getSource(type).setFrame(0, 0, 500, 70);
+ final String message = "There must not be resize animation.";
+
+ // New insets source won't cause the resize animation.
+ mController.onStateChanged(state1);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing source visibility (visible --> invisible) won't cause the resize animation.
+ // The previous source and the current one must be both visible.
+ mController.onStateChanged(state2);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+
+ // Changing source visibility (invisible --> visible) won't cause the resize animation.
+ // The previous source and the current one must be both visible.
+ mController.onStateChanged(state3);
+ assertEquals(message, ANIMATION_TYPE_NONE, mController.getAnimationType(type));
+ });
+ InstrumentationRegistry.getInstrumentation().waitForIdleSync();
+ }
+
+ @Test
public void testCaptionInsetsStateAssemble() {
InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
mController.onFrameChanged(new Rect(0, 0, 100, 300));
diff --git a/core/tests/coretests/src/android/view/InsetsStateTest.java b/core/tests/coretests/src/android/view/InsetsStateTest.java
index 3bd2939..bf8bb76 100644
--- a/core/tests/coretests/src/android/view/InsetsStateTest.java
+++ b/core/tests/coretests/src/android/view/InsetsStateTest.java
@@ -216,9 +216,9 @@
mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
- Rect visibleInsets = mState.calculateVisibleInsets(
+ Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 400), SOFT_INPUT_ADJUST_NOTHING);
- assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
+ assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
}
@Test
@@ -226,9 +226,9 @@
mState.getSource(ITYPE_CAPTION_BAR).setFrame(new Rect(0, 0, 100, 300));
mState.getSource(ITYPE_CAPTION_BAR).setVisible(true);
- Rect visibleInsets = mState.calculateVisibleInsets(
+ Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 150, 400), SOFT_INPUT_ADJUST_NOTHING);
- assertEquals(new Rect(0, 300, 0, 0), visibleInsets);
+ assertEquals(Insets.of(0, 300, 0, 0), visibleInsets);
}
@Test
@@ -413,9 +413,9 @@
// Make sure bottom gestures are ignored
mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
- Rect visibleInsets = mState.calculateVisibleInsets(
+ Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_PAN);
- assertEquals(new Rect(0, 100, 0, 100), visibleInsets);
+ assertEquals(Insets.of(0, 100, 0, 100), visibleInsets);
}
@Test
@@ -428,9 +428,9 @@
// Make sure bottom gestures are ignored
mState.getSource(ITYPE_BOTTOM_GESTURES).setFrame(new Rect(0, 100, 100, 300));
mState.getSource(ITYPE_BOTTOM_GESTURES).setVisible(true);
- Rect visibleInsets = mState.calculateVisibleInsets(
+ Insets visibleInsets = mState.calculateVisibleInsets(
new Rect(0, 0, 100, 300), SOFT_INPUT_ADJUST_NOTHING);
- assertEquals(new Rect(0, 100, 0, 0), visibleInsets);
+ assertEquals(Insets.of(0, 100, 0, 0), visibleInsets);
}
@Test
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/data/etc/services.core.protolog.json b/data/etc/services.core.protolog.json
index b49b289..0d7225b 100644
--- a/data/etc/services.core.protolog.json
+++ b/data/etc/services.core.protolog.json
@@ -211,6 +211,12 @@
"group": "WM_DEBUG_SYNC_ENGINE",
"at": "com\/android\/server\/wm\/BLASTSyncEngine.java"
},
+ "-1898316768": {
+ "message": "Unable to retrieve window container to start layer mirroring for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-1895337367": {
"message": "Delete root task display=%d winMode=%d",
"level": "VERBOSE",
@@ -571,6 +577,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityStarter.java"
},
+ "-1483435730": {
+ "message": "InsetsSource setWin %s for type %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1480772131": {
"message": "No app or window is requesting an orientation, return %d for display id=%d",
"level": "VERBOSE",
@@ -673,6 +685,12 @@
"group": "WM_DEBUG_IME",
"at": "com\/android\/server\/wm\/ImeInsetsSourceProvider.java"
},
+ "-1394745488": {
+ "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1391944764": {
"message": "SURFACE DESTROY: %s. %s",
"level": "INFO",
@@ -721,12 +739,6 @@
"group": "WM_DEBUG_STARTING_WINDOW",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "-1312861660": {
- "message": "notifyInsetsControlChanged for %s ",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"-1311436264": {
"message": "Unregister task fragment organizer=%s uid=%d pid=%d",
"level": "VERBOSE",
@@ -835,6 +847,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-1185473319": {
+ "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
+ "level": "INFO",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"-1176488860": {
"message": "SURFACE isSecure=%b: %s",
"level": "INFO",
@@ -1081,6 +1099,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-904499590": {
+ "message": "Provided surface for layer mirroring on display %d is not present, so do not update the surface",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-883738232": {
"message": "Adding more than one toast window for UID at a time.",
"level": "WARN",
@@ -1249,6 +1273,12 @@
"group": "WM_DEBUG_WINDOW_TRANSITIONS",
"at": "com\/android\/server\/wm\/Transition.java"
},
+ "-702650156": {
+ "message": "Override with TaskFragment remote animation for transit=%s",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_APP_TRANSITIONS",
+ "at": "com\/android\/server\/wm\/AppTransitionController.java"
+ },
"-701167286": {
"message": "applyAnimation: transit=%s, enter=%b, wc=%s",
"level": "VERBOSE",
@@ -1285,6 +1315,12 @@
"group": "WM_DEBUG_ORIENTATION",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "-663411559": {
+ "message": "Going ahead with updating layer mirroring for display %d to new bounds %s and\/or orientation %d.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-655104359": {
"message": "Frontmost changed immersion: %s",
"level": "DEBUG",
@@ -1531,12 +1567,6 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
- "-395922585": {
- "message": "InsetsSource setWin %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"-393505149": {
"message": "unable to update pointer icon",
"level": "WARN",
@@ -1549,6 +1579,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-384564722": {
+ "message": "Unable to start layer mirroring for display %d since the surface is not available.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-381475323": {
"message": "DisplayContent: boot is waiting for window of type %d to be drawn",
"level": "DEBUG",
@@ -1621,6 +1657,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-309399422": {
+ "message": "Display %d state is now (%d), so update layer mirroring?",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-302468788": {
"message": "Expected target rootTask=%s to be top most but found rootTask=%s",
"level": "WARN",
@@ -1687,6 +1729,12 @@
"group": "WM_DEBUG_WINDOW_MOVEMENT",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "-190034097": {
+ "message": "Unable to retrieve window container to update layer mirroring for display %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"-177040661": {
"message": "Start rotation animation. customAnim=%s, mCurRotation=%s, mOriginalRotation=%s",
"level": "DEBUG",
@@ -1741,12 +1789,6 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
- "-112805366": {
- "message": "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"-108977760": {
"message": "Sandbox max bounds for uid %s to bounds %s. config to never sandbox = %s, config to always sandbox = %s, letterboxing from mismatch with parent bounds = %s, has mCompatDisplayInsets = %s, should create compatDisplayInsets = %s",
"level": "DEBUG",
@@ -1789,6 +1831,18 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/TaskFragment.java"
},
+ "-79877120": {
+ "message": "Display %d has content (%b) so disable layer mirroring",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
+ "-70719599": {
+ "message": "Unregister remote animations for organizer=%s uid=%d pid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+ },
"-55185509": {
"message": "setFocusedTask: taskId=%d touchedActivity=%s",
"level": "DEBUG",
@@ -1849,12 +1903,6 @@
"group": "WM_DEBUG_RECENTS_ANIMATIONS",
"at": "com\/android\/server\/wm\/RecentsAnimationController.java"
},
- "29780972": {
- "message": "InsetsSource Control %s for target %s",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"35398067": {
"message": "goodToGo(): onAnimationStart, transit=%s, apps=%d, wallpapers=%d, nonApps=%d",
"level": "DEBUG",
@@ -1897,24 +1945,12 @@
"group": "WM_DEBUG_TASKS",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
- "73987756": {
- "message": "ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
- "level": "INFO",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"74885950": {
"message": "Waiting for top state to be released by %s",
"level": "VERBOSE",
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityTaskSupervisor.java"
},
- "75707221": {
- "message": "ControlAdapter startAnimation mSource: %s controlTarget: %s",
- "level": "INFO",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
- },
"83950285": {
"message": "removeAnimation(%d)",
"level": "DEBUG",
@@ -2287,6 +2323,12 @@
"group": "WM_SHOW_SURFACE_ALLOC",
"at": "com\/android\/server\/wm\/RootWindowContainer.java"
},
+ "416924848": {
+ "message": "InsetsSource Control %s for target %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"417311568": {
"message": "onResize: Resizing %s",
"level": "DEBUG",
@@ -2347,6 +2389,12 @@
"group": "WM_DEBUG_WINDOW_ORGANIZER",
"at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
},
+ "504397469": {
+ "message": "Unable to update layer mirroring for display %d to new bounds %s and\/or orientation %d, since the surface is not available.",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"508887531": {
"message": "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s",
"level": "VERBOSE",
@@ -2803,6 +2851,12 @@
"group": "WM_DEBUG_STATES",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1030898920": {
+ "message": "notifyInsetsControlChanged for %s ",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"1033274509": {
"message": "moveWindowTokenToDisplay: Attempted to move non-existing token: %s",
"level": "WARN",
@@ -2821,6 +2875,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1047505501": {
+ "message": "notifyInsetsChanged for %s ",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/WindowState.java"
+ },
"1047769218": {
"message": "Finishing activity r=%s, result=%d, data=%s, reason=%s",
"level": "VERBOSE",
@@ -2941,6 +3001,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1210037962": {
+ "message": "Register remote animations for organizer=%s uid=%d pid=%d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_WINDOW_ORGANIZER",
+ "at": "com\/android\/server\/wm\/TaskFragmentOrganizerController.java"
+ },
"1219600119": {
"message": "addWindow: win=%s Callers=%s",
"level": "DEBUG",
@@ -3085,6 +3151,12 @@
"group": "WM_DEBUG_SCREEN_ON",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "1407569006": {
+ "message": "Display %d was already layer mirroring, so apply transformations if necessary",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"1417601133": {
"message": "Enqueueing ADD_STARTING",
"level": "VERBOSE",
@@ -3211,12 +3283,6 @@
"group": "WM_DEBUG_APP_TRANSITIONS",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
- "1533154777": {
- "message": "notifyInsetsChanged for %s ",
- "level": "DEBUG",
- "group": "WM_DEBUG_IME",
- "at": "com\/android\/server\/wm\/WindowState.java"
- },
"1557732761": {
"message": "For Intent %s bringing to top: %s",
"level": "DEBUG",
@@ -3337,6 +3403,12 @@
"group": "WM_DEBUG_CONFIGURATION",
"at": "com\/android\/server\/wm\/ActivityRecord.java"
},
+ "1687376052": {
+ "message": "Display %d has no content and is on, so start layer mirroring for state %d",
+ "level": "VERBOSE",
+ "group": "WM_DEBUG_LAYER_MIRRORING",
+ "at": "com\/android\/server\/wm\/DisplayContent.java"
+ },
"1689989893": {
"message": "SyncGroup %d: Set ready",
"level": "VERBOSE",
@@ -3643,6 +3715,12 @@
"group": "WM_ERROR",
"at": "com\/android\/server\/wm\/WindowManagerService.java"
},
+ "2070726247": {
+ "message": "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+ "level": "DEBUG",
+ "group": "WM_DEBUG_WINDOW_INSETS",
+ "at": "com\/android\/server\/wm\/InsetsSourceProvider.java"
+ },
"2083556954": {
"message": "Set mOrientationChanging of %s",
"level": "VERBOSE",
@@ -3735,6 +3813,9 @@
"WM_DEBUG_KEEP_SCREEN_ON": {
"tag": "WindowManager"
},
+ "WM_DEBUG_LAYER_MIRRORING": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_LOCKTASK": {
"tag": "WindowManager"
},
@@ -3768,6 +3849,9 @@
"WM_DEBUG_TASKS": {
"tag": "WindowManager"
},
+ "WM_DEBUG_WINDOW_INSETS": {
+ "tag": "WindowManager"
+ },
"WM_DEBUG_WINDOW_MOVEMENT": {
"tag": "WindowManager"
},
diff --git a/graphics/java/android/graphics/FontListParser.java b/graphics/java/android/graphics/FontListParser.java
index 93a336e..96b3325 100644
--- a/graphics/java/android/graphics/FontListParser.java
+++ b/graphics/java/android/graphics/FontListParser.java
@@ -25,6 +25,7 @@
import android.os.Build;
import android.os.LocaleList;
import android.text.FontConfig;
+import android.util.ArraySet;
import android.util.Xml;
import org.xmlpull.v1.XmlPullParser;
@@ -37,6 +38,7 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.regex.Pattern;
/**
@@ -120,7 +122,23 @@
}
}
- private static FontConfig readFamilies(
+ /**
+ * Parses the familyset tag in font.xml
+ * @param parser a XML pull parser
+ * @param fontDir A system font directory, e.g. "/system/fonts"
+ * @param customization A OEM font customization
+ * @param updatableFontMap A map of updated font files
+ * @param lastModifiedDate A date that the system font is updated.
+ * @param configVersion A version of system font config.
+ * @param allowNonExistingFile true if allowing non-existing font files during parsing fonts.xml
+ * @return result of fonts.xml
+ *
+ * @throws XmlPullParserException
+ * @throws IOException
+ *
+ * @hide
+ */
+ public static FontConfig readFamilies(
@NonNull XmlPullParser parser,
@NonNull String fontDir,
@NonNull FontCustomizationParser.Result customization,
@@ -159,7 +177,24 @@
}
families.addAll(oemNamedFamilies.values());
- return new FontConfig(families, aliases, lastModifiedDate, configVersion);
+
+ // Filters aliases that point to non-existing families.
+ Set<String> namedFamilies = new ArraySet<>();
+ for (int i = 0; i < families.size(); ++i) {
+ String name = families.get(i).getName();
+ if (name != null) {
+ namedFamilies.add(name);
+ }
+ }
+ List<FontConfig.Alias> filtered = new ArrayList<>();
+ for (int i = 0; i < aliases.size(); ++i) {
+ FontConfig.Alias alias = aliases.get(i);
+ if (namedFamilies.contains(alias.getOriginal())) {
+ filtered.add(alias);
+ }
+ }
+
+ return new FontConfig(families, filtered, lastModifiedDate, configVersion);
}
private static boolean keepReading(XmlPullParser parser)
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
index 4206d03..9212a0f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/JetpackTaskFragmentOrganizer.java
@@ -62,6 +62,7 @@
final Map<IBinder, Configuration> mFragmentParentConfigs = new ArrayMap<>();
private final TaskFragmentCallback mCallback;
+ private TaskFragmentAnimationController mAnimationController;
/**
* Callback that notifies the controller about changes to task fragments.
@@ -83,6 +84,25 @@
mCallback = callback;
}
+ @Override
+ public void registerOrganizer() {
+ if (mAnimationController != null) {
+ throw new IllegalStateException("Must unregister the organizer before re-register.");
+ }
+ super.registerOrganizer();
+ mAnimationController = new TaskFragmentAnimationController(this);
+ mAnimationController.registerRemoteAnimations();
+ }
+
+ @Override
+ public void unregisterOrganizer() {
+ if (mAnimationController != null) {
+ mAnimationController.unregisterRemoteAnimations();
+ mAnimationController = null;
+ }
+ super.unregisterOrganizer();
+ }
+
/**
* Starts a new Activity and puts it into split with an existing Activity side-by-side.
* @param launchingFragmentToken token for the launching TaskFragment. If it exists, it will
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
index 4fd2126..a41557d 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitContainer.java
@@ -40,7 +40,15 @@
mSplitRule = splitRule;
if (shouldFinishPrimaryWithSecondary(splitRule)) {
- mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
+ if (mPrimaryContainer.getRunningActivityCount() == 1
+ && mPrimaryContainer.hasActivity(primaryActivity.getActivityToken())) {
+ mSecondaryContainer.addContainerToFinishOnExit(mPrimaryContainer);
+ } else {
+ // Only adding the activity to be finished vs. the entire TaskFragment while
+ // the secondary container exits because there are other unrelated activities in the
+ // primary TaskFragment.
+ mSecondaryContainer.addActivityToFinishOnExit(primaryActivity);
+ }
}
if (shouldFinishSecondaryWithPrimary(splitRule)) {
mPrimaryContainer.addContainerToFinishOnExit(mSecondaryContainer);
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
index 05c6792..12c273a 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/SplitController.java
@@ -117,6 +117,10 @@
}
container.setInfo(taskFragmentAppearedInfo.getTaskFragmentInfo());
+ if (container.isFinished()) {
+ mPresenter.cleanupContainer(container, false /* shouldFinishDependent */);
+ updateCallbackIfNecessary();
+ }
}
@Override
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
new file mode 100644
index 0000000..b85287d
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationController.java
@@ -0,0 +1,61 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
+
+import android.util.Log;
+import android.view.RemoteAnimationAdapter;
+import android.view.RemoteAnimationDefinition;
+import android.window.TaskFragmentOrganizer;
+
+/** Controls the TaskFragment remote animations. */
+class TaskFragmentAnimationController {
+
+ private static final String TAG = "TaskFragAnimationCtrl";
+ // TODO(b/196173550) turn off when finalize
+ static final boolean DEBUG = false;
+
+ private final TaskFragmentOrganizer mOrganizer;
+ private final TaskFragmentAnimationRunner mRemoteRunner = new TaskFragmentAnimationRunner();
+
+ TaskFragmentAnimationController(TaskFragmentOrganizer organizer) {
+ mOrganizer = organizer;
+ }
+
+ void registerRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "registerRemoteAnimations");
+ }
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter animationAdapter =
+ new RemoteAnimationAdapter(mRemoteRunner, 0, 0);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_OPEN, animationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, animationAdapter);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, animationAdapter);
+ mOrganizer.registerRemoteAnimations(definition);
+ }
+
+ void unregisterRemoteAnimations() {
+ if (DEBUG) {
+ Log.v(TAG, "unregisterRemoteAnimations");
+ }
+ mOrganizer.unregisterRemoteAnimations();
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
new file mode 100644
index 0000000..9ee60d8
--- /dev/null
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentAnimationRunner.java
@@ -0,0 +1,93 @@
+/*
+ * 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 androidx.window.extensions.organizer;
+
+import static android.view.RemoteAnimationTarget.MODE_OPENING;
+
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.util.Log;
+import android.view.IRemoteAnimationFinishedCallback;
+import android.view.IRemoteAnimationRunner;
+import android.view.RemoteAnimationTarget;
+import android.view.SurfaceControl;
+import android.view.WindowManager;
+
+import androidx.annotation.Nullable;
+
+/** To run the TaskFragment animations. */
+class TaskFragmentAnimationRunner extends IRemoteAnimationRunner.Stub {
+
+ private static final String TAG = "TaskFragAnimationRunner";
+ private final Handler mHandler = new Handler(Looper.myLooper());
+
+ @Nullable
+ private IRemoteAnimationFinishedCallback mFinishedCallback;
+
+ @Override
+ public void onAnimationStart(@WindowManager.TransitionOldType int transit,
+ RemoteAnimationTarget[] apps,
+ RemoteAnimationTarget[] wallpapers,
+ RemoteAnimationTarget[] nonApps,
+ IRemoteAnimationFinishedCallback finishedCallback) {
+ if (wallpapers.length != 0 || nonApps.length != 0) {
+ throw new IllegalArgumentException("TaskFragment shouldn't handle animation with"
+ + "wallpaper or non-app windows.");
+ }
+ if (TaskFragmentAnimationController.DEBUG) {
+ Log.v(TAG, "onAnimationStart transit=" + transit);
+ }
+ mHandler.post(() -> startAnimation(apps, finishedCallback));
+ }
+
+ @Override
+ public void onAnimationCancelled() {
+ if (TaskFragmentAnimationController.DEBUG) {
+ Log.v(TAG, "onAnimationCancelled");
+ }
+ mHandler.post(this::onAnimationFinished);
+ }
+
+ private void startAnimation(RemoteAnimationTarget[] targets,
+ IRemoteAnimationFinishedCallback finishedCallback) {
+ // TODO(b/196173550) replace with actual animations
+ mFinishedCallback = finishedCallback;
+ SurfaceControl.Transaction t = new SurfaceControl.Transaction();
+ for (RemoteAnimationTarget target : targets) {
+ if (target.mode == MODE_OPENING) {
+ t.show(target.leash);
+ t.setAlpha(target.leash, 1);
+ }
+ t.setPosition(target.leash, target.localBounds.left, target.localBounds.top);
+ }
+ t.apply();
+ onAnimationFinished();
+ }
+
+ private void onAnimationFinished() {
+ if (mFinishedCallback == null) {
+ return;
+ }
+ try {
+ mFinishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ e.rethrowFromSystemServer();
+ }
+ mFinishedCallback = null;
+ }
+}
diff --git a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
index a4f5c75..8503b9f 100644
--- a/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
+++ b/libs/WindowManager/Jetpack/src/androidx/window/extensions/organizer/TaskFragmentContainer.java
@@ -125,12 +125,20 @@
return false;
}
+ int getRunningActivityCount() {
+ int count = mPendingAppearedActivities.size();
+ if (mInfo != null) {
+ count += mInfo.getRunningActivityCount();
+ }
+ return count;
+ }
+
@Nullable
TaskFragmentInfo getInfo() {
return mInfo;
}
- void setInfo(@Nullable TaskFragmentInfo info) {
+ void setInfo(@NonNull TaskFragmentInfo info) {
mInfo = info;
if (mInfo == null || mPendingAppearedActivities.isEmpty()) {
return;
@@ -182,20 +190,30 @@
*/
void finish(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
@NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
- if (mIsFinished) {
- return;
+ if (!mIsFinished) {
+ mIsFinished = true;
+ finishActivities(shouldFinishDependent, presenter, wct, controller);
}
- mIsFinished = true;
- // Finish own activities
- for (Activity activity : collectActivities()) {
- activity.finish();
+ if (mInfo == null) {
+ // Defer removal the container and wait until TaskFragment appeared.
+ return;
}
// Cleanup the visuals
presenter.deleteTaskFragment(wct, getTaskFragmentToken());
// Cleanup the records
controller.removeContainer(this);
+ // Clean up task fragment information
+ mInfo = null;
+ }
+
+ private void finishActivities(boolean shouldFinishDependent, @NonNull SplitPresenter presenter,
+ @NonNull WindowContainerTransaction wct, @NonNull SplitController controller) {
+ // Finish own activities
+ for (Activity activity : collectActivities()) {
+ activity.finish();
+ }
if (!shouldFinishDependent) {
return;
diff --git a/libs/WindowManager/Shell/res/color/split_divider_background.xml b/libs/WindowManager/Shell/res/color/split_divider_background.xml
new file mode 100644
index 0000000..84f4fdf
--- /dev/null
+++ b/libs/WindowManager/Shell/res/color/split_divider_background.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ ~ 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.
+ -->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+ <item android:color="@android:color/system_neutral2_500" android:lStar="35" />
+</selector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml
new file mode 100644
index 0000000..18dc909
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_bottom.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/split_divider_corner_size"
+ android:height="@dimen/split_divider_corner_size"
+ android:viewportWidth="42"
+ android:viewportHeight="42">
+
+ <group android:pivotX="21"
+ android:pivotY="21"
+ android:rotation="180">
+ <path
+ android:fillColor="@color/split_divider_background"
+ android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
new file mode 100644
index 0000000..931cacf
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_left.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/split_divider_corner_size"
+ android:height="@dimen/split_divider_corner_size"
+ android:viewportWidth="42"
+ android:viewportHeight="42">
+
+ <group android:pivotX="21"
+ android:pivotY="21"
+ android:rotation="-90">
+ <path
+ android:fillColor="@color/split_divider_background"
+ android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml
new file mode 100644
index 0000000..54e4761
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_right.xml
@@ -0,0 +1,30 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/split_divider_corner_size"
+ android:height="@dimen/split_divider_corner_size"
+ android:viewportWidth="42"
+ android:viewportHeight="42">
+
+ <group android:pivotX="21"
+ android:pivotY="21"
+ android:rotation="90">
+ <path
+ android:fillColor="@color/split_divider_background"
+ android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+ </group>
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/drawable/split_rounded_top.xml b/libs/WindowManager/Shell/res/drawable/split_rounded_top.xml
new file mode 100644
index 0000000..9115b5a
--- /dev/null
+++ b/libs/WindowManager/Shell/res/drawable/split_rounded_top.xml
@@ -0,0 +1,26 @@
+<!--
+ ~ 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.
+ -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="@dimen/split_divider_corner_size"
+ android:height="@dimen/split_divider_corner_size"
+ android:viewportWidth="42"
+ android:viewportHeight="42">
+
+ <path
+ android:fillColor="@color/split_divider_background"
+ android:pathData="m 0 0 c 8 0 16 8 16 16 h 10 c 0 -8 8 -16 16 -16 z" />
+
+</vector>
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
index ed5d2e1..d732b01 100644
--- a/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/docked_stack_divider.xml
@@ -22,7 +22,7 @@
<View
style="@style/DockedDividerBackground"
android:id="@+id/docked_divider_background"
- android:background="@color/docked_divider_background"/>
+ android:background="@color/split_divider_background"/>
<com.android.wm.shell.legacysplitscreen.MinimizedDockShadow
style="@style/DockedDividerMinimizedShadow"
diff --git a/libs/WindowManager/Shell/res/layout/split_divider.xml b/libs/WindowManager/Shell/res/layout/split_divider.xml
index 7f583f3..94182cd 100644
--- a/libs/WindowManager/Shell/res/layout/split_divider.xml
+++ b/libs/WindowManager/Shell/res/layout/split_divider.xml
@@ -19,15 +19,25 @@
android:layout_height="match_parent"
android:layout_width="match_parent">
- <View
- style="@style/DockedDividerBackground"
- android:id="@+id/docked_divider_background"
- android:background="@color/docked_divider_background"/>
+ <FrameLayout
+ android:id="@+id/divider_bar"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent">
- <com.android.wm.shell.common.split.DividerHandleView
- style="@style/DockedDividerHandle"
- android:id="@+id/docked_divider_handle"
- android:contentDescription="@string/accessibility_divider"
- android:background="@null"/>
+ <View style="@style/DockedDividerTopLeftRoundCorner"/>
+
+ <View
+ style="@style/DockedDividerBackground"
+ android:id="@+id/docked_divider_background"/>
+
+ <View style="@style/DockedDividerBottomRightRoundCorner"/>
+
+ <com.android.wm.shell.common.split.DividerHandleView
+ style="@style/DockedDividerHandle"
+ android:id="@+id/docked_divider_handle"
+ android:contentDescription="@string/accessibility_divider"
+ android:background="@null"/>
+
+ </FrameLayout>
</com.android.wm.shell.common.split.DividerView>
diff --git a/libs/WindowManager/Shell/res/values-land/dimens.xml b/libs/WindowManager/Shell/res/values-land/dimens.xml
index aafba58..a95323f 100644
--- a/libs/WindowManager/Shell/res/values-land/dimens.xml
+++ b/libs/WindowManager/Shell/res/values-land/dimens.xml
@@ -16,8 +16,12 @@
*/
-->
<resources>
+ <!-- Divider handle size for legacy split screen -->
<dimen name="docked_divider_handle_width">2dp</dimen>
<dimen name="docked_divider_handle_height">16dp</dimen>
+ <!-- Divider handle size for split screen -->
+ <dimen name="split_divider_handle_width">3dp</dimen>
+ <dimen name="split_divider_handle_height">72dp</dimen>
<!-- Padding between status bar and bubbles when displayed in expanded state, smaller
value in landscape since we have limited vertical space-->
diff --git a/libs/WindowManager/Shell/res/values-land/styles.xml b/libs/WindowManager/Shell/res/values-land/styles.xml
index 863bb69..e5707f3 100644
--- a/libs/WindowManager/Shell/res/values-land/styles.xml
+++ b/libs/WindowManager/Shell/res/values-land/styles.xml
@@ -19,6 +19,7 @@
<item name="android:layout_width">10dp</item>
<item name="android:layout_height">match_parent</item>
<item name="android:layout_gravity">center_horizontal</item>
+ <item name="android:background">@color/split_divider_background</item>
</style>
<style name="DockedDividerHandle">
@@ -27,6 +28,20 @@
<item name="android:layout_height">96dp</item>
</style>
+ <style name="DockedDividerTopLeftRoundCorner">
+ <item name="android:layout_gravity">center_horizontal|top</item>
+ <item name="android:background">@drawable/split_rounded_top</item>
+ <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+ <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+ </style>
+
+ <style name="DockedDividerBottomRightRoundCorner">
+ <item name="android:layout_gravity">center_horizontal|bottom</item>
+ <item name="android:background">@drawable/split_rounded_bottom</item>
+ <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+ <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+ </style>
+
<style name="DockedDividerMinimizedShadow">
<item name="android:layout_width">8dp</item>
<item name="android:layout_height">match_parent</item>
diff --git a/libs/WindowManager/Shell/res/values/colors.xml b/libs/WindowManager/Shell/res/values/colors.xml
index 350beaf..93c0352 100644
--- a/libs/WindowManager/Shell/res/values/colors.xml
+++ b/libs/WindowManager/Shell/res/values/colors.xml
@@ -17,7 +17,6 @@
*/
-->
<resources>
- <color name="docked_divider_background">#ff000000</color>
<color name="docked_divider_handle">#ffffff</color>
<drawable name="forced_resizable_background">#59000000</drawable>
<color name="minimize_dock_shadow_start">#60000000</color>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 130f741..f8576643 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -76,8 +76,15 @@
<!-- How high we lift the divider when touching -->
<dimen name="docked_stack_divider_lift_elevation">4dp</dimen>
+ <!-- Divider handle size for legacy split screen -->
<dimen name="docked_divider_handle_width">16dp</dimen>
<dimen name="docked_divider_handle_height">2dp</dimen>
+ <!-- Divider handle size for split screen -->
+ <dimen name="split_divider_handle_width">72dp</dimen>
+ <dimen name="split_divider_handle_height">3dp</dimen>
+
+ <dimen name="split_divider_bar_width">10dp</dimen>
+ <dimen name="split_divider_corner_size">42dp</dimen>
<!-- One-Handed Mode -->
<!-- Threshold for dragging distance to enable one-handed mode -->
diff --git a/libs/WindowManager/Shell/res/values/styles.xml b/libs/WindowManager/Shell/res/values/styles.xml
index fffcd33..28ff25a 100644
--- a/libs/WindowManager/Shell/res/values/styles.xml
+++ b/libs/WindowManager/Shell/res/values/styles.xml
@@ -32,8 +32,23 @@
<style name="DockedDividerBackground">
<item name="android:layout_width">match_parent</item>
- <item name="android:layout_height">10dp</item>
+ <item name="android:layout_height">@dimen/split_divider_bar_width</item>
<item name="android:layout_gravity">center_vertical</item>
+ <item name="android:background">@color/split_divider_background</item>
+ </style>
+
+ <style name="DockedDividerTopLeftRoundCorner">
+ <item name="android:layout_gravity">center_vertical|left</item>
+ <item name="android:background">@drawable/split_rounded_left</item>
+ <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+ <item name="android:layout_height">@dimen/split_divider_corner_size</item>
+ </style>
+
+ <style name="DockedDividerBottomRightRoundCorner">
+ <item name="android:layout_gravity">center_vertical|right</item>
+ <item name="android:background">@drawable/split_rounded_right</item>
+ <item name="android:layout_width">@dimen/split_divider_corner_size</item>
+ <item name="android:layout_height">@dimen/split_divider_corner_size</item>
</style>
<style name="DockedDividerMinimizedShadow">
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index 95b80df..9dafefe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -628,8 +628,11 @@
mAddedToWindowManager = true;
mBubbleData.getOverflow().initialize(this);
mWindowManager.addView(mStackView, mWmLayoutParams);
- // Position info is dependent on us being attached to a window
- mBubblePositioner.update();
+ mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
+ mBubblePositioner.update();
+ mStackView.onDisplaySizeChanged();
+ return windowInsets;
+ });
} catch (IllegalStateException e) {
// This means the stack has already been added. This shouldn't happen...
e.printStackTrace();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
index 5a51eed..5bc6128 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleStackView.java
@@ -1315,6 +1315,7 @@
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
+ mPositioner.update();
getViewTreeObserver().addOnComputeInternalInsetsListener(this);
getViewTreeObserver().addOnDrawListener(mSystemGestureExcludeUpdater);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
index 9a3bdab..a1fb658 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayController.java
@@ -67,7 +67,10 @@
*/
public void initialize() {
try {
- mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+ int[] displayIds = mWmService.registerDisplayWindowListener(mDisplayContainerListener);
+ for (int i = 0; i < displayIds.length; i++) {
+ onDisplayAdded(displayIds[i]);
+ }
} catch (RemoteException e) {
throw new RuntimeException("Unable to register display controller");
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
index 5f3de7e..565f148 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayInsetsController.java
@@ -233,18 +233,18 @@
* control. Won't be called if config_remoteInsetsControllerControlsSystemBars is false.
* @param packageName: Passes the top package name
*/
- void topFocusedWindowChanged(String packageName);
+ default void topFocusedWindowChanged(String packageName) {}
/**
* Called when the window insets configuration has changed.
*/
- void insetsChanged(InsetsState insetsState);
+ default void insetsChanged(InsetsState insetsState) {}
/**
* Called when this window retrieved control over a specified set of insets sources.
*/
- void insetsControlChanged(InsetsState insetsState,
- InsetsSourceControl[] activeControls);
+ default void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {}
/**
* Called when a set of insets source window should be shown by policy.
@@ -252,7 +252,7 @@
* @param types internal insets types (WindowInsets.Type.InsetsType) to show
* @param fromIme true if this request originated from IME (InputMethodService).
*/
- void showInsets(int types, boolean fromIme);
+ default void showInsets(int types, boolean fromIme) {}
/**
* Called when a set of insets source window should be hidden by policy.
@@ -260,6 +260,6 @@
* @param types internal insets types (WindowInsets.Type.InsetsType) to hide
* @param fromIme true if this request originated from IME (InputMethodService).
*/
- void hideInsets(int types, boolean fromIme);
+ default void hideInsets(int types, boolean fromIme) {}
}
}
\ No newline at end of file
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/DividerHandleView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
index 218bf47..c76937d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerHandleView.java
@@ -70,7 +70,8 @@
private final Paint mPaint = new Paint();
private final int mWidth;
private final int mHeight;
- private final int mCircleDiameter;
+ private final int mTouchingWidth;
+ private final int mTouchingHeight;
private int mCurrentWidth;
private int mCurrentHeight;
private AnimatorSet mAnimator;
@@ -80,11 +81,12 @@
super(context, attrs);
mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
mPaint.setAntiAlias(true);
- mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
- mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+ mWidth = getResources().getDimensionPixelSize(R.dimen.split_divider_handle_width);
+ mHeight = getResources().getDimensionPixelSize(R.dimen.split_divider_handle_height);
mCurrentWidth = mWidth;
mCurrentHeight = mHeight;
- mCircleDiameter = (mWidth + mHeight) / 3;
+ mTouchingWidth = mWidth > mHeight ? mWidth / 2 : mWidth;
+ mTouchingHeight = mHeight > mWidth ? mHeight / 2 : mHeight;
}
/** Sets touching state for this handle view. */
@@ -98,16 +100,16 @@
}
if (!animate) {
if (touching) {
- mCurrentWidth = mCircleDiameter;
- mCurrentHeight = mCircleDiameter;
+ mCurrentWidth = mTouchingWidth;
+ mCurrentHeight = mTouchingHeight;
} else {
mCurrentWidth = mWidth;
mCurrentHeight = mHeight;
}
invalidate();
} else {
- animateToTarget(touching ? mCircleDiameter : mWidth,
- touching ? mCircleDiameter : mHeight, touching);
+ animateToTarget(touching ? mTouchingWidth : mWidth,
+ touching ? mTouchingHeight : mHeight, touching);
}
mTouching = touching;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
index cba019a..f35c8e1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerView.java
@@ -19,15 +19,23 @@
import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
import static android.view.WindowManager.LayoutParams.FLAG_SLIPPERY;
+import android.animation.ObjectAnimator;
import android.content.Context;
+import android.graphics.Rect;
import android.util.AttributeSet;
+import android.util.Property;
+import android.util.TypedValue;
import android.view.GestureDetector;
+import android.view.InsetsSource;
+import android.view.InsetsState;
import android.view.MotionEvent;
import android.view.SurfaceControlViewHost;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
+import android.view.ViewGroup;
import android.view.WindowManager;
+import android.view.animation.Interpolator;
import android.widget.FrameLayout;
import androidx.annotation.NonNull;
@@ -44,6 +52,15 @@
public static final long TOUCH_ANIMATION_DURATION = 150;
public static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
+ // TODO(b/191269755): use the value defined in InsetsController.
+ private static final Interpolator RESIZE_INTERPOLATOR = Interpolators.LINEAR;
+
+ // TODO(b/191269755): use the value defined in InsetsController.
+ private static final int ANIMATION_DURATION_RESIZE = 300;
+
+ /** The task bar expanded height. Used to determine whether to insets divider bounds or not. */
+ private float mExpandedTaskBarHeight;
+
private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
private SplitLayout mSplitLayout;
@@ -58,6 +75,31 @@
private GestureDetector mDoubleTapDetector;
private boolean mInteractive;
+ /**
+ * Tracks divider bar visible bounds in screen-based coordination. Used to calculate with
+ * insets.
+ */
+ private final Rect mDividerBounds = new Rect();
+ private final Rect mTempRect = new Rect();
+ private FrameLayout mDividerBar;
+
+
+ static final Property<DividerView, Integer> DIVIDER_HEIGHT_PROPERTY =
+ new Property<DividerView, Integer>(Integer.class, "height") {
+ @Override
+ public Integer get(DividerView object) {
+ return object.mDividerBar.getLayoutParams().height;
+ }
+
+ @Override
+ public void set(DividerView object, Integer value) {
+ ViewGroup.MarginLayoutParams lp = (ViewGroup.MarginLayoutParams)
+ object.mDividerBar.getLayoutParams();
+ lp.height = value;
+ object.mDividerBar.setLayoutParams(lp);
+ }
+ };
+
public DividerView(@NonNull Context context) {
super(context);
}
@@ -79,16 +121,46 @@
/** Sets up essential dependencies of the divider bar. */
public void setup(
SplitLayout layout,
- SurfaceControlViewHost viewHost) {
+ SurfaceControlViewHost viewHost,
+ InsetsState insetsState) {
mSplitLayout = layout;
mViewHost = viewHost;
+ mDividerBounds.set(layout.getDividerBounds());
+ onInsetsChanged(insetsState, false /* animate */);
+ }
+
+ void onInsetsChanged(InsetsState insetsState, boolean animate) {
+ mTempRect.set(mSplitLayout.getDividerBounds());
+ final InsetsSource taskBarInsetsSource =
+ insetsState.getSource(InsetsState.ITYPE_EXTRA_NAVIGATION_BAR);
+ // Only insets the divider bar with task bar when it's expanded so that the rounded corners
+ // will be drawn against task bar.
+ if (taskBarInsetsSource.getFrame().height() >= mExpandedTaskBarHeight) {
+ mTempRect.inset(taskBarInsetsSource.calculateVisibleInsets(mTempRect));
+ }
+
+ if (!mTempRect.equals(mDividerBounds)) {
+ if (animate) {
+ ObjectAnimator animator = ObjectAnimator.ofInt(this,
+ DIVIDER_HEIGHT_PROPERTY, mDividerBounds.height(), mTempRect.height());
+ animator.setInterpolator(RESIZE_INTERPOLATOR);
+ animator.setDuration(ANIMATION_DURATION_RESIZE);
+ animator.start();
+ } else {
+ DIVIDER_HEIGHT_PROPERTY.set(this, mTempRect.height());
+ }
+ mDividerBounds.set(mTempRect);
+ }
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
+ mDividerBar = findViewById(R.id.divider_bar);
mHandle = findViewById(R.id.docked_divider_handle);
mBackground = findViewById(R.id.docked_divider_background);
+ mExpandedTaskBarHeight = getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.taskbar_frame_height);
mTouchElevation = getResources().getDimensionPixelSize(
R.dimen.docked_stack_divider_lift_elevation);
mDoubleTapDetector = new GestureDetector(getContext(), new DoubleTapListener());
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..754b8da 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
@@ -40,6 +40,8 @@
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
+import android.view.InsetsSourceControl;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -50,15 +52,17 @@
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;
+import com.android.wm.shell.common.DisplayInsetsController;
/**
* Records and handles layout of splits. Helps to calculate proper bounds when configuration or
* divide position changes.
*/
-public final class SplitLayout {
+public final class SplitLayout implements DisplayInsetsController.OnInsetsChangedListener {
/**
* Split position isn't specified normally meaning to use what ever it is currently set to.
*/
@@ -93,16 +97,20 @@
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;
private final ImePositionProcessor mImePositionProcessor;
private final DismissingParallaxPolicy mDismissingParallaxPolicy;
private final ShellTaskOrganizer mTaskOrganizer;
+ private final InsetsState mInsetsState = new InsetsState();
private Context mContext;
private DividerSnapAlgorithm mDividerSnapAlgorithm;
+ private WindowContainerToken mWinToken1;
+ private WindowContainerToken mWinToken2;
private int mDividePosition;
private boolean mInitialized = false;
private int mOrientation;
@@ -189,10 +197,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 +244,8 @@
mBounds1.bottom = position;
mBounds2.top = mBounds1.bottom + mDividerSize;
}
+ DockedDividerUtils.sanitizeStackBounds(mBounds1, true /** topLeft */);
+ DockedDividerUtils.sanitizeStackBounds(mBounds2, false /** topLeft */);
mDismissingParallaxPolicy.applyDividerPosition(position, isLandscape);
}
@@ -243,7 +253,7 @@
public void init() {
if (mInitialized) return;
mInitialized = true;
- mSplitWindowManager.init(this);
+ mSplitWindowManager.init(this, mInsetsState);
mDisplayImeController.addPositionProcessor(mImePositionProcessor);
}
@@ -256,6 +266,23 @@
mImePositionProcessor.reset();
}
+ @Override
+ public void insetsChanged(InsetsState insetsState) {
+ mInsetsState.set(insetsState);
+ if (!mInitialized) {
+ return;
+ }
+ mSplitWindowManager.onInsetsChanged(insetsState);
+ }
+
+ @Override
+ public void insetsControlChanged(InsetsState insetsState,
+ InsetsSourceControl[] activeControls) {
+ if (!mInsetsState.equals(insetsState)) {
+ insetsChanged(insetsState);
+ }
+ }
+
/**
* Updates bounds with the passing position. Usually used to update recording bounds while
* performing animation or dragging divider bar to resize the splits.
@@ -278,6 +305,10 @@
mDividePosition = mDividerSnapAlgorithm.getMiddleTarget().position;
mSplitWindowManager.setResizingSplits(false);
updateBounds(mDividePosition);
+ mWinToken1 = null;
+ mWinToken2 = null;
+ mWinBounds1.setEmpty();
+ mWinBounds2.setEmpty();
}
/**
@@ -403,8 +434,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;
+ }
}
/**
@@ -492,7 +531,7 @@
/**
* Applies a parallax to the task to hint dismissing progress.
*
- * @param position the split position to apply dismissing parallax effect
+ * @param position the split position to apply dismissing parallax effect
* @param isLandscape indicates whether it's splitting horizontally or vertically
*/
void applyDividerPosition(int position, boolean isLandscape) {
@@ -504,11 +543,11 @@
if (position <= mDividerSnapAlgorithm.getFirstSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_LEFT : DOCKED_TOP;
totalDismissingDistance = mDividerSnapAlgorithm.getDismissStartTarget().position
- - mDividerSnapAlgorithm.getFirstSplitTarget().position;
+ - mDividerSnapAlgorithm.getFirstSplitTarget().position;
} else if (position >= mDividerSnapAlgorithm.getLastSplitTarget().position) {
mDismissingSide = isLandscape ? DOCKED_RIGHT : DOCKED_BOTTOM;
totalDismissingDistance = mDividerSnapAlgorithm.getLastSplitTarget().position
- - mDividerSnapAlgorithm.getDismissEndTarget().position;
+ - mDividerSnapAlgorithm.getDismissEndTarget().position;
}
if (mDismissingSide != DOCKED_INVALID) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
index b7bbe80..fc7edfc 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitWindowManager.java
@@ -36,6 +36,7 @@
import android.os.RemoteException;
import android.util.Slog;
import android.view.IWindow;
+import android.view.InsetsState;
import android.view.LayoutInflater;
import android.view.SurfaceControl;
import android.view.SurfaceControlViewHost;
@@ -103,7 +104,7 @@
}
/** Inflates {@link DividerView} on to the root surface. */
- void init(SplitLayout splitLayout) {
+ void init(SplitLayout splitLayout, InsetsState insetsState) {
if (mDividerView != null || mViewHost != null) {
throw new UnsupportedOperationException(
"Try to inflate divider view again without release first");
@@ -123,7 +124,7 @@
lp.setTitle(mWindowName);
lp.privateFlags |= PRIVATE_FLAG_NO_MOVE_ANIMATION | PRIVATE_FLAG_TRUSTED_OVERLAY;
mViewHost.setView(mDividerView, lp);
- mDividerView.setup(splitLayout, mViewHost);
+ mDividerView.setup(splitLayout, mViewHost, insetsState);
}
/**
@@ -169,4 +170,10 @@
SurfaceControl getSurfaceControl() {
return mLeash;
}
+
+ void onInsetsChanged(InsetsState insetsState) {
+ if (mDividerView != null) {
+ mDividerView.onInsetsChanged(insetsState, true /* animate */);
+ }
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
index 64f7be5..73deea5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DropOutlineDrawable.java
@@ -86,7 +86,7 @@
public DropOutlineDrawable(Context context) {
super();
// TODO(b/169894807): Use corner specific radii and maybe lower radius for non-edge corners
- mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context.getResources());
+ mCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context);
mColor = context.getColor(R.color.drop_outline_background);
mMaxAlpha = Color.alpha(mColor);
// Initialize as hidden
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/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
index a646b07..ae8c1b6 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PhonePipMenuController.java
@@ -60,8 +60,7 @@
private static final boolean DEBUG = false;
public static final int MENU_STATE_NONE = 0;
- public static final int MENU_STATE_CLOSE = 1;
- public static final int MENU_STATE_FULL = 2;
+ public static final int MENU_STATE_FULL = 1;
/**
* A listener interface to receive notification on changes in PIP.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
index 67b1e6d..8ef2b6b 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipMenuView.java
@@ -23,7 +23,6 @@
import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_ICONS;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
@@ -203,7 +202,7 @@
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
- if (action == ACTION_CLICK && mMenuState == MENU_STATE_CLOSE) {
+ if (action == ACTION_CLICK && mMenuState != MENU_STATE_FULL) {
mController.showMenu();
}
return super.performAccessibilityAction(host, action, args);
@@ -271,13 +270,12 @@
mDismissButton.getAlpha(), 1f);
ObjectAnimator resizeAnim = ObjectAnimator.ofFloat(mResizeHandle, View.ALPHA,
mResizeHandle.getAlpha(),
- ENABLE_RESIZE_HANDLE && menuState == MENU_STATE_CLOSE && showResizeHandle
- ? 1f : 0f);
+ ENABLE_RESIZE_HANDLE && showResizeHandle ? 1f : 0f);
if (menuState == MENU_STATE_FULL) {
mMenuContainerAnimator.playTogether(menuAnim, settingsAnim, dismissAnim,
resizeAnim);
} else {
- mMenuContainerAnimator.playTogether(dismissAnim, resizeAnim);
+ mMenuContainerAnimator.playTogether(resizeAnim);
}
mMenuContainerAnimator.setInterpolator(Interpolators.ALPHA_IN);
mMenuContainerAnimator.setDuration(ANIMATION_HIDE_DURATION_MS);
@@ -429,7 +427,7 @@
FrameLayout.LayoutParams expandedLp =
(FrameLayout.LayoutParams) expandContainer.getLayoutParams();
- if (mActions.isEmpty() || menuState == MENU_STATE_CLOSE || menuState == MENU_STATE_NONE) {
+ if (mActions.isEmpty() || menuState == MENU_STATE_NONE) {
actionsContainer.setVisibility(View.INVISIBLE);
// Update the expand container margin to adjust the center of the expand button to
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
index 7867f93..9f2f6a5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipTouchHandler.java
@@ -22,7 +22,6 @@
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_LEFT;
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_NONE;
import static com.android.wm.shell.pip.PipBoundsState.STASH_TYPE_RIGHT;
-import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_CLOSE;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_FULL;
import static com.android.wm.shell.pip.phone.PhonePipMenuController.MENU_STATE_NONE;
import static com.android.wm.shell.pip.phone.PipMenuView.ANIM_TYPE_NONE;
@@ -81,7 +80,6 @@
private final PhonePipMenuController mMenuController;
private final AccessibilityManager mAccessibilityManager;
- private boolean mShowPipMenuOnAnimationEnd = false;
/**
* Whether PIP stash is enabled or not. When enabled, if the user flings toward the edge of the
@@ -280,7 +278,6 @@
public void onActivityPinned() {
mPipDismissTargetHandler.createOrUpdateDismissTarget();
- mShowPipMenuOnAnimationEnd = true;
mPipResizeGestureHandler.onActivityPinned();
mFloatingContentCoordinator.onContentAdded(mMotionHelper);
}
@@ -304,13 +301,6 @@
// Set the initial bounds as the user resize bounds.
mPipResizeGestureHandler.setUserResizeBounds(mPipBoundsState.getBounds());
}
-
- if (mShowPipMenuOnAnimationEnd) {
- mMenuController.showMenu(MENU_STATE_CLOSE, mPipBoundsState.getBounds(),
- true /* allowMenuTimeout */, false /* willResizeMenu */,
- shouldShowResizeHandle());
- mShowPipMenuOnAnimationEnd = false;
- }
}
public void onConfigurationChanged() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
index 6ec514b..2dd5393 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/ISplitScreen.aidl
@@ -22,7 +22,7 @@
import android.os.UserHandle;
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import com.android.wm.shell.splitscreen.ISplitScreenListener;
@@ -82,7 +82,7 @@
* Starts tasks simultaneously in one transition.
*/
oneway void startTasks(int mainTaskId, in Bundle mainOptions, int sideTaskId,
- in Bundle sideOptions, int sidePosition, in IRemoteTransition remoteTransition) = 10;
+ in Bundle sideOptions, int sidePosition, in RemoteTransition remoteTransition) = 10;
/**
* Version of startTasks using legacy transition system.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 67223c3..804fba7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -22,7 +22,6 @@
import static com.android.wm.shell.common.ExecutorUtils.executeRemoteCallWithTaskPermission;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitLayout.SPLIT_POSITION_TOP_OR_LEFT;
-import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
@@ -42,9 +41,9 @@
import android.view.RemoteAnimationAdapter;
import android.view.RemoteAnimationTarget;
import android.view.SurfaceControl;
-import android.view.WindowManager;
import android.view.SurfaceSession;
-import android.window.IRemoteTransition;
+import android.view.WindowManager;
+import android.window.RemoteTransition;
import android.window.WindowContainerTransaction;
import androidx.annotation.BinderThread;
@@ -56,6 +55,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.RemoteCallable;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
@@ -67,6 +67,7 @@
import com.android.wm.shell.transition.Transitions;
import java.io.PrintWriter;
+import java.util.Arrays;
import java.util.concurrent.Executor;
/**
@@ -74,6 +75,7 @@
* {@link SplitScreen}.
* @see StageCoordinator
*/
+// TODO(b/198577848): Implement split screen flicker test to consolidate CUJ of split screen.
public class SplitScreenController implements DragAndDropPolicy.Starter,
RemoteCallable<SplitScreenController> {
private static final String TAG = SplitScreenController.class.getSimpleName();
@@ -85,6 +87,7 @@
private final ShellExecutor mMainExecutor;
private final SplitScreenImpl mImpl = new SplitScreenImpl();
private final DisplayImeController mDisplayImeController;
+ private final DisplayInsetsController mDisplayInsetsController;
private final Transitions mTransitions;
private final TransactionPool mTransactionPool;
private final SplitscreenEventLogger mLogger;
@@ -95,6 +98,7 @@
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTDAOrganizer,
ShellExecutor mainExecutor, DisplayImeController displayImeController,
+ DisplayInsetsController displayInsetsController,
Transitions transitions, TransactionPool transactionPool) {
mTaskOrganizer = shellTaskOrganizer;
mSyncQueue = syncQueue;
@@ -102,6 +106,7 @@
mRootTDAOrganizer = rootTDAOrganizer;
mMainExecutor = mainExecutor;
mDisplayImeController = displayImeController;
+ mDisplayInsetsController = displayInsetsController;
mTransitions = transitions;
mTransactionPool = transactionPool;
mLogger = new SplitscreenEventLogger();
@@ -125,8 +130,8 @@
if (mStageCoordinator == null) {
// TODO: Multi-display
mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
- mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController, mTransitions,
- mTransactionPool, mLogger);
+ mRootTDAOrganizer, mTaskOrganizer, mDisplayImeController,
+ mDisplayInsetsController, mTransitions, mTransactionPool, mLogger);
}
}
@@ -236,46 +241,34 @@
private void startIntentLegacy(PendingIntent intent, Intent fillInIntent,
@SplitScreen.StageType int stage, @SplitPosition int position,
@Nullable Bundle options) {
- final boolean wasInSplit = isSplitScreenVisible();
-
LegacyTransitions.ILegacyTransition transition = new LegacyTransitions.ILegacyTransition() {
@Override
public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
IRemoteAnimationFinishedCallback finishedCallback,
SurfaceControl.Transaction t) {
- boolean cancelled = apps == null || apps.length == 0;
mStageCoordinator.updateSurfaceBounds(null /* layout */, t);
- if (cancelled) {
- if (!wasInSplit) {
- final WindowContainerTransaction undoWct = new WindowContainerTransaction();
- mStageCoordinator.prepareExitSplitScreen(STAGE_TYPE_MAIN, undoWct);
- mSyncQueue.queue(undoWct);
- mSyncQueue.runInSync(undoT -> {
- // looks weird, but we want undoT to execute after t but still want the
- // rest of the syncQueue runnables to aggregate.
- t.merge(undoT);
- undoT.merge(t);
- });
- return;
- }
- } else {
+
+ if (apps != null) {
for (int i = 0; i < apps.length; ++i) {
if (apps[i].mode == MODE_OPENING) {
t.show(apps[i].leash);
}
}
}
- RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
+
+ final RemoteAnimationTarget divider = mStageCoordinator.getDividerBarLegacyTarget();
if (divider.leash != null) {
t.show(divider.leash);
}
+
t.apply();
- if (cancelled) return;
- try {
- finishedCallback.onAnimationFinished();
- } catch (RemoteException e) {
- Slog.e(TAG, "Error finishing legacy transition: ", e);
+ if (finishedCallback != null) {
+ try {
+ finishedCallback.onAnimationFinished();
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Error finishing legacy transition: ", e);
+ }
}
}
};
@@ -295,11 +288,15 @@
mRootTDAOrganizer.attachToDisplayArea(DEFAULT_DISPLAY, builder);
SurfaceControl sc = builder.build();
SurfaceControl.Transaction transaction = new SurfaceControl.Transaction();
+
+ // Ensure that we order these in the parent in the right z-order as their previous order
+ Arrays.sort(apps, (a1, a2) -> a1.prefixOrderIndex - a2.prefixOrderIndex);
+ int layer = 1;
for (RemoteAnimationTarget appTarget : apps) {
- // TODO(b/195958376) set the correct layer/z-order in transaction for the new surface
transaction.reparent(appTarget.leash, sc);
transaction.setPosition(appTarget.leash, appTarget.screenSpaceBounds.left,
appTarget.screenSpaceBounds.top);
+ transaction.setLayer(appTarget.leash, layer++);
}
transaction.apply();
transaction.close();
@@ -556,7 +553,7 @@
public void startTasks(int mainTaskId, @Nullable Bundle mainOptions,
int sideTaskId, @Nullable Bundle sideOptions,
@SplitPosition int sidePosition,
- @Nullable IRemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mController, "startTasks",
(controller) -> controller.mStageCoordinator.startTasks(mainTaskId, mainOptions,
sideTaskId, sideOptions, sidePosition, remoteTransition));
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index 69d0be6..86e7b0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -35,7 +35,7 @@
import android.os.IBinder;
import android.view.SurfaceControl;
import android.view.WindowManager;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
import android.window.WindowContainerTransaction;
@@ -169,7 +169,7 @@
/** Starts a transition to enter split with a remote transition animator. */
IBinder startEnterTransition(@WindowManager.TransitionType int transitType,
- @NonNull WindowContainerTransaction wct, @Nullable IRemoteTransition remoteTransition,
+ @NonNull WindowContainerTransaction wct, @Nullable RemoteTransition remoteTransition,
@NonNull Transitions.TransitionHandler handler) {
if (remoteTransition != null) {
// Wrapping it for ease-of-use (OneShot handles all the binder linking/death stuff)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index 736fae4..33c3fb70 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -72,7 +72,7 @@
import android.view.SurfaceSession;
import android.view.WindowManager;
import android.window.DisplayAreaInfo;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerToken;
@@ -85,6 +85,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
@@ -136,6 +137,7 @@
private final Context mContext;
private final List<SplitScreen.SplitScreenListener> mListeners = new ArrayList<>();
private final DisplayImeController mDisplayImeController;
+ private final DisplayInsetsController mDisplayInsetsController;
private final SplitScreenTransitions mSplitTransitions;
private final SplitscreenEventLogger mLogger;
private boolean mExitSplitScreenOnHide;
@@ -163,7 +165,8 @@
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
- DisplayImeController displayImeController, Transitions transitions,
+ DisplayImeController displayImeController,
+ DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool, SplitscreenEventLogger logger) {
mContext = context;
mDisplayId = displayId;
@@ -185,6 +188,7 @@
mSyncQueue,
mSurfaceSession);
mDisplayImeController = displayImeController;
+ mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this);
final DeviceStateManager deviceStateManager =
mContext.getSystemService(DeviceStateManager.class);
@@ -199,7 +203,8 @@
StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController displayImeController,
- SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
+ DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
+ Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) {
mContext = context;
mDisplayId = displayId;
@@ -209,6 +214,7 @@
mMainStage = mainStage;
mSideStage = sideStage;
mDisplayImeController = displayImeController;
+ mDisplayInsetsController = displayInsetsController;
mRootTDAOrganizer.registerListener(displayId, this);
mSplitLayout = splitLayout;
mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
@@ -257,7 +263,7 @@
/** Starts 2 tasks in one transition. */
void startTasks(int mainTaskId, @Nullable Bundle mainOptions, int sideTaskId,
@Nullable Bundle sideOptions, @SplitPosition int sidePosition,
- @Nullable IRemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
mainOptions = mainOptions != null ? mainOptions : new Bundle();
sideOptions = sideOptions != null ? sideOptions : new Bundle();
@@ -352,7 +358,7 @@
public void startIntent(PendingIntent intent, Intent fillInIntent,
@SplitScreen.StageType int stage, @SplitPosition int position,
@androidx.annotation.Nullable Bundle options,
- @Nullable IRemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition) {
final WindowContainerTransaction wct = new WindowContainerTransaction();
options = resolveStartStage(stage, position, options, wct);
wct.sendPendingIntent(intent, fillInIntent, options);
@@ -832,6 +838,7 @@
mDisplayAreaInfo.configuration, this,
b -> mRootTDAOrganizer.attachToDisplayArea(mDisplayId, b),
mDisplayImeController, mTaskOrganizer);
+ mDisplayInsetsController.addInsetsChangedListener(mDisplayId, mSplitLayout);
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
index 3512a0c..da91c1c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageTaskListener.java
@@ -113,10 +113,20 @@
/** @return {@code true} if this listener contains the currently focused task. */
boolean isFocused() {
- if (mRootTaskInfo.isFocused) return true;
- for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
- if (mChildrenTaskInfo.valueAt(i).isFocused) return true;
+ if (mRootTaskInfo == null) {
+ return false;
}
+
+ if (mRootTaskInfo.isFocused) {
+ return true;
+ }
+
+ for (int i = mChildrenTaskInfo.size() - 1; i >= 0; --i) {
+ if (mChildrenTaskInfo.valueAt(i).isFocused) {
+ return true;
+ }
+ }
+
return false;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
index 2286598..8df7cbb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenContentDrawer.java
@@ -50,6 +50,7 @@
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.ContextThemeWrapper;
import android.view.SurfaceControl;
import android.view.View;
import android.window.SplashScreenView;
@@ -137,12 +138,14 @@
* null if failed.
*/
void createContentView(Context context, @StartingWindowType int suggestType, ActivityInfo info,
- int taskId, Consumer<SplashScreenView> splashScreenViewConsumer) {
+ int taskId, Consumer<SplashScreenView> splashScreenViewConsumer,
+ Consumer<Runnable> uiThreadInitConsumer) {
mSplashscreenWorkerHandler.post(() -> {
SplashScreenView contentView;
try {
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "makeSplashScreenContentView");
- contentView = makeSplashScreenContentView(context, info, suggestType);
+ contentView = makeSplashScreenContentView(context, info, suggestType,
+ uiThreadInitConsumer);
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
} catch (RuntimeException e) {
Slog.w(TAG, "failed creating starting window content at taskId: "
@@ -238,7 +241,7 @@
}
private SplashScreenView makeSplashScreenContentView(Context context, ActivityInfo ai,
- @StartingWindowType int suggestType) {
+ @StartingWindowType int suggestType, Consumer<Runnable> uiThreadInitConsumer) {
updateDensity();
getWindowAttrs(context, mTmpAttrs);
@@ -253,6 +256,7 @@
.setWindowBGColor(themeBGColor)
.overlayDrawable(legacyDrawable)
.chooseStyle(suggestType)
+ .setUiThreadInitConsumer(uiThreadInitConsumer)
.build();
}
@@ -299,6 +303,11 @@
}
}
+ /** Creates the wrapper with system theme to avoid unexpected styles from app. */
+ ContextThemeWrapper createViewContextWrapper(Context appContext) {
+ return new ContextThemeWrapper(appContext, mContext.getTheme());
+ }
+
/** The configuration of the splash screen window. */
public static class SplashScreenWindowAttrs {
private int mWindowBgResId = 0;
@@ -318,6 +327,7 @@
private int mThemeColor;
private Drawable[] mFinalIconDrawables;
private int mFinalIconSize = mIconSize;
+ private Consumer<Runnable> mUiThreadInitTask;
StartingWindowViewBuilder(@NonNull Context context, @NonNull ActivityInfo aInfo) {
mContext = context;
@@ -339,6 +349,11 @@
return this;
}
+ StartingWindowViewBuilder setUiThreadInitConsumer(Consumer<Runnable> uiThreadInitTask) {
+ mUiThreadInitTask = uiThreadInitTask;
+ return this;
+ }
+
SplashScreenView build() {
Drawable iconDrawable;
final int animationDuration;
@@ -385,7 +400,8 @@
animationDuration = 0;
}
- return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration);
+ return fillViewWithIcon(mFinalIconSize, mFinalIconDrawables, animationDuration,
+ mUiThreadInitTask);
}
private class ShapeIconFactory extends BaseIconFactory {
@@ -463,7 +479,7 @@
}
private SplashScreenView fillViewWithIcon(int iconSize, @Nullable Drawable[] iconDrawable,
- int animationDuration) {
+ int animationDuration, Consumer<Runnable> uiThreadInitTask) {
Drawable foreground = null;
Drawable background = null;
if (iconDrawable != null) {
@@ -472,13 +488,15 @@
}
Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "fillViewWithIcon");
- final SplashScreenView.Builder builder = new SplashScreenView.Builder(mContext)
+ final ContextThemeWrapper wrapper = createViewContextWrapper(mContext);
+ final SplashScreenView.Builder builder = new SplashScreenView.Builder(wrapper)
.setBackgroundColor(mThemeColor)
.setOverlayDrawable(mOverlayDrawable)
.setIconSize(iconSize)
.setIconBackground(background)
.setCenterViewDrawable(foreground)
- .setAnimationDurationMillis(animationDuration);
+ .setAnimationDurationMillis(animationDuration)
+ .setUiThreadInitConsumer(uiThreadInitTask);
if (mSuggestType == STARTING_WINDOW_TYPE_SPLASH_SCREEN
&& mTmpAttrs.mBrandingImage != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
index 951b97e..f0685a8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/SplashscreenIconDrawableFactory.java
@@ -304,6 +304,13 @@
return true;
}
+ @Override
+ public void stopAnimation() {
+ if (mIconAnimator != null) {
+ mIconAnimator.end();
+ }
+ }
+
private final Callback mCallback = new Callback() {
@Override
public void invalidateDrawable(@NonNull Drawable who) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
index 01c9b66..76105a3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurface.java
@@ -36,4 +36,12 @@
default int getBackgroundColor(TaskInfo taskInfo) {
return Color.BLACK;
}
+
+ /** Set the proxy to communicate with SysUi side components. */
+ void setSysuiProxy(SysuiProxy proxy);
+
+ /** Callback to tell SysUi components execute some methods. */
+ interface SysuiProxy {
+ void requestTopUi(boolean requestTopUi, String componentTag);
+ }
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 52a3ac5..debe6d5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -117,6 +117,7 @@
final SplashscreenContentDrawer mSplashscreenContentDrawer;
private Choreographer mChoreographer;
private final WindowManagerGlobal mWindowManagerGlobal;
+ private StartingSurface.SysuiProxy mSysuiProxy;
/**
* @param splashScreenExecutor The thread used to control add and remove starting window.
@@ -145,12 +146,17 @@
return mDisplayManager.getDisplay(displayId);
}
- private int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
+ int getSplashScreenTheme(int splashScreenThemeResId, ActivityInfo activityInfo) {
return splashScreenThemeResId != 0
? splashScreenThemeResId
: activityInfo.getThemeResource() != 0 ? activityInfo.getThemeResource()
: com.android.internal.R.style.Theme_DeviceDefault_DayNight;
}
+
+ void setSysuiProxy(StartingSurface.SysuiProxy sysuiProxy) {
+ mSysuiProxy = sysuiProxy;
+ }
+
/**
* Called when a task need a splash screen starting window.
*
@@ -168,7 +174,7 @@
final int displayId = taskInfo.displayId;
final int taskId = taskInfo.taskId;
- Context context = mContext;
+
// replace with the default theme if the application didn't set
final int theme = getSplashScreenTheme(windowInfo.splashScreenThemeResId, activityInfo);
if (DEBUG_SPLASH_SCREEN) {
@@ -176,12 +182,16 @@
+ " theme=" + Integer.toHexString(theme) + " task=" + taskInfo.taskId
+ " suggestType=" + suggestType);
}
-
final Display display = getDisplay(displayId);
if (display == null) {
// Can't show splash screen on requested display, so skip showing at all.
return;
}
+ Context context = displayId == DEFAULT_DISPLAY
+ ? mContext : mContext.createDisplayContext(display);
+ if (context == null) {
+ return;
+ }
if (theme != context.getThemeResId()) {
try {
context = context.createPackageContextAsUser(activityInfo.packageName,
@@ -292,7 +302,8 @@
// Record whether create splash screen view success, notify to current thread after
// create splash screen view finished.
final SplashScreenViewSupplier viewSupplier = new SplashScreenViewSupplier();
- final FrameLayout rootLayout = new FrameLayout(context);
+ final FrameLayout rootLayout = new FrameLayout(
+ mSplashscreenContentDrawer.createViewContextWrapper(context));
rootLayout.setPadding(0, 0, 0, 0);
rootLayout.setFitsSystemWindows(false);
final Runnable setViewSynchronized = () -> {
@@ -317,8 +328,11 @@
}
Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
};
+ if (mSysuiProxy != null) {
+ mSysuiProxy.requestTopUi(true, TAG);
+ }
mSplashscreenContentDrawer.createContentView(context, suggestType, activityInfo, taskId,
- viewSupplier::setView);
+ viewSupplier::setView, viewSupplier::setUiThreadInitTask);
try {
if (addWindow(taskId, appToken, rootLayout, display, params, suggestType)) {
// We use the splash screen worker thread to create SplashScreenView while adding
@@ -353,6 +367,7 @@
private static class SplashScreenViewSupplier implements Supplier<SplashScreenView> {
private SplashScreenView mView;
private boolean mIsViewSet;
+ private Runnable mUiThreadInitTask;
void setView(SplashScreenView view) {
synchronized (this) {
mView = view;
@@ -361,6 +376,12 @@
}
}
+ void setUiThreadInitTask(Runnable initTask) {
+ synchronized (this) {
+ mUiThreadInitTask = initTask;
+ }
+ }
+
@Override
public @Nullable SplashScreenView get() {
synchronized (this) {
@@ -370,6 +391,10 @@
} catch (InterruptedException ignored) {
}
}
+ if (mUiThreadInitTask != null) {
+ mUiThreadInitTask.run();
+ mUiThreadInitTask = null;
+ }
return mView;
}
}
@@ -492,7 +517,7 @@
Slog.v(TAG, reason + "the splash screen. Releasing SurfaceControlViewHost for task:"
+ taskId);
}
- viewHost.getView().post(viewHost::release);
+ SplashScreenView.releaseIconHost(viewHost);
}
protected boolean addWindow(int taskId, IBinder appToken, View view, Display display,
@@ -573,6 +598,9 @@
}
private void removeWindowInner(View decorView, boolean hideView) {
+ if (mSysuiProxy != null) {
+ mSysuiProxy.requestTopUi(false, TAG);
+ }
if (hideView) {
decorView.setVisibility(View.GONE);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
index e84d498..a5c47c4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingWindowController.java
@@ -217,6 +217,11 @@
return color != Color.TRANSPARENT
? color : SplashscreenContentDrawer.getSystemBGColor();
}
+
+ @Override
+ public void setSysuiProxy(SysuiProxy proxy) {
+ mSplashScreenExecutor.execute(() -> mStartingSurfaceDrawer.setSysuiProxy(proxy));
+ }
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
index 7d011e6..cdc0795 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/TaskSnapshotWindow.java
@@ -343,7 +343,7 @@
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
return state.calculateInsets(frame, WindowInsets.Type.systemBars(),
- false /* ignoreVisibility */);
+ false /* ignoreVisibility */).toRect();
}
private void drawSnapshot() {
@@ -364,6 +364,7 @@
// In case window manager leaks us, make sure we don't retain the snapshot.
mSnapshot = null;
+ mSurfaceControl.release();
}
private void drawSizeMatchSnapshot() {
@@ -431,6 +432,7 @@
mTransaction.setBuffer(mSurfaceControl, background);
}
mTransaction.apply();
+ childSurfaceControl.release();
}
/**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
index dffc700..bdcdb63 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/IShellTransitions.aidl
@@ -16,7 +16,7 @@
package com.android.wm.shell.transition;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
/**
@@ -28,10 +28,10 @@
* Registers a remote transition handler.
*/
oneway void registerRemote(in TransitionFilter filter,
- in IRemoteTransition remoteTransition) = 1;
+ in RemoteTransition remoteTransition) = 1;
/**
* Unregisters a remote transition handler.
*/
- oneway void unregisterRemote(in IRemoteTransition remoteTransition) = 2;
+ oneway void unregisterRemote(in RemoteTransition remoteTransition) = 2;
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
index 6bd8053..3be896e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/OneShotRemoteHandler.java
@@ -24,6 +24,7 @@
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
@@ -43,10 +44,10 @@
private IBinder mTransition = null;
/** The remote to delegate animation to */
- private final IRemoteTransition mRemote;
+ private final RemoteTransition mRemote;
public OneShotRemoteHandler(@NonNull ShellExecutor mainExecutor,
- @NonNull IRemoteTransition remote) {
+ @NonNull RemoteTransition remote) {
mMainExecutor = mainExecutor;
mRemote = remote;
}
@@ -88,7 +89,7 @@
if (mRemote.asBinder() != null) {
mRemote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
}
- mRemote.startAnimation(transition, info, startTransaction, cb);
+ mRemote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
if (mRemote.asBinder() != null) {
@@ -115,7 +116,7 @@
}
};
try {
- mRemote.mergeAnimation(transition, info, t, mergeTarget, cb);
+ mRemote.getRemoteTransition().mergeAnimation(transition, info, t, mergeTarget, cb);
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error merging remote transition.", e);
}
@@ -125,8 +126,9 @@
@Nullable
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@Nullable TransitionRequestInfo request) {
- IRemoteTransition remote = request.getRemoteTransition();
- if (remote != mRemote) return null;
+ RemoteTransition remote = request.getRemoteTransition();
+ IRemoteTransition iRemote = remote != null ? remote.getRemoteTransition() : null;
+ if (iRemote != mRemote.getRemoteTransition()) return null;
mTransition = transition;
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "RemoteTransition directly requested"
+ " for %s: %s", transition, remote);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
index bda884c..ac612a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/RemoteTransitionHandler.java
@@ -27,6 +27,7 @@
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -50,10 +51,10 @@
private final ShellExecutor mMainExecutor;
/** Includes remotes explicitly requested by, eg, ActivityOptions */
- private final ArrayMap<IBinder, IRemoteTransition> mRequestedRemotes = new ArrayMap<>();
+ private final ArrayMap<IBinder, RemoteTransition> mRequestedRemotes = new ArrayMap<>();
/** Ordered by specificity. Last filters will be checked first */
- private final ArrayList<Pair<TransitionFilter, IRemoteTransition>> mFilters =
+ private final ArrayList<Pair<TransitionFilter, RemoteTransition>> mFilters =
new ArrayList<>();
private final ArrayMap<IBinder, RemoteDeathHandler> mDeathHandlers = new ArrayMap<>();
@@ -62,19 +63,12 @@
mMainExecutor = mainExecutor;
}
- void addFiltered(TransitionFilter filter, IRemoteTransition remote) {
- try {
- RemoteDeathHandler handler = new RemoteDeathHandler(remote.asBinder());
- remote.asBinder().linkToDeath(handler, 0 /* flags */);
- mDeathHandlers.put(remote.asBinder(), handler);
- } catch (RemoteException e) {
- Slog.e(TAG, "Failed to link to death");
- return;
- }
+ void addFiltered(TransitionFilter filter, RemoteTransition remote) {
+ handleDeath(remote.asBinder(), null /* finishCallback */);
mFilters.add(new Pair<>(filter, remote));
}
- void removeFiltered(IRemoteTransition remote) {
+ void removeFiltered(RemoteTransition remote) {
boolean removed = false;
for (int i = mFilters.size() - 1; i >= 0; --i) {
if (mFilters.get(i).second == remote) {
@@ -83,8 +77,7 @@
}
}
if (removed) {
- RemoteDeathHandler handler = mDeathHandlers.remove(remote.asBinder());
- remote.asBinder().unlinkToDeath(handler, 0 /* flags */);
+ unhandleDeath(remote.asBinder(), null /* finishCallback */);
}
}
@@ -98,7 +91,7 @@
@NonNull SurfaceControl.Transaction startTransaction,
@NonNull SurfaceControl.Transaction finishTransaction,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- IRemoteTransition pendingRemote = mRequestedRemotes.get(transition);
+ RemoteTransition pendingRemote = mRequestedRemotes.get(transition);
if (pendingRemote == null) {
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "Transition %s doesn't have "
+ "explicit remote, search filters for match for %s", transition, info);
@@ -120,21 +113,12 @@
if (pendingRemote == null) return false;
- final IRemoteTransition remote = pendingRemote;
- final IBinder.DeathRecipient remoteDied = () -> {
- Log.e(Transitions.TAG, "Remote transition died, finishing");
- mMainExecutor.execute(() -> {
- mRequestedRemotes.remove(transition);
- finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */);
- });
- };
+ final RemoteTransition remote = pendingRemote;
IRemoteTransitionFinishedCallback cb = new IRemoteTransitionFinishedCallback.Stub() {
@Override
public void onTransitionFinished(WindowContainerTransaction wct,
SurfaceControl.Transaction sct) {
- if (remote.asBinder() != null) {
- remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
- }
+ unhandleDeath(remote.asBinder(), finishCallback);
mMainExecutor.execute(() -> {
if (sct != null) {
finishTransaction.merge(sct);
@@ -145,15 +129,11 @@
}
};
try {
- if (remote.asBinder() != null) {
- remote.asBinder().linkToDeath(remoteDied, 0 /* flags */);
- }
- remote.startAnimation(transition, info, startTransaction, cb);
+ handleDeath(remote.asBinder(), finishCallback);
+ remote.getRemoteTransition().startAnimation(transition, info, startTransaction, cb);
} catch (RemoteException e) {
Log.e(Transitions.TAG, "Error running remote transition.", e);
- if (remote.asBinder() != null) {
- remote.asBinder().unlinkToDeath(remoteDied, 0 /* flags */);
- }
+ unhandleDeath(remote.asBinder(), finishCallback);
mRequestedRemotes.remove(transition);
mMainExecutor.execute(
() -> finishCallback.onTransitionFinished(null /* wct */, null /* wctCB */));
@@ -165,7 +145,7 @@
public void mergeAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
@NonNull SurfaceControl.Transaction t, @NonNull IBinder mergeTarget,
@NonNull Transitions.TransitionFinishCallback finishCallback) {
- final IRemoteTransition remote = mRequestedRemotes.get(mergeTarget);
+ final IRemoteTransition remote = mRequestedRemotes.get(mergeTarget).getRemoteTransition();
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, " Attempt merge %s into %s",
transition, remote);
if (remote == null) return;
@@ -196,7 +176,7 @@
@Nullable
public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
@Nullable TransitionRequestInfo request) {
- IRemoteTransition remote = request.getRemoteTransition();
+ RemoteTransition remote = request.getRemoteTransition();
if (remote == null) return null;
mRequestedRemotes.put(transition, remote);
ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TRANSITIONS, "RemoteTransition directly requested"
@@ -204,14 +184,70 @@
return new WindowContainerTransaction();
}
+ private void handleDeath(@NonNull IBinder remote,
+ @Nullable Transitions.TransitionFinishCallback finishCallback) {
+ synchronized (mDeathHandlers) {
+ RemoteDeathHandler deathHandler = mDeathHandlers.get(remote);
+ if (deathHandler == null) {
+ deathHandler = new RemoteDeathHandler(remote);
+ try {
+ remote.linkToDeath(deathHandler, 0 /* flags */);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to link to death");
+ return;
+ }
+ mDeathHandlers.put(remote, deathHandler);
+ }
+ deathHandler.addUser(finishCallback);
+ }
+ }
+
+ private void unhandleDeath(@NonNull IBinder remote,
+ @Nullable Transitions.TransitionFinishCallback finishCallback) {
+ synchronized (mDeathHandlers) {
+ RemoteDeathHandler deathHandler = mDeathHandlers.get(remote);
+ if (deathHandler == null) return;
+ deathHandler.removeUser(finishCallback);
+ if (deathHandler.getUserCount() == 0) {
+ if (!deathHandler.mPendingFinishCallbacks.isEmpty()) {
+ throw new IllegalStateException("Unhandling death for binder that still has"
+ + " pending finishCallback(s).");
+ }
+ remote.unlinkToDeath(deathHandler, 0 /* flags */);
+ mDeathHandlers.remove(remote);
+ }
+ }
+ }
+
/** NOTE: binder deaths can alter the filter order */
private class RemoteDeathHandler implements IBinder.DeathRecipient {
private final IBinder mRemote;
+ private final ArrayList<Transitions.TransitionFinishCallback> mPendingFinishCallbacks =
+ new ArrayList<>();
+ private int mUsers = 0;
RemoteDeathHandler(IBinder remote) {
mRemote = remote;
}
+ void addUser(@Nullable Transitions.TransitionFinishCallback finishCallback) {
+ if (finishCallback != null) {
+ mPendingFinishCallbacks.add(finishCallback);
+ }
+ ++mUsers;
+ }
+
+ void removeUser(@Nullable Transitions.TransitionFinishCallback finishCallback) {
+ if (finishCallback != null) {
+ mPendingFinishCallbacks.remove(finishCallback);
+ }
+ --mUsers;
+ }
+
+ int getUserCount() {
+ return mUsers;
+ }
+
@Override
@BinderThread
public void binderDied() {
@@ -221,6 +257,16 @@
mFilters.remove(i);
}
}
+ for (int i = mRequestedRemotes.size() - 1; i >= 0; --i) {
+ if (mRemote.equals(mRequestedRemotes.valueAt(i).asBinder())) {
+ mRequestedRemotes.removeAt(i);
+ }
+ }
+ for (int i = mPendingFinishCallbacks.size() - 1; i >= 0; --i) {
+ mPendingFinishCallbacks.get(i).onTransitionFinished(
+ null /* wct */, null /* wctCB */);
+ }
+ mPendingFinishCallbacks.clear();
});
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
index bc42c6e..802d25f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/ShellTransitions.java
@@ -17,7 +17,7 @@
package com.android.wm.shell.transition;
import android.annotation.NonNull;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import com.android.wm.shell.common.annotations.ExternalThread;
@@ -39,10 +39,10 @@
* Registers a remote transition.
*/
void registerRemote(@NonNull TransitionFilter filter,
- @NonNull IRemoteTransition remoteTransition);
+ @NonNull RemoteTransition remoteTransition);
/**
* Unregisters a remote transition.
*/
- void unregisterRemote(@NonNull IRemoteTransition remoteTransition);
+ void unregisterRemote(@NonNull RemoteTransition remoteTransition);
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
index 8d21ce2..2720157 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java
@@ -40,8 +40,8 @@
import android.util.Log;
import android.view.SurfaceControl;
import android.view.WindowManager;
-import android.window.IRemoteTransition;
import android.window.ITransitionPlayer;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -176,13 +176,13 @@
return new ShellTransitions() {
@Override
public void registerRemote(@androidx.annotation.NonNull TransitionFilter filter,
- @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+ @androidx.annotation.NonNull RemoteTransition remoteTransition) {
// Do nothing
}
@Override
public void unregisterRemote(
- @androidx.annotation.NonNull IRemoteTransition remoteTransition) {
+ @androidx.annotation.NonNull RemoteTransition remoteTransition) {
// Do nothing
}
};
@@ -218,12 +218,12 @@
/** Register a remote transition to be used when `filter` matches an incoming transition */
public void registerRemote(@NonNull TransitionFilter filter,
- @NonNull IRemoteTransition remoteTransition) {
+ @NonNull RemoteTransition remoteTransition) {
mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
}
/** Unregisters a remote transition and all associated filters */
- public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+ public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
mRemoteTransitionHandler.removeFiltered(remoteTransition);
}
@@ -704,14 +704,14 @@
@Override
public void registerRemote(@NonNull TransitionFilter filter,
- @NonNull IRemoteTransition remoteTransition) {
+ @NonNull RemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
});
}
@Override
- public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+ public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
mMainExecutor.execute(() -> {
mRemoteTransitionHandler.removeFiltered(remoteTransition);
});
@@ -738,7 +738,7 @@
@Override
public void registerRemote(@NonNull TransitionFilter filter,
- @NonNull IRemoteTransition remoteTransition) {
+ @NonNull RemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mTransitions, "registerRemote",
(transitions) -> {
transitions.mRemoteTransitionHandler.addFiltered(filter, remoteTransition);
@@ -746,7 +746,7 @@
}
@Override
- public void unregisterRemote(@NonNull IRemoteTransition remoteTransition) {
+ public void unregisterRemote(@NonNull RemoteTransition remoteTransition) {
executeRemoteCallWithTaskPermission(mTransitions, "unregisterRemote",
(transitions) -> {
transitions.mRemoteTransitionHandler.removeFiltered(remoteTransition);
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
index d4b4e5d..1529f5b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/helpers/PipAppHelper.kt
@@ -17,11 +17,14 @@
package com.android.wm.shell.flicker.helpers
import android.app.Instrumentation
+import android.graphics.Rect
import android.media.session.MediaController
import android.media.session.MediaSessionManager
import android.os.SystemClock
import androidx.test.uiautomator.By
import androidx.test.uiautomator.BySelector
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.helpers.FIND_TIMEOUT
import com.android.server.wm.flicker.helpers.SYSTEMUI_PACKAGE
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.pip.tv.closeTvPipWindow
@@ -85,6 +88,10 @@
// Wait on WMHelper or simply wait for 3 seconds
wmHelper?.waitFor("hasPipWindow") { it.wmState.hasPipWindow() } ?: SystemClock.sleep(3_000)
+ // when entering pip, the dismiss button is visible at the start. to ensure the pip
+ // animation is complete, wait until the pip dismiss button is no longer visible.
+ // b/176822698: dismiss-only state will be removed in the future
+ uiDevice.wait(Until.gone(By.res(SYSTEMUI_PACKAGE, "dismiss")), FIND_TIMEOUT)
}
fun clickStartMediaSessionButton() {
@@ -113,25 +120,25 @@
}
}
+ private fun getWindowRect(wmHelper: WindowManagerStateHelper): Rect {
+ val windowRegion = wmHelper.getWindowRegion(component)
+ require(!windowRegion.isEmpty) {
+ "Unable to find a PIP window in the current state"
+ }
+ return windowRegion.bounds
+ }
+
/**
* Expands the pip window and dismisses it by clicking on the X button.
- *
- * Note, currently the View coordinates reported by the accessibility are relative to
- * the window, so the correct coordinates need to be calculated
- *
- * For example, in a PIP window located at Rect(508, 1444 - 1036, 1741), the
- * dismiss button coordinates are shown as Rect(650, 0 - 782, 132), with center in
- * Point(716, 66), instead of Point(970, 1403)
- *
- * See b/179337864
*/
fun closePipWindow(wmHelper: WindowManagerStateHelper) {
if (isTelevision) {
uiDevice.closeTvPipWindow()
} else {
- expandPipWindow(wmHelper)
+ val windowRect = getWindowRect(wmHelper)
+ uiDevice.click(windowRect.centerX(), windowRect.centerY())
val exitPipObject = uiDevice.findObject(By.res(SYSTEMUI_PACKAGE, "dismiss"))
- requireNotNull(exitPipObject) { "PIP window dismiss button not found" }
+ ?: error("PIP window dismiss button not found")
val dismissButtonBounds = exitPipObject.visibleBounds
uiDevice.click(dismissButtonBounds.centerX(), dismissButtonBounds.centerY())
}
@@ -142,32 +149,29 @@
}
/**
- * Click once on the PIP window to expand it
+ * Close the pip window by pressing the expand button
*/
- fun expandPipWindow(wmHelper: WindowManagerStateHelper) {
- val windowRegion = wmHelper.getWindowRegion(component)
- require(!windowRegion.isEmpty) {
- "Unable to find a PIP window in the current state"
- }
- val windowRect = windowRegion.bounds
+ fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
+ val windowRect = getWindowRect(wmHelper)
uiDevice.click(windowRect.centerX(), windowRect.centerY())
- // Ensure WindowManagerService wait until all animations have completed
+ // search and interact with the expand button
+ val expandSelector = By.res(SYSTEMUI_PACKAGE, "expand_button")
+ uiDevice.wait(Until.hasObject(expandSelector), FIND_TIMEOUT)
+ val expandPipObject = uiDevice.findObject(expandSelector)
+ ?: error("PIP window expand button not found")
+ val expandButtonBounds = expandPipObject.visibleBounds
+ uiDevice.click(expandButtonBounds.centerX(), expandButtonBounds.centerY())
+ wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
wmHelper.waitForAppTransitionIdle()
- mInstrumentation.uiAutomation.syncInputTransactions()
}
/**
- * Double click on the PIP window to reopen to app
+ * Double click on the PIP window to expand it
*/
- fun expandPipWindowToApp(wmHelper: WindowManagerStateHelper) {
- val windowRegion = wmHelper.getWindowRegion(component)
- require(!windowRegion.isEmpty) {
- "Unable to find a PIP window in the current state"
- }
- val windowRect = windowRegion.bounds
+ fun doubleClickPipWindow(wmHelper: WindowManagerStateHelper) {
+ val windowRect = getWindowRect(wmHelper)
uiDevice.click(windowRect.centerX(), windowRect.centerY())
uiDevice.click(windowRect.centerX(), windowRect.centerY())
- wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
wmHelper.waitForAppTransitionIdle()
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
index af99fc4..ff34364 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ExitPrimarySplitScreenShowSecondaryFullscreen.kt
@@ -17,7 +17,6 @@
package com.android.wm.shell.flicker.legacysplitscreen
import android.content.ComponentName
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.Surface
import androidx.test.filters.FlakyTest
@@ -113,7 +112,7 @@
override fun visibleLayersShownMoreThanOneConsecutiveEntry() =
super.visibleLayersShownMoreThanOneConsecutiveEntry()
- @Postsubmit
+ @Presubmit
@Test
override fun visibleWindowsShownMoreThanOneConsecutiveEntry() =
super.visibleWindowsShownMoreThanOneConsecutiveEntry()
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
index 7b4b71b..5fb6f1f 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/LegacySplitScreenToLauncher.kt
@@ -104,7 +104,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
index ec0c73a..a7ac6a7 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/OpenAppToLegacySplitScreen.kt
@@ -28,7 +28,6 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.launchSplitScreen
-import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerIsVisible
import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.appPairsDividerBecomesVisible
@@ -77,7 +76,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
index d7f71a8..cd15051 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/legacysplitscreen/ResizeLegacySplitScreen.kt
@@ -129,7 +129,7 @@
fun statusBarLayerIsVisible() = testSpec.statusBarLayerIsVisible()
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.endRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Test
fun navBarLayerRotatesAndScales() =
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
deleted file mode 100644
index 39e89fb..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterExitPipTest.kt
+++ /dev/null
@@ -1,120 +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.wm.shell.flicker.pip
-
-import android.platform.test.annotations.Postsubmit
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-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.annotation.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch and exit.
- * To run this test: `atest WMShellFlickerTests:EnterExitPipTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class EnterExitPipTest(
- testSpec: FlickerTestParameter
-) : PipTransition(testSpec) {
- private val testApp = FixedAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = buildTransition(eachRun = true) {
- setup {
- eachRun {
- testApp.launchViaIntent(wmHelper)
- }
- }
- transitions {
- // This will bring PipApp to fullscreen
- pipApp.launchViaIntent(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun pipAppRemainInsideVisibleBounds() {
- testSpec.assertWm {
- coversAtMost(displayBounds, pipApp.component)
- }
- }
-
- @Postsubmit
- @Test
- fun showBothAppWindowsThenHidePip() {
- testSpec.assertWm {
- // when the activity is STOPPING, sometimes it becomes invisible in an entry before
- // the window, sometimes in the same entry. This occurs because we log 1x per frame
- // thus we ignore activity here
- isAppWindowVisible(testApp.component, ignoreActivity = true)
- .isAppWindowOnTop(pipApp.component)
- .then()
- .isAppWindowInvisible(testApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun showBothAppLayersThenHidePip() {
- testSpec.assertLayers {
- isVisible(testApp.component)
- .isVisible(pipApp.component)
- .then()
- .isInvisible(testApp.component)
- }
- }
-
- @Presubmit
- @Test
- fun testAppCoversFullScreenWithPipOnDisplay() {
- testSpec.assertLayersStart {
- visibleRegion(testApp.component).coversExactly(displayBounds)
- visibleRegion(pipApp.component).coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun pipAppCoversFullScreen() {
- testSpec.assertLayersEnd {
- visibleRegion(pipApp.component).coversExactly(displayBounds)
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
index 0f0a4ab..046972d 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipTest.kt
@@ -23,8 +23,10 @@
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.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toLayerName
import org.junit.FixMethodOrder
import org.junit.Test
import org.junit.runner.RunWith
@@ -32,8 +34,21 @@
import org.junit.runners.Parameterized
/**
- * Test Pip launch.
+ * Test entering pip from an app by interacting with the app UI
+ *
* To run this test: `atest WMShellFlickerTests:EnterPipTest`
+ *
+ * Actions:
+ * Launch an app in full screen
+ * Press an "enter pip" button to put [pipApp] in pip mode
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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,14 +56,19 @@
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
class EnterPipTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true, stringExtras = emptyMap()) {
transitions {
pipApp.clickEnterPipButton(wmHelper)
- pipApp.expandPipWindow(wmHelper)
}
}
+ /**
+ * Checks [pipApp] window remains visible throughout the animation
+ */
@Presubmit
@Test
fun pipAppWindowAlwaysVisible() {
@@ -57,6 +77,9 @@
}
}
+ /**
+ * Checks [pipApp] layer remains visible throughout the animation
+ */
@Presubmit
@Test
fun pipAppLayerAlwaysVisible() {
@@ -65,19 +88,89 @@
}
}
- @FlakyTest
+ /**
+ * Checks that the pip app window remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
@Test
- fun pipWindowBecomesVisible() {
+ fun pipWindowRemainInsideVisibleBounds() {
testSpec.assertWm {
- invoke("pipWindowIsNotVisible") {
- verify("Has no pip window").that(it.wmState.hasPipWindow()).isTrue()
- }.then().invoke("pipWindowIsVisible") {
- verify("Has pip window").that(it.wmState.hasPipWindow()).isTrue()
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the pip app layer remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ fun pipLayerRemainInsideVisibleBounds() {
+ testSpec.assertLayers {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] always reduces during the animation
+ */
+ @Presubmit
+ @Test
+ fun pipLayerReduces() {
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.coversAtMost(previous.visibleRegion.region)
}
}
}
+ /**
+ * Checks that [pipApp] window becomes pinned
+ */
+ @Presubmit
+ @Test
+ fun pipWindowBecomesPinned() {
+ testSpec.assertWm {
+ invoke("pipWindowIsNotPinned") { it.isNotPinned(pipApp.component) }
+ .then()
+ .invoke("pipWindowIsPinned") { it.isPinned(pipApp.component) }
+ }
+ }
+
+ /**
+ * Checks [LAUNCHER_COMPONENT] layer remains visible throughout the animation
+ */
+ @Presubmit
+ @Test
+ fun launcherLayerBecomesVisible() {
+ testSpec.assertLayers {
+ isInvisible(LAUNCHER_COMPONENT)
+ .then()
+ .isVisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks the focus doesn't change during the animation
+ */
+ @FlakyTest
+ @Test
+ fun focusDoesNotChange() {
+ testSpec.assertEventLog {
+ this.focusDoesNotChange()
+ }
+ }
+
companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
@Parameterized.Parameters(name = "{0}")
@JvmStatic
fun getParams(): List<FlickerTestParameter> {
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
index 67ad322..097ccb8 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/EnterPipToOtherOrientationTest.kt
@@ -25,7 +25,11 @@
import com.android.server.wm.flicker.FlickerTestParameterFactory
import com.android.server.wm.flicker.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.entireScreenCovered
import com.android.server.wm.flicker.helpers.WindowUtils
+import com.android.server.wm.flicker.navBarLayerRotatesAndScales
+import com.android.server.wm.flicker.statusBarLayerRotatesScales
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_LANDSCAPE
import com.android.wm.shell.flicker.pip.PipTransition.BroadcastActionTrigger.Companion.ORIENTATION_PORTRAIT
@@ -38,8 +42,22 @@
import org.junit.runners.Parameterized
/**
- * Test Pip with orientation changes.
- * To run this test: `atest WMShellFlickerTests:PipOrientationTest`
+ * Test entering pip while changing orientation (from app in landscape to pip window in portrait)
+ *
+ * To run this test: `atest EnterPipToOtherOrientationTest:EnterPipToOtherOrientationTest`
+ *
+ * Actions:
+ * Launch [testApp] on a fixed portrait orientation
+ * Launch [pipApp] on a fixed landscape orientation
+ * Broadcast action [ACTION_ENTER_PIP] to enter pip mode
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
@@ -53,6 +71,9 @@
private val startingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_90)
private val endingBounds = WindowUtils.getDisplayBounds(Surface.ROTATION_0)
+ /**
+ * Defines the transition used to run the test
+ */
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = { configuration ->
setupAndTeardown(this, configuration)
@@ -79,21 +100,41 @@
broadcastActionTrigger.doAction(ACTION_ENTER_PIP)
wmHelper.waitFor { it.wmState.hasPipWindow() }
wmHelper.waitForAppTransitionIdle()
+ // during rotation the status bar becomes invisible and reappears at the end
+ wmHelper.waitForNavBarStatusBarVisible()
}
}
+ /**
+ * Checks that the [WindowManagerStateHelper.NAV_BAR_COMPONENT] has the correct position at
+ * the start and end of the transition
+ */
@FlakyTest
@Test
- override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+ override fun navBarLayerRotatesAndScales() =
+ testSpec.navBarLayerRotatesAndScales(Surface.ROTATION_90, Surface.ROTATION_0)
- @FlakyTest
+ /**
+ * Checks that the [WindowManagerStateHelper.STATUS_BAR_COMPONENT] has the correct position at
+ * the start and end of the transition
+ */
+ @Presubmit
@Test
- override fun statusBarLayerRotatesScales() = super.statusBarLayerRotatesScales()
+ override fun statusBarLayerRotatesScales() =
+ testSpec.statusBarLayerRotatesScales(Surface.ROTATION_90, Surface.ROTATION_0)
- @FlakyTest
+ /**
+ * Checks that all parts of the screen are covered at the start and end of the transition
+ *
+ * TODO b/197726599 Prevents all states from being checked
+ */
+ @Presubmit
@Test
- override fun entireScreenCovered() = super.entireScreenCovered()
+ override fun entireScreenCovered() = testSpec.entireScreenCovered(allStates = false)
+ /**
+ * Checks [pipApp] window remains visible and on top throughout the transition
+ */
@Presubmit
@Test
fun pipAppWindowIsAlwaysOnTop() {
@@ -102,40 +143,84 @@
}
}
+ /**
+ * Checks that [testApp] window is not visible at the start
+ */
@Presubmit
@Test
- fun pipAppHidesTestApp() {
+ fun testAppWindowInvisibleOnStart() {
testSpec.assertWmStart {
isInvisible(testApp.component)
}
}
+ /**
+ * Checks that [testApp] window is visible at the end
+ */
@Presubmit
@Test
- fun testAppWindowIsVisible() {
+ fun testAppWindowVisibleOnEnd() {
testSpec.assertWmEnd {
isVisible(testApp.component)
}
}
+ /**
+ * Checks that [testApp] layer is not visible at the start
+ */
@Presubmit
@Test
- fun pipAppLayerHidesTestApp() {
+ fun testAppLayerInvisibleOnStart() {
testSpec.assertLayersStart {
- visibleRegion(pipApp.component).coversExactly(startingBounds)
isInvisible(testApp.component)
}
}
+ /**
+ * Checks that [testApp] layer is visible at the end
+ */
@Presubmit
@Test
- fun testAppLayerCoversFullScreen() {
+ fun testAppLayerVisibleOnEnd() {
testSpec.assertLayersEnd {
- visibleRegion(testApp.component).coversExactly(endingBounds)
+ isVisible(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] covers the full display area at the start of
+ * the transition
+ */
+ @Presubmit
+ @Test
+ fun pipAppLayerCoversFullScreenOnStart() {
+ testSpec.assertLayersStart {
+ visibleRegion(pipApp.component).coversExactly(startingBounds)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [testApp] plus the visible region of [pipApp]
+ * cover the full display area at the end of the transition
+ */
+ @Presubmit
+ @Test
+ fun testAppPlusPipLayerCoversFullScreenOnEnd() {
+ testSpec.assertLayersEnd {
+ val pipRegion = visibleRegion(pipApp.component).region
+ visibleRegion(testApp.component)
+ .plus(pipRegion)
+ .coversExactly(endingBounds)
}
}
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/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
new file mode 100644
index 0000000..faaaecb
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipToAppTransition.kt
@@ -0,0 +1,131 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Presubmit
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.traces.parser.toLayerName
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import org.junit.Test
+
+/**
+ * Base class for pip expand tests
+ */
+abstract class ExitPipToAppTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ protected val testApp = FixedAppHelper(instrumentation)
+
+ /**
+ * Checks that the pip app window remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ open fun pipAppWindowRemainInsideVisibleBounds() {
+ testSpec.assertWm {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the pip app layer remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ open fun pipAppLayerRemainInsideVisibleBounds() {
+ testSpec.assertLayers {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks both app windows are visible at the start of the transition (with [pipApp] on top).
+ * Then, during the transition, [testApp] becomes invisible and [pipApp] remains visible
+ */
+ @Presubmit
+ @Test
+ open fun showBothAppWindowsThenHidePip() {
+ testSpec.assertWm {
+ // when the activity is STOPPING, sometimes it becomes invisible in an entry before
+ // the window, sometimes in the same entry. This occurs because we log 1x per frame
+ // thus we ignore activity here
+ isAppWindowVisible(testApp.component, ignoreActivity = true)
+ .isAppWindowOnTop(pipApp.component)
+ .then()
+ .isAppWindowInvisible(testApp.component)
+ .isAppWindowVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks both app layers are visible at the start of the transition. Then, during the
+ * transition, [testApp] becomes invisible and [pipApp] remains visible
+ */
+ @Presubmit
+ @Test
+ open fun showBothAppLayersThenHidePip() {
+ testSpec.assertLayers {
+ isVisible(testApp.component)
+ .isVisible(pipApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ .isVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [testApp] plus the visible region of [pipApp]
+ * cover the full display area at the start of the transition
+ */
+ @Presubmit
+ @Test
+ open fun testPlusPipAppsCoverFullScreenAtStart() {
+ testSpec.assertLayersStart {
+ val pipRegion = visibleRegion(pipApp.component).region
+ visibleRegion(testApp.component)
+ .plus(pipRegion)
+ .coversExactly(displayBounds)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] covers the full display area at the end of
+ * the transition
+ */
+ @Presubmit
+ @Test
+ open fun pipAppCoversFullScreenAtEnd() {
+ testSpec.assertLayersEnd {
+ visibleRegion(pipApp.component).coversExactly(displayBounds)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] always expands during the animation
+ */
+ @Presubmit
+ @Test
+ open fun pipLayerExpands() {
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
+ }
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
similarity index 67%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
index 28b1028..3414031 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipTransition.kt
@@ -20,15 +20,16 @@
import android.view.Surface
import androidx.test.filters.FlakyTest
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.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.startRotation
import org.junit.Test
-import org.junit.runners.Parameterized
-abstract class PipCloseTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+/**
+ * Base class for exiting pip (closing pip window) without returning to the app
+ */
+abstract class ExitPipTransition(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = true) { configuration ->
setup {
@@ -43,16 +44,28 @@
}
}
+ /**
+ * Checks that [pipApp] window is pinned and visible at the start and then becomes
+ * unpinned and invisible at the same moment, and remains unpinned and invisible
+ * until the end of the transition
+ */
@Presubmit
@Test
open fun pipWindowBecomesInvisible() {
testSpec.assertWm {
- this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
- .then()
- .isAppWindowInvisible(pipApp.component)
+ this.invoke("hasPipWindow") {
+ it.isPinned(pipApp.component).isVisible(pipApp.component)
+ }.then().invoke("!hasPipWindow") {
+ it.isNotPinned(pipApp.component).isInvisible(pipApp.component)
+ }
}
}
+ /**
+ * Checks that [pipApp] and [LAUNCHER_COMPONENT] layers are visible at the start
+ * of the transition. Then [pipApp] layer becomes invisible, and remains invisible
+ * until the end of the transition
+ */
@Presubmit
@Test
open fun pipLayerBecomesInvisible() {
@@ -65,6 +78,10 @@
}
}
+ /**
+ * Checks that the focus changes between the [pipApp] window and the launcher when
+ * closing the pip window
+ */
@FlakyTest(bugId = 151179149)
@Test
open fun focusChanges() {
@@ -72,14 +89,4 @@
this.focusChanges(pipApp.launcherName, "NexusLauncherActivity")
}
}
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
- }
- }
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
new file mode 100644
index 0000000..fa100b5
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaExpandButtonClickTest.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+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.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toWindowName
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window back to full screen via the expand button
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipViaExpandButtonClickTest`
+ *
+ * Actions:
+ * Launch an app in pip mode [pipApp],
+ * Launch another full screen mode [testApp]
+ * Expand [pipApp] app to full screen by clicking on the pip window and
+ * then on the expand button
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipViaExpandButtonClickTest(
+ testSpec: FlickerTestParameter
+) : ExitPipToAppTransition(testSpec) {
+
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = true) {
+ setup {
+ eachRun {
+ // launch an app behind the pip one
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ // This will bring PipApp to fullscreen
+ pipApp.expandPipWindowToApp(wmHelper)
+ // Wait until the other app is no longer visible
+ wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
new file mode 100644
index 0000000..617ef22
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipViaIntentTest.kt
@@ -0,0 +1,90 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+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.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toWindowName
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window back to full screen via an intent
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipViaIntentTest`
+ *
+ * Actions:
+ * Launch an app in pip mode [pipApp],
+ * Launch another full screen mode [testApp]
+ * Expand [pipApp] app to full screen via an intent
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited from [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipViaIntentTest(testSpec: FlickerTestParameter) : ExitPipToAppTransition(testSpec) {
+
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = true) {
+ setup {
+ eachRun {
+ // launch an app behind the pip one
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+ transitions {
+ // This will bring PipApp to fullscreen
+ pipApp.launchViaIntent(wmHelper)
+ // Wait until the other app is no longer visible
+ wmHelper.waitForSurfaceAppeared(testApp.component.toWindowName())
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
new file mode 100644
index 0000000..e3d099f
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithDismissButtonTest.kt
@@ -0,0 +1,88 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+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.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test closing a pip window via the dismiss button
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipWithDismissButtonTest`
+ *
+ * Actions:
+ * Launch an app in pip mode [pipApp],
+ * Click on the pip window
+ * Click on dismiss button and wait window disappear
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExitPipWithDismissButtonTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = {
+ super.transition(this, it)
+ transitions {
+ pipApp.closePipWindow(wmHelper)
+ }
+ }
+
+ @Postsubmit
+ @Test
+ override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
+
+ @Postsubmit
+ @Test
+ override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
similarity index 62%
rename from libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
rename to libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
index 356ec94..2cdfc2b 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithSwipeTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExitPipWithSwipeDownTest.kt
@@ -22,6 +22,7 @@
import androidx.test.filters.RequiresDevice
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.annotation.Group3
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.startRotation
@@ -33,24 +34,40 @@
import org.junit.runners.Parameterized
/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipCloseWithSwipe`
+ * Test closing a pip window by swiping it to the bottom-center of the screen
+ *
+ * To run this test: `atest WMShellFlickerTests:ExitPipWithSwipeDownTest`
+ *
+ * Actions:
+ * Launch an app in pip mode [pipApp],
+ * Swipe the pip window to the bottom-center of the screen and wait it disappear
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
@FixMethodOrder(MethodSorters.NAME_ASCENDING)
@Group3
-class PipCloseWithSwipeTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
+class ExitPipWithSwipeDownTest(testSpec: FlickerTestParameter) : ExitPipTransition(testSpec) {
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = {
- super.transition(this, it)
+ get() = { args ->
+ super.transition(this, args)
transitions {
val pipRegion = wmHelper.getWindowRegion(pipApp.component).bounds
val pipCenterX = pipRegion.centerX()
val pipCenterY = pipRegion.centerY()
val displayCenterX = device.displayWidth / 2
- device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 5)
+ device.swipe(pipCenterX, pipCenterY, displayCenterX, device.displayHeight, 10)
+ wmHelper.waitFor("!hasPipWindow") { !it.wmState.hasPipWindow() }
+ wmHelper.waitForWindowSurfaceDisappeared(pipApp.component)
+ wmHelper.waitForAppTransitionIdle()
}
}
@@ -90,4 +107,20 @@
@Presubmit
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 20)
+ }
+ }
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
new file mode 100644
index 0000000..89b2c40
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/ExpandPipOnDoubleClickTest.kt
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+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.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.traces.parser.toLayerName
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test expanding a pip window by double clicking it
+ *
+ * To run this test: `atest WMShellFlickerTests:ExpandPipOnDoubleClickTest`
+ *
+ * Actions:
+ * Launch an app in pip mode [pipApp],
+ * Expand [pipApp] app to its maximum pip size by double clicking on it
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class ExpandPipOnDoubleClickTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = true) {
+ transitions {
+ pipApp.doubleClickPipWindow(wmHelper)
+ }
+ }
+
+ /**
+ * Checks that the pip app window remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ fun pipWindowRemainInsideVisibleBounds() {
+ testSpec.assertWm {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the pip app layer remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ fun pipLayerRemainInsideVisibleBounds() {
+ testSpec.assertLayers {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks [pipApp] window remains visible throughout the animation
+ */
+ @Postsubmit
+ @Test
+ fun pipWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ isAppWindowVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks [pipApp] layer remains visible throughout the animation
+ */
+ @Presubmit
+ @Test
+ fun pipLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ isVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] always expands during the animation
+ */
+ @Presubmit
+ @Test
+ fun pipLayerExpands() {
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ current.visibleRegion.coversAtLeast(previous.visibleRegion.region)
+ }
+ }
+ }
+
+ /**
+ * Checks [pipApp] window remains pinned throughout the animation
+ */
+ @Presubmit
+ @Test
+ fun windowIsAlwaysPinned() {
+ testSpec.assertWm {
+ this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
+ }
+ }
+
+ /**
+ * Checks [pipApp] layer remains visible throughout the animation
+ */
+ @Presubmit
+ @Test
+ fun launcherIsAlwaysVisible() {
+ testSpec.assertLayers {
+ isVisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that the focus doesn't change between windows during the transition
+ */
+ @FlakyTest
+ @Test
+ fun focusDoesNotChange() {
+ testSpec.assertEventLog {
+ this.focusDoesNotChange()
+ }
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
+ repetitions = 5)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
new file mode 100644
index 0000000..0ab857d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipDownShelfHeightChangeTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+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.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.RegionSubject
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (decrease).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipDownShelfHeightChangeTest`
+ *
+ * Actions:
+ * Launch [pipApp] in pip mode
+ * Launch [testApp]
+ * Press home
+ * Check if pip window moves down (visually)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class MovePipDownShelfHeightChangeTest(
+ testSpec: FlickerTestParameter
+) : MovePipShelfHeightTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = false) {
+ teardown {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ }
+ test {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ taplInstrumentation.pressHome()
+ }
+ }
+
+ override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) {
+ current.isHigherOrEqual(previous.region)
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
new file mode 100644
index 0000000..ed04fc9
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipShelfHeightTransition.kt
@@ -0,0 +1,118 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.platform.test.annotations.Presubmit
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.FlickerTestParameter
+import com.android.server.wm.flicker.traces.RegionSubject
+import com.android.server.wm.traces.parser.toLayerName
+import com.android.server.wm.traces.parser.toWindowName
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import org.junit.Test
+
+/**
+ * Base class for pip tests with Launcher shelf height change
+ */
+abstract class MovePipShelfHeightTransition(
+ testSpec: FlickerTestParameter
+) : PipTransition(testSpec) {
+ protected val taplInstrumentation = LauncherInstrumentation()
+ protected val testApp = FixedAppHelper(instrumentation)
+
+ /**
+ * Checks if the window movement direction is valid
+ */
+ protected abstract fun assertRegionMovement(previous: RegionSubject, current: RegionSubject)
+
+ /**
+ * Checks [pipApp] window remains visible throughout the animation
+ */
+ @Presubmit
+ @Test
+ open fun pipWindowIsAlwaysVisible() {
+ testSpec.assertWm {
+ isAppWindowVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks [pipApp] layer remains visible throughout the animation
+ */
+ @Presubmit
+ @Test
+ open fun pipLayerIsAlwaysVisible() {
+ testSpec.assertLayers {
+ isVisible(pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the pip app window remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ open fun pipWindowRemainInsideVisibleBounds() {
+ testSpec.assertWm {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the pip app layer remains inside the display bounds throughout the whole
+ * animation
+ */
+ @Presubmit
+ @Test
+ open fun pipLayerRemainInsideVisibleBounds() {
+ testSpec.assertLayers {
+ coversAtMost(displayBounds, pipApp.component)
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] always moves in the correct direction
+ * during the animation.
+ */
+ @Presubmit
+ @Test
+ open fun pipWindowMoves() {
+ val windowName = pipApp.component.toWindowName()
+ testSpec.assertWm {
+ val pipWindowList = this.windowStates { it.name.contains(windowName) && it.isVisible }
+ pipWindowList.zipWithNext { previous, current ->
+ assertRegionMovement(previous.frame, current.frame)
+ }
+ }
+ }
+
+ /**
+ * Checks that the visible region of [pipApp] always moves up during the animation
+ */
+ @Presubmit
+ @Test
+ open fun pipLayerMoves() {
+ val layerName = pipApp.component.toLayerName()
+ testSpec.assertLayers {
+ val pipLayerList = this.layers { it.name.contains(layerName) && it.isVisible }
+ pipLayerList.zipWithNext { previous, current ->
+ assertRegionMovement(previous.visibleRegion, current.visibleRegion)
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
new file mode 100644
index 0000000..e507edf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/MovePipUpShelfHeightChangeTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.wm.shell.flicker.pip
+
+import android.view.Surface
+import androidx.test.filters.RequiresDevice
+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.annotation.Group3
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.traces.RegionSubject
+import org.junit.FixMethodOrder
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test Pip movement with Launcher shelf height change (increase).
+ *
+ * To run this test: `atest WMShellFlickerTests:MovePipUpShelfHeightChangeTest`
+ *
+ * Actions:
+ * Launch [pipApp] in pip mode
+ * Press home
+ * Launch [testApp]
+ * Check if pip window moves up (visually)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited [PipTransition]
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group3
+class MovePipUpShelfHeightChangeTest(
+ testSpec: FlickerTestParameter
+) : MovePipShelfHeightTransition(testSpec) {
+ /**
+ * Defines the transition used to run the test
+ */
+ override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
+ get() = buildTransition(eachRun = false) {
+ teardown {
+ eachRun {
+ taplInstrumentation.pressHome()
+ }
+ test {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ }
+ }
+
+ override fun assertRegionMovement(previous: RegionSubject, current: RegionSubject) {
+ current.isLowerOrEqual(previous.region)
+ }
+
+ companion object {
+ /**
+ * Creates the test configurations.
+ *
+ * See [FlickerTestParameterFactory.getConfigNonRotationTests] for configuring
+ * repetitions, screen orientation and navigation modes.
+ */
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): List<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
+ supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
+ }
+ }
+}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
deleted file mode 100644
index 1c5d77f..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipCloseWithDismissButtonTest.kt
+++ /dev/null
@@ -1,56 +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.wm.shell.flicker.pip
-
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-import com.android.server.wm.flicker.FlickerParametersRunnerFactory
-import com.android.server.wm.flicker.FlickerTestParameter
-import com.android.server.wm.flicker.annotation.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipCloseWithDismissButton`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipCloseWithDismissButtonTest(testSpec: FlickerTestParameter) : PipCloseTransition(testSpec) {
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = {
- super.transition(this, it)
- transitions {
- pipApp.closePipWindow(wmHelper)
- }
- }
-
- @FlakyTest
- @Test
- override fun pipLayerBecomesInvisible() = super.pipLayerBecomesInvisible()
-
- @FlakyTest
- @Test
- override fun pipWindowBecomesInvisible() = super.pipWindowBecomesInvisible()
-}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
index 050beb3..0861652 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipLegacySplitScreenTest.kt
@@ -27,13 +27,15 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.helpers.launchSplitScreen
import com.android.server.wm.flicker.helpers.wakeUpAndGoToHomeScreen
-import com.android.wm.shell.flicker.helpers.ImeAppHelper
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
import com.android.server.wm.flicker.repetitions
import com.android.server.wm.flicker.rules.RemoveAllTasksButHomeRule.Companion.removeAllTasksButHome
import com.android.wm.shell.flicker.helpers.BaseAppHelper.Companion.isShellTransitionsEnabled
+import com.android.wm.shell.flicker.helpers.FixedAppHelper
+import com.android.wm.shell.flicker.helpers.ImeAppHelper
+import com.android.wm.shell.flicker.helpers.SplitScreenHelper
import com.android.wm.shell.flicker.testapp.Components.PipActivity.EXTRA_ENTER_PIP
import org.junit.Assume.assumeFalse
+import org.junit.Assume.assumeTrue
import org.junit.Before
import org.junit.FixMethodOrder
import org.junit.Test
@@ -56,6 +58,8 @@
@Before
open fun setup() {
+ // Only run legacy split tests when the system is using legacy split screen.
+ assumeTrue(SplitScreenHelper.isUsingLegacySplit())
// Legacy split is having some issue with Shell transition, and will be deprecated soon.
assumeFalse(isShellTransitionsEnabled())
}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
index 45cb152..b105460 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipRotationTest.kt
@@ -32,8 +32,6 @@
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
import com.android.server.wm.flicker.startRotation
import com.android.server.wm.flicker.statusBarLayerRotatesScales
-import com.android.server.wm.traces.common.Region
-import com.android.server.wm.traces.parser.minus
import com.android.wm.shell.flicker.helpers.FixedAppHelper
import org.junit.FixMethodOrder
import org.junit.Test
@@ -43,7 +41,22 @@
/**
* Test Pip Stack in bounds after rotations.
+ *
* To run this test: `atest WMShellFlickerTests:PipRotationTest`
+ *
+ * Actions:
+ * Launch a [pipApp] in pip mode
+ * Launch another app [fixedApp] (appears below pip)
+ * Rotate the screen from [testSpec.config.startRotation] to [testSpec.config.endRotation]
+ * (usually, 0->90 and 90->0)
+ *
+ * Notes:
+ * 1. Some default assertions (e.g., nav bar, status bar and screen covered)
+ * are inherited from [PipTransition]
+ * 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)
@@ -52,8 +65,8 @@
@Group3
class PipRotationTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
private val fixedApp = FixedAppHelper(instrumentation)
- private val startingBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- private val endingBounds = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
+ private val screenBoundsStart = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+ private val screenBoundsEnd = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
get() = buildTransition(eachRun = false) { configuration ->
@@ -68,55 +81,108 @@
transitions {
setRotation(configuration.endRotation)
}
- teardown {
- eachRun {
- setRotation(Surface.ROTATION_0)
- }
- }
}
+ /**
+ * Checks that all parts of the screen are covered at the start and end of the transition
+ */
@Presubmit
@Test
- override fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
- testSpec.config.endRotation, allStates = false)
+ override fun entireScreenCovered() = testSpec.entireScreenCovered()
+ /**
+ * Checks the position of the navigation bar at the start and end of the transition
+ */
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() =
testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation,
testSpec.config.endRotation)
+ /**
+ * Checks the position of the status bar at the start and end of the transition
+ */
@Presubmit
@Test
override fun statusBarLayerRotatesScales() =
testSpec.statusBarLayerRotatesScales(testSpec.config.startRotation,
testSpec.config.endRotation)
+ /**
+ * Checks that [fixedApp] layer is within [screenBoundsStart] at the start of the transition
+ */
@Presubmit
@Test
fun appLayerRotates_StartingBounds() {
testSpec.assertLayersStart {
- val pipRegion = visibleRegion(pipApp.component).region
- val expectedWithoutPip = Region(startingBounds.bounds.left, startingBounds.bounds.top,
- startingBounds.bounds.right, startingBounds.bounds.bottom).minus(pipRegion)
- visibleRegion(fixedApp.component).coversExactly(expectedWithoutPip)
- visibleRegion(pipApp.component).coversAtMost(startingBounds)
+ visibleRegion(fixedApp.component).coversExactly(screenBoundsStart)
}
}
+ /**
+ * Checks that [fixedApp] layer is within [screenBoundsEnd] at the end of the transition
+ */
@Presubmit
@Test
fun appLayerRotates_EndingBounds() {
testSpec.assertLayersEnd {
- val pipRegion = visibleRegion(pipApp.component).region
- val expectedWithoutPip = Region(endingBounds.bounds.left, endingBounds.bounds.top,
- endingBounds.bounds.right, endingBounds.bounds.bottom).minus(pipRegion)
- visibleRegion(fixedApp.component).coversExactly(expectedWithoutPip)
- visibleRegion(pipApp.component).coversAtMost(endingBounds)
+ visibleRegion(fixedApp.component).coversExactly(screenBoundsEnd)
+ }
+ }
+
+ /**
+ * Checks that [pipApp] layer is within [screenBoundsStart] at the start of the transition
+ */
+ @Presubmit
+ @Test
+ fun pipLayerRotates_StartingBounds() {
+ testSpec.assertLayersStart {
+ visibleRegion(pipApp.component).coversAtMost(screenBoundsStart)
+ }
+ }
+
+ /**
+ * Checks that [pipApp] layer is within [screenBoundsEnd] at the end of the transition
+ */
+ @Presubmit
+ @Test
+ fun pipLayerRotates_EndingBounds() {
+ testSpec.assertLayersEnd {
+ visibleRegion(pipApp.component).coversAtMost(screenBoundsEnd)
+ }
+ }
+
+ /**
+ * Ensure that the [pipApp] window does not obscure the [fixedApp] at the start of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun pipIsAboveFixedAppWindow_Start() {
+ testSpec.assertWmStart {
+ isAboveWindow(pipApp.component, fixedApp.component)
+ }
+ }
+
+ /**
+ * Ensure that the [pipApp] window does not obscure the [fixedApp] at the end of the
+ * transition
+ */
+ @Presubmit
+ @Test
+ fun pipIsAboveFixedAppWindow_End() {
+ testSpec.assertWmEnd {
+ isAboveWindow(pipApp.component, fixedApp.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/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
deleted file mode 100644
index 914bc8b..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipShelfHeightTest.kt
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * 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.wm.shell.flicker.pip
-
-import android.platform.test.annotations.Presubmit
-import android.view.Surface
-import androidx.test.filters.RequiresDevice
-import com.android.launcher3.tapl.LauncherInstrumentation
-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.annotation.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.wm.shell.flicker.helpers.FixedAppHelper
-import com.google.common.truth.Truth
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip movement with Launcher shelf height change.
- * To run this test: `atest WMShellFlickerTests:PipShelfHeightTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipShelfHeightTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
- private val taplInstrumentation = LauncherInstrumentation()
- private val testApp = FixedAppHelper(instrumentation)
-
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = buildTransition(eachRun = false) {
- teardown {
- eachRun {
- taplInstrumentation.pressHome()
- }
- test {
- testApp.exit(wmHelper)
- }
- }
- transitions {
- testApp.launchViaIntent(wmHelper)
- }
- }
-
- @Presubmit
- @Test
- fun pipAlwaysVisible() = testSpec.assertWm { this.isAppWindowVisible(pipApp.component) }
-
- @Presubmit
- @Test
- fun pipLayerInsideDisplay() {
- testSpec.assertLayersStart {
- visibleRegion(pipApp.component).coversAtMost(displayBounds)
- }
- }
-
- @Presubmit
- @Test
- fun pipWindowMovesUp() = testSpec.assertWmEnd {
- val initialState = this.trace?.first()?.wmState
- ?: error("Trace should not be empty")
- val startPos = initialState.pinnedWindows.first().frame
- val currPos = this.wmState.pinnedWindows.first().frame
- val subject = Truth.assertWithMessage("Pip should have moved up")
- subject.that(currPos.top).isGreaterThan(startPos.top)
- subject.that(currPos.bottom).isGreaterThan(startPos.bottom)
- subject.that(currPos.left).isEqualTo(startPos.left)
- subject.that(currPos.right).isEqualTo(startPos.right)
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance().getConfigNonRotationTests(
- supportedRotations = listOf(Surface.ROTATION_0), repetitions = 5)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
deleted file mode 100644
index 5abcf39..0000000
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipToAppTest.kt
+++ /dev/null
@@ -1,113 +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.wm.shell.flicker.pip
-
-import android.view.Surface
-import androidx.test.filters.FlakyTest
-import androidx.test.filters.RequiresDevice
-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.Group3
-import com.android.server.wm.flicker.dsl.FlickerBuilder
-import com.android.server.wm.flicker.helpers.setRotation
-import com.android.server.wm.flicker.startRotation
-import org.junit.FixMethodOrder
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.junit.runners.MethodSorters
-import org.junit.runners.Parameterized
-
-/**
- * Test Pip launch.
- * To run this test: `atest WMShellFlickerTests:PipToAppTest`
- */
-@RequiresDevice
-@RunWith(Parameterized::class)
-@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
-@FixMethodOrder(MethodSorters.NAME_ASCENDING)
-@Group3
-class PipToAppTest(testSpec: FlickerTestParameter) : PipTransition(testSpec) {
- override val transition: FlickerBuilder.(Map<String, Any?>) -> Unit
- get() = buildTransition(eachRun = true) { configuration ->
- setup {
- eachRun {
- this.setRotation(configuration.startRotation)
- }
- }
- teardown {
- eachRun {
- this.setRotation(Surface.ROTATION_0)
- }
- }
- transitions {
- pipApp.expandPipWindowToApp(wmHelper)
- }
- }
-
- @FlakyTest
- @Test
- fun appReplacesPipWindow() {
- testSpec.assertWm {
- this.invoke("hasPipWindow") { it.isPinned(pipApp.component) }
- .isAppWindowOnTop(pipApp.component)
- .then()
- .invoke("hasNotPipWindow") { it.isNotPinned(pipApp.component) }
- .isAppWindowOnTop(pipApp.component)
- }
- }
-
- @FlakyTest
- @Test
- fun appReplacesPipLayer() {
- testSpec.assertLayers {
- this.isVisible(pipApp.component)
- .isVisible(LAUNCHER_COMPONENT)
- .then()
- .isVisible(pipApp.component)
- .isInvisible(LAUNCHER_COMPONENT)
- }
- }
-
- @FlakyTest
- @Test
- fun testAppCoversFullScreen() {
- testSpec.assertLayersStart {
- visibleRegion(pipApp.component).coversExactly(displayBounds)
- }
- }
-
- @FlakyTest(bugId = 151179149)
- @Test
- fun focusChanges() {
- testSpec.assertEventLog {
- this.focusChanges("NexusLauncherActivity",
- pipApp.launcherName, "NexusLauncherActivity")
- }
- }
-
- companion object {
- @Parameterized.Parameters(name = "{0}")
- @JvmStatic
- fun getParams(): List<FlickerTestParameter> {
- return FlickerTestParameterFactory.getInstance()
- .getConfigNonRotationTests(supportedRotations = listOf(Surface.ROTATION_0),
- repetitions = 5)
- }
- }
-}
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
index ca80d18..ce89fb6 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/PipTransition.kt
@@ -187,6 +187,5 @@
@Presubmit
@Test
- open fun entireScreenCovered() =
- testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
+ open fun entireScreenCovered() = testSpec.entireScreenCovered()
}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
index e7b6197..02a3eb1 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/pip/SetRequestedOrientationWhilePinnedTest.kt
@@ -144,9 +144,7 @@
@FlakyTest
@Test
- override fun entireScreenCovered() {
- super.entireScreenCovered()
- }
+ override fun entireScreenCovered() = super.entireScreenCovered()
companion object {
@Parameterized.Parameters(name = "{0}")
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
index 698315a..c456c7d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/split/SplitWindowManagerTests.java
@@ -22,6 +22,7 @@
import android.content.res.Configuration;
import android.graphics.Rect;
+import android.view.InsetsState;
import android.view.SurfaceControl;
import androidx.test.annotation.UiThreadTest;
@@ -59,7 +60,7 @@
@Test
@UiThreadTest
public void testInitRelease() {
- mSplitWindowManager.init(mSplitLayout);
+ mSplitWindowManager.init(mSplitLayout, new InsetsState());
assertThat(mSplitWindowManager.getSurfaceControl()).isNotNull();
mSplitWindowManager.release();
assertThat(mSplitWindowManager.getSurfaceControl()).isNull();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index b0a39d6..736566e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -33,6 +33,7 @@
import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
import com.android.wm.shell.ShellTaskOrganizer;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.common.split.SplitLayout;
@@ -65,10 +66,12 @@
TestStageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
RootTaskDisplayAreaOrganizer rootTDAOrganizer, ShellTaskOrganizer taskOrganizer,
MainStage mainStage, SideStage sideStage, DisplayImeController imeController,
- SplitLayout splitLayout, Transitions transitions, TransactionPool transactionPool,
+ DisplayInsetsController insetsController, SplitLayout splitLayout,
+ Transitions transitions, TransactionPool transactionPool,
SplitscreenEventLogger logger) {
super(context, displayId, syncQueue, rootTDAOrganizer, taskOrganizer, mainStage,
- sideStage, imeController, splitLayout, transitions, transactionPool, logger);
+ sideStage, imeController, insetsController, splitLayout, transitions,
+ transactionPool, logger);
// Prepare default TaskDisplayArea for testing.
mDisplayAreaInfo = new DisplayAreaInfo(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index cb759dc..d357e77 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -46,6 +46,7 @@
import android.view.SurfaceSession;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
import android.window.WindowContainerTransaction;
@@ -58,6 +59,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.ShellExecutor;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
@@ -79,6 +81,7 @@
@Mock private SyncTransactionQueue mSyncQueue;
@Mock private RootTaskDisplayAreaOrganizer mRootTDAOrganizer;
@Mock private DisplayImeController mDisplayImeController;
+ @Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private TransactionPool mTransactionPool;
@Mock private Transitions mTransitions;
@Mock private SurfaceSession mSurfaceSession;
@@ -107,9 +110,10 @@
StageTaskListener.StageListenerCallbacks.class), mSyncQueue, mSurfaceSession);
mSideStage.onTaskAppeared(new TestRunningTaskInfoBuilder().build(), createMockSurface());
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
- mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
- mDisplayImeController, mSplitLayout, mTransitions, mTransactionPool,
- mLogger);
+ mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
+ mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
+ mTransactionPool,
+ mLogger);
mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
.when(mTransitions).startTransition(anyInt(), any(), any());
@@ -127,8 +131,8 @@
TestRemoteTransition testRemote = new TestRemoteTransition();
IBinder transition = mSplitScreenTransitions.startEnterTransition(
- TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(), testRemote,
- mStageCoordinator);
+ TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
+ new RemoteTransition(testRemote), mStageCoordinator);
mMainStage.onTaskAppeared(mMainChild, createMockSurface());
mSideStage.onTaskAppeared(mSideChild, createMockSurface());
boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -301,7 +305,7 @@
TransitionInfo enterInfo = createEnterPairInfo();
IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
TRANSIT_SPLIT_SCREEN_PAIR_OPEN, new WindowContainerTransaction(),
- new TestRemoteTransition(), mStageCoordinator);
+ new RemoteTransition(new TestRemoteTransition()), mStageCoordinator);
mMainStage.onTaskAppeared(mMainChild, createMockSurface());
mSideStage.onTaskAppeared(mSideChild, createMockSurface());
mStageCoordinator.startAnimation(enterTransit, enterInfo,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index a4b76fb..6cce0ab 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -37,6 +37,7 @@
import com.android.wm.shell.ShellTestCase;
import com.android.wm.shell.TestRunningTaskInfoBuilder;
import com.android.wm.shell.common.DisplayImeController;
+import com.android.wm.shell.common.DisplayInsetsController;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TransactionPool;
import com.android.wm.shell.transition.Transitions;
@@ -57,6 +58,7 @@
@Mock private MainStage mMainStage;
@Mock private SideStage mSideStage;
@Mock private DisplayImeController mDisplayImeController;
+ @Mock private DisplayInsetsController mDisplayInsetsController;
@Mock private Transitions mTransitions;
@Mock private TransactionPool mTransactionPool;
@Mock private SplitscreenEventLogger mLogger;
@@ -67,8 +69,8 @@
MockitoAnnotations.initMocks(this);
mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
mSyncQueue, mRootTDAOrganizer, mTaskOrganizer, mMainStage, mSideStage,
- mDisplayImeController, null /* splitLayout */, mTransitions, mTransactionPool,
- mLogger);
+ mDisplayImeController, mDisplayInsetsController, null /* splitLayout */,
+ mTransitions, mTransactionPool, mLogger);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 160b367..2994e71 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -25,6 +25,7 @@
import static org.junit.Assert.assertNotEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.verify;
import android.app.ActivityManager;
@@ -85,7 +86,6 @@
static final class TestStartingSurfaceDrawer extends StartingSurfaceDrawer{
int mAddWindowForTask = 0;
- int mViewThemeResId;
TestStartingSurfaceDrawer(Context context, ShellExecutor splashScreenExecutor,
TransactionPool pool) {
@@ -97,7 +97,6 @@
WindowManager.LayoutParams params, int suggestType) {
// listen for addView
mAddWindowForTask = taskId;
- mViewThemeResId = view.getContext().getThemeResId();
// Do not wait for background color
return false;
}
@@ -167,12 +166,15 @@
final int taskId = 1;
final StartingWindowInfo windowInfo =
createWindowInfo(taskId, 0);
+ final int[] theme = new int[1];
+ doAnswer(invocation -> theme[0] = (Integer) invocation.callRealMethod())
+ .when(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any());
+
mStartingSurfaceDrawer.addSplashScreenStartingWindow(windowInfo, mBinder,
STARTING_WINDOW_TYPE_SPLASH_SCREEN);
waitHandlerIdle(mTestHandler);
- verify(mStartingSurfaceDrawer).addWindow(eq(taskId), eq(mBinder), any(), any(), any(),
- eq(STARTING_WINDOW_TYPE_SPLASH_SCREEN));
- assertNotEquals(mStartingSurfaceDrawer.mViewThemeResId, 0);
+ verify(mStartingSurfaceDrawer).getSplashScreenTheme(eq(0), any());
+ assertNotEquals(theme[0], 0);
}
@Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
index 54eacee..b0f0d71 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java
@@ -63,6 +63,7 @@
import android.view.WindowManager;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -238,7 +239,8 @@
};
IBinder transitToken = new Binder();
transitions.requestStartTransition(transitToken,
- new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */, testRemote));
+ new TransitionRequestInfo(TRANSIT_OPEN, null /* trigger */,
+ new RemoteTransition(testRemote)));
verify(mOrganizer, times(1)).startTransition(eq(TRANSIT_OPEN), eq(transitToken), any());
TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN)
.addChange(TRANSIT_OPEN).addChange(TRANSIT_CLOSE).build();
@@ -383,7 +385,7 @@
new TransitionFilter.Requirement[]{new TransitionFilter.Requirement()};
filter.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- transitions.registerRemote(filter, testRemote);
+ transitions.registerRemote(filter, new RemoteTransition(testRemote));
mMainExecutor.flushAll();
IBinder transitToken = new Binder();
@@ -426,11 +428,12 @@
final int transitType = TRANSIT_FIRST_CUSTOM + 1;
- OneShotRemoteHandler oneShot = new OneShotRemoteHandler(mMainExecutor, testRemote);
+ OneShotRemoteHandler oneShot = new OneShotRemoteHandler(mMainExecutor,
+ new RemoteTransition(testRemote));
// Verify that it responds to the remote but not other things.
IBinder transitToken = new Binder();
assertNotNull(oneShot.handleRequest(transitToken,
- new TransitionRequestInfo(transitType, null, testRemote)));
+ new TransitionRequestInfo(transitType, null, new RemoteTransition(testRemote))));
assertNull(oneShot.handleRequest(transitToken,
new TransitionRequestInfo(transitType, null, null)));
@@ -731,24 +734,12 @@
IWindowManager mockWM = mock(IWindowManager.class);
final IDisplayWindowListener[] displayListener = new IDisplayWindowListener[1];
try {
- doAnswer(new Answer() {
- @Override
- public Object answer(InvocationOnMock invocation) {
- displayListener[0] = invocation.getArgument(0);
- return null;
- }
- }).when(mockWM).registerDisplayWindowListener(any());
+ doReturn(new int[] {DEFAULT_DISPLAY}).when(mockWM).registerDisplayWindowListener(any());
} catch (RemoteException e) {
// No remote stuff happening, so this can't be hit
}
DisplayController out = new DisplayController(mContext, mockWM, mMainExecutor);
out.initialize();
- try {
- displayListener[0].onDisplayAdded(DEFAULT_DISPLAY);
- mMainExecutor.flushAll();
- } catch (RemoteException e) {
- // Again, no remote stuff
- }
return out;
}
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index a031b4c..c22ab94 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -447,13 +447,26 @@
*/
public static final int FLAG_CAPTURE_PRIVATE = 0x1 << 13;
+ /**
+ * @hide
+ * Flag indicating the audio content has been processed to provide a virtual multichannel
+ * audio experience
+ */
+ public static final int FLAG_CONTENT_SPATIALIZED = 0x1 << 14;
+
+ /**
+ * @hide
+ * Flag indicating the audio content is to never be spatialized
+ */
+ public static final int FLAG_NEVER_SPATIALIZE = 0x1 << 15;
// Note that even though FLAG_MUTE_HAPTIC is stored as a flag bit, it is not here since
// it is known as a boolean value outside of AudioAttributes.
private static final int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO
| FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY
| FLAG_BYPASS_MUTE | FLAG_LOW_LATENCY | FLAG_DEEP_BUFFER | FLAG_NO_MEDIA_PROJECTION
- | FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE;
+ | FLAG_NO_SYSTEM_CAPTURE | FLAG_CAPTURE_PRIVATE | FLAG_CONTENT_SPATIALIZED
+ | FLAG_NEVER_SPATIALIZE;
private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED |
FLAG_HW_AV_SYNC | FLAG_LOW_LATENCY;
/* mask of flags that can be set by SDK and System APIs through the Builder */
@@ -615,6 +628,49 @@
}
/**
+ * Return true if the audio content associated with these attributes has already been
+ * spatialized, that is it has already been processed to offer a binaural or transaural
+ * immersive audio experience.
+ * @return {@code true} if the content has been processed
+ */
+ public boolean isContentSpatialized() {
+ return (mFlags & FLAG_CONTENT_SPATIALIZED) != 0;
+ }
+
+ /** @hide */
+ @IntDef(flag = false, value = {
+ SPATIALIZATION_BEHAVIOR_AUTO,
+ SPATIALIZATION_BEHAVIOR_NEVER,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface SpatializationBehavior {};
+
+ /**
+ * Constant indicating the audio content associated with these attributes will follow the
+ * default platform behavior with regards to which content will be spatialized or not.
+ * @see #getSpatializationBehavior()
+ * @see Spatializer
+ */
+ public static final int SPATIALIZATION_BEHAVIOR_AUTO = 0;
+
+ /**
+ * Constant indicating the audio content associated with these attributes should never
+ * be virtualized.
+ * @see #getSpatializationBehavior()
+ * @see Spatializer
+ */
+ public static final int SPATIALIZATION_BEHAVIOR_NEVER = 1;
+
+ /**
+ * Return the behavior affecting whether spatialization will be used.
+ * @return the spatialization behavior
+ */
+ public @SpatializationBehavior int getSpatializationBehavior() {
+ return ((mFlags & FLAG_NEVER_SPATIALIZE) != 0)
+ ? SPATIALIZATION_BEHAVIOR_NEVER : SPATIALIZATION_BEHAVIOR_AUTO;
+ }
+
+ /**
* Return the capture policy.
* @return the capture policy set by {@link Builder#setAllowedCapturePolicy(int)} or
* the default if it was not called.
@@ -657,6 +713,8 @@
private int mSource = MediaRecorder.AudioSource.AUDIO_SOURCE_INVALID;
private int mFlags = 0x0;
private boolean mMuteHapticChannels = true;
+ private boolean mIsContentSpatialized = false;
+ private int mSpatializationBehavior = SPATIALIZATION_BEHAVIOR_AUTO;
private HashSet<String> mTags = new HashSet<String>();
private Bundle mBundle;
private int mPrivacySensitive = PRIVACY_SENSITIVE_DEFAULT;
@@ -687,6 +745,8 @@
mFlags = aa.getAllFlags();
mTags = (HashSet<String>) aa.mTags.clone();
mMuteHapticChannels = aa.areHapticChannelsMuted();
+ mIsContentSpatialized = aa.isContentSpatialized();
+ mSpatializationBehavior = aa.getSpatializationBehavior();
}
/**
@@ -719,6 +779,12 @@
if (mMuteHapticChannels) {
aa.mFlags |= FLAG_MUTE_HAPTIC;
}
+ if (mIsContentSpatialized) {
+ aa.mFlags |= FLAG_CONTENT_SPATIALIZED;
+ }
+ if (mSpatializationBehavior == SPATIALIZATION_BEHAVIOR_NEVER) {
+ aa.mFlags |= FLAG_NEVER_SPATIALIZE;
+ }
if (mPrivacySensitive == PRIVACY_SENSITIVE_DEFAULT) {
// capturing for camcorder or communication is private by default to
@@ -906,6 +972,35 @@
}
/**
+ * Specifies whether the content has already been processed for spatialization.
+ * If it has, setting this to true will prevent issues such as double-processing.
+ * @param isSpatialized
+ * @return the same Builder instance
+ */
+ public @NonNull Builder setIsContentSpatialized(boolean isSpatialized) {
+ mIsContentSpatialized = isSpatialized;
+ return this;
+ }
+
+ /**
+ * Sets the behavior affecting whether spatialization will be used.
+ * @param sb the spatialization behavior
+ * @return the same Builder instance
+ *
+ */
+ public @NonNull Builder setSpatializationBehavior(@SpatializationBehavior int sb) {
+ switch (sb) {
+ case SPATIALIZATION_BEHAVIOR_NEVER:
+ case SPATIALIZATION_BEHAVIOR_AUTO:
+ break;
+ default:
+ throw new IllegalArgumentException("Invalid spatialization behavior " + sb);
+ }
+ mSpatializationBehavior = sb;
+ return this;
+ }
+
+ /**
* @hide
* Replaces flags.
* @param flags any combination of {@link AudioAttributes#FLAG_ALL}.
@@ -990,6 +1085,8 @@
mContentType = attributes.mContentType;
mFlags = attributes.getAllFlags();
mMuteHapticChannels = attributes.areHapticChannelsMuted();
+ mIsContentSpatialized = attributes.isContentSpatialized();
+ mSpatializationBehavior = attributes.getSpatializationBehavior();
mTags = attributes.mTags;
mBundle = attributes.mBundle;
mSource = attributes.mSource;
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 3b9c05b..5db9ddf 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -805,7 +805,7 @@
}
@UnsupportedAppUsage
- private static IAudioService getService()
+ static IAudioService getService()
{
if (sService != null) {
return sService;
@@ -2439,6 +2439,25 @@
}
//====================================================================
+ // Immersive audio
+
+ /**
+ * Return a handle to the optional platform's {@link Spatializer}
+ * @return {@code null} if spatialization is not supported, the {@code Spatializer} instance
+ * otherwise.
+ */
+ public @Nullable Spatializer getSpatializer() {
+ int level = Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+ try {
+ level = getService().getSpatializerImmersiveAudioLevel();
+ } catch (Exception e) { /* using NONE */ }
+ if (level == Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE) {
+ return null;
+ }
+ return new Spatializer(this);
+ }
+
+ //====================================================================
// Bluetooth SCO control
/**
* Sticky broadcast intent action indicating that the Bluetooth SCO audio
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 0b35ebe..8480c52 100755
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -20,6 +20,7 @@
import android.content.ComponentName;
import android.media.AudioAttributes;
import android.media.AudioDeviceAttributes;
+import android.media.AudioFormat;
import android.media.AudioFocusInfo;
import android.media.AudioPlaybackConfiguration;
import android.media.AudioRecordingConfiguration;
@@ -34,6 +35,7 @@
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
import android.media.IStrategyPreferredDevicesDispatcher;
+import android.media.ISpatializerCallback;
import android.media.IVolumeController;
import android.media.IVolumeController;
import android.media.PlayerBase;
@@ -392,4 +394,24 @@
void registerModeDispatcher(IAudioModeDispatcher dispatcher);
oneway void unregisterModeDispatcher(IAudioModeDispatcher dispatcher);
+
+ int getSpatializerImmersiveAudioLevel();
+
+ boolean isSpatializerEnabled();
+
+ boolean isSpatializerAvailable();
+
+ void setSpatializerEnabled(boolean enabled);
+
+ boolean canBeSpatialized(in AudioAttributes aa, in AudioFormat af);
+
+ void registerSpatializerCallback(in ISpatializerCallback callback);
+
+ void unregisterSpatializerCallback(in ISpatializerCallback callback);
+
+ List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices();
+
+ void addSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
+
+ void removeSpatializerCompatibleAudioDevice(in AudioDeviceAttributes ada);
}
diff --git a/media/java/android/media/ISpatializerCallback.aidl b/media/java/android/media/ISpatializerCallback.aidl
new file mode 100644
index 0000000..50f91e7
--- /dev/null
+++ b/media/java/android/media/ISpatializerCallback.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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 android.media;
+
+/**
+ * AIDL for the AudioService to signal Spatializer state changes.
+ *
+ * {@hide}
+ */
+oneway interface ISpatializerCallback {
+
+ void dispatchSpatializerEnabledChanged(boolean enabled);
+
+ void dispatchSpatializerAvailableChanged(boolean available);
+}
diff --git a/media/java/android/media/Spatializer.java b/media/java/android/media/Spatializer.java
new file mode 100644
index 0000000..3ed8b58
--- /dev/null
+++ b/media/java/android/media/Spatializer.java
@@ -0,0 +1,404 @@
+/*
+ * 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 android.media;
+
+import android.annotation.CallbackExecutor;
+import android.annotation.IntDef;
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.RequiresPermission;
+import android.annotation.SystemApi;
+import android.media.permission.ClearCallingIdentityContext;
+import android.media.permission.SafeCloseable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import com.android.internal.annotations.GuardedBy;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.concurrent.Executor;
+
+/**
+ * Spatializer provides access to querying capabilities and behavior of sound spatialization
+ * on the device.
+ * Sound spatialization simulates sounds originating around the listener as if they were coming
+ * from virtual speakers placed around the listener.<br>
+ * Support for spatialization is optional, use {@link AudioManager#getSpatializer()} to obtain an
+ * instance of this class if the feature is supported.
+ *
+ */
+public class Spatializer {
+
+ private final @NonNull AudioManager mAm;
+
+ private final Object mStateListenerLock = new Object();
+
+ private static final String TAG = "Spatializer";
+
+ /**
+ * List of listeners for state listener and their associated Executor.
+ * List is lazy-initialized on first registration
+ */
+ @GuardedBy("mStateListenerLock")
+ private @Nullable ArrayList<StateListenerInfo> mStateListeners;
+
+ @GuardedBy("mStateListenerLock")
+ private SpatializerInfoDispatcherStub mInfoDispatcherStub;
+
+ /**
+ * @hide
+ * Constructor with AudioManager acting as proxy to AudioService
+ * @param am a non-null AudioManager
+ */
+ protected Spatializer(@NonNull AudioManager am) {
+ mAm = Objects.requireNonNull(am);
+ }
+
+ /**
+ * Returns whether spatialization is enabled or not.
+ * A false value can originate for instance from the user electing to
+ * disable the feature.<br>
+ * Note that this state reflects a platform-wide state of the "desire" to use spatialization,
+ * but availability of the audio processing is still dictated by the compatibility between
+ * the effect and the hardware configuration, as indicated by {@link #isAvailable()}.
+ * @return {@code true} if spatialization is enabled
+ * @see #isAvailable()
+ */
+ public boolean isEnabled() {
+ try {
+ return mAm.getService().isSpatializerEnabled();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying isSpatializerEnabled, returning false", e);
+ return false;
+ }
+ }
+
+ /**
+ * Returns whether spatialization is available.
+ * Reasons for spatialization being unavailable include situations where audio output is
+ * incompatible with sound spatialization, such as playback on a monophonic speaker.<br>
+ * Note that spatialization can be available, but disabled by the user, in which case this
+ * method would still return {@code true}, whereas {@link #isEnabled()}
+ * would return {@code false}.
+ * @return {@code true} if the spatializer effect is available and capable
+ * of processing the audio for the current configuration of the device,
+ * {@code false} otherwise.
+ * @see #isEnabled()
+ */
+ public boolean isAvailable() {
+ try {
+ return mAm.getService().isSpatializerAvailable();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying isSpatializerAvailable, returning false", e);
+ return false;
+ }
+ }
+
+ /** @hide */
+ @IntDef(flag = false, value = {
+ SPATIALIZER_IMMERSIVE_LEVEL_NONE,
+ SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ public @interface ImmersiveAudioLevel {};
+
+ /**
+ * @hide
+ * Constant indicating there are no spatialization capabilities supported on this device.
+ * @see AudioManager#getImmersiveAudioLevel()
+ */
+ public static final int SPATIALIZER_IMMERSIVE_LEVEL_NONE = 0;
+
+ /**
+ * @hide
+ * Constant indicating the {@link Spatializer} on this device supports multichannel
+ * spatialization.
+ * @see AudioManager#getImmersiveAudioLevel()
+ */
+ public static final int SPATIALIZER_IMMERSIVE_LEVEL_MULTICHANNEL = 1;
+
+ /**
+ * @hide
+ * Enables / disables the spatializer effect.
+ * Changing the enabled state will trigger the public
+ * {@link OnSpatializerStateChangedListener#onSpatializerEnabledChanged(Spatializer, boolean)}
+ * registered listeners.
+ * @param enabled {@code true} for enabling the effect
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public void setEnabled(boolean enabled) {
+ try {
+ mAm.getService().setSpatializerEnabled(enabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling setSpatializerEnabled", e);
+ }
+ }
+
+ /**
+ * An interface to be notified of changes to the state of the spatializer.
+ */
+ public interface OnSpatializerStateChangedListener {
+ /**
+ * Called when the enabled state of the spatializer effect changes
+ * @param spat the {@code Spatializer} instance whose state changed
+ * @param enabled {@code true} if the spatializer effect is enabled on the device,
+ * {@code false} otherwise
+ * @see #isEnabled()
+ */
+ void onSpatializerEnabledChanged(@NonNull Spatializer spat, boolean enabled);
+
+ /**
+ * Called when the availability of the spatializer effect changes
+ * @param spat the {@code Spatializer} instance whose state changed
+ * @param available {@code true} if the spatializer effect is available and capable
+ * of processing the audio for the current configuration of the device,
+ * {@code false} otherwise.
+ * @see #isAvailable()
+ */
+ void onSpatializerAvailableChanged(@NonNull Spatializer spat, boolean available);
+ }
+
+ /**
+ * Returns whether audio of the given {@link AudioFormat}, played with the given
+ * {@link AudioAttributes} can be spatialized.
+ * Note that the result reflects the capabilities of the device and may change when
+ * audio accessories are connected/disconnected (e.g. wired headphones plugged in or not).
+ * The result is independent from whether spatialization processing is enabled or not.
+ * @param attributes the {@code AudioAttributes} of the content as used for playback
+ * @param format the {@code AudioFormat} of the content as used for playback
+ * @return {@code true} if the device is capable of spatializing the combination of audio format
+ * and attributes, {@code false} otherwise.
+ */
+ public boolean canBeSpatialized(
+ @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+ try {
+ return mAm.getService().canBeSpatialized(
+ Objects.requireNonNull(attributes), Objects.requireNonNull(format));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying canBeSpatialized for attr:" + attributes
+ + " format:" + format + " returning false", e);
+ return false;
+ }
+ }
+
+ /**
+ * Adds a listener to be notified of changes to the enabled state of the
+ * {@code Spatializer}.
+ * @param executor the {@code Executor} handling the callback
+ * @param listener the listener to receive enabled state updates
+ * @see #isEnabled()
+ */
+ public void addOnSpatializerStateChangedListener(
+ @NonNull @CallbackExecutor Executor executor,
+ @NonNull OnSpatializerStateChangedListener listener) {
+ Objects.requireNonNull(executor);
+ Objects.requireNonNull(listener);
+ synchronized (mStateListenerLock) {
+ if (hasSpatializerStateListener(listener)) {
+ throw new IllegalArgumentException(
+ "Called addOnSpatializerStateChangedListener() "
+ + "on a previously registered listener");
+ }
+ // lazy initialization of the list of strategy-preferred device listener
+ if (mStateListeners == null) {
+ mStateListeners = new ArrayList<>();
+ }
+ mStateListeners.add(new StateListenerInfo(listener, executor));
+ if (mStateListeners.size() == 1) {
+ // register binder for callbacks
+ if (mInfoDispatcherStub == null) {
+ mInfoDispatcherStub =
+ new SpatializerInfoDispatcherStub();
+ }
+ try {
+ mAm.getService().registerSpatializerCallback(
+ mInfoDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ }
+ }
+ }
+ }
+
+ /**
+ * Removes a previously added listener for changes to the enabled state of the
+ * {@code Spatializer}.
+ * @param listener the listener to receive enabled state updates
+ * @see #isEnabled()
+ */
+ public void removeOnSpatializerStateChangedListener(
+ @NonNull OnSpatializerStateChangedListener listener) {
+ Objects.requireNonNull(listener);
+ synchronized (mStateListenerLock) {
+ if (!removeStateListener(listener)) {
+ throw new IllegalArgumentException(
+ "Called removeOnSpatializerStateChangedListener() "
+ + "on an unregistered listener");
+ }
+ if (mStateListeners.size() == 0) {
+ // unregister binder for callbacks
+ try {
+ mAm.getService().unregisterSpatializerCallback(mInfoDispatcherStub);
+ } catch (RemoteException e) {
+ throw e.rethrowFromSystemServer();
+ } finally {
+ mInfoDispatcherStub = null;
+ mStateListeners = null;
+ }
+ }
+ }
+ }
+
+ /**
+ * @hide
+ * Returns the list of playback devices that are compatible with the playback of multichannel
+ * audio through virtualization
+ * @return a list of devices. An empty list indicates virtualization is not supported.
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
+ try {
+ return mAm.getService().getSpatializerCompatibleAudioDevices();
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error querying getSpatializerCompatibleAudioDevices(), "
+ + " returning empty list", e);
+ return new ArrayList<AudioDeviceAttributes>(0);
+ }
+ }
+
+ /**
+ * @hide
+ * Adds a playback device to the list of devices compatible with the playback of multichannel
+ * audio through spatialization.
+ * @see #getCompatibleAudioDevices()
+ * @param ada the audio device compatible with spatialization
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ try {
+ mAm.getService().addSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling addSpatializerCompatibleAudioDevice(), ", e);
+ }
+ }
+
+ /**
+ * @hide
+ * Remove a playback device from the list of devices compatible with the playback of
+ * multichannel audio through spatialization.
+ * @see #getCompatibleAudioDevices()
+ * @param ada the audio device incompatible with spatialization
+ */
+ @SystemApi(client = SystemApi.Client.PRIVILEGED_APPS)
+ @RequiresPermission(android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ public void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ try {
+ mAm.getService().removeSpatializerCompatibleAudioDevice(Objects.requireNonNull(ada));
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling removeSpatializerCompatibleAudioDevice(), ", e);
+ }
+ }
+
+ private final class SpatializerInfoDispatcherStub extends ISpatializerCallback.Stub {
+ @Override
+ public void dispatchSpatializerEnabledChanged(boolean enabled) {
+ // make a shallow copy of listeners so callback is not executed under lock
+ final ArrayList<StateListenerInfo> stateListeners;
+ synchronized (mStateListenerLock) {
+ if (mStateListeners == null || mStateListeners.size() == 0) {
+ return;
+ }
+ stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
+ }
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ for (StateListenerInfo info : stateListeners) {
+ info.mExecutor.execute(() ->
+ info.mListener.onSpatializerEnabledChanged(Spatializer.this, enabled));
+ }
+ }
+ }
+
+ @Override
+ public void dispatchSpatializerAvailableChanged(boolean available) {
+ // make a shallow copy of listeners so callback is not executed under lock
+ final ArrayList<StateListenerInfo> stateListeners;
+ synchronized (mStateListenerLock) {
+ if (mStateListeners == null || mStateListeners.size() == 0) {
+ return;
+ }
+ stateListeners = (ArrayList<StateListenerInfo>) mStateListeners.clone();
+ }
+ try (SafeCloseable ignored = ClearCallingIdentityContext.create()) {
+ for (StateListenerInfo info : stateListeners) {
+ info.mExecutor.execute(() ->
+ info.mListener.onSpatializerAvailableChanged(
+ Spatializer.this, available));
+ }
+ }
+ }
+ }
+
+ private static class StateListenerInfo {
+ final @NonNull OnSpatializerStateChangedListener mListener;
+ final @NonNull Executor mExecutor;
+
+ StateListenerInfo(@NonNull OnSpatializerStateChangedListener listener,
+ @NonNull Executor exe) {
+ mListener = listener;
+ mExecutor = exe;
+ }
+ }
+
+ @GuardedBy("mStateListenerLock")
+ private boolean hasSpatializerStateListener(OnSpatializerStateChangedListener listener) {
+ return getStateListenerInfo(listener) != null;
+ }
+
+ @GuardedBy("mStateListenerLock")
+ private @Nullable StateListenerInfo getStateListenerInfo(
+ OnSpatializerStateChangedListener listener) {
+ if (mStateListeners == null) {
+ return null;
+ }
+ for (StateListenerInfo info : mStateListeners) {
+ if (info.mListener == listener) {
+ return info;
+ }
+ }
+ return null;
+ }
+
+ @GuardedBy("mStateListenerLock")
+ /**
+ * @return true if the listener was removed from the list
+ */
+ private boolean removeStateListener(OnSpatializerStateChangedListener listener) {
+ final StateListenerInfo infoToRemove = getStateListenerInfo(listener);
+ if (infoToRemove != null) {
+ mStateListeners.remove(infoToRemove);
+ return true;
+ }
+ return false;
+ }
+}
diff --git a/media/java/android/media/projection/MediaProjection.java b/media/java/android/media/projection/MediaProjection.java
index 72cddc9..5259c4f 100644
--- a/media/java/android/media/projection/MediaProjection.java
+++ b/media/java/android/media/projection/MediaProjection.java
@@ -25,6 +25,7 @@
import android.hardware.display.VirtualDisplay;
import android.hardware.display.VirtualDisplayConfig;
import android.os.Handler;
+import android.os.IBinder;
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Log;
@@ -100,19 +101,22 @@
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, boolean isSecure, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
- DisplayManager dm = (DisplayManager) mContext.getSystemService(Context.DISPLAY_SERVICE);
int flags = DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR
| DisplayManager.VIRTUAL_DISPLAY_FLAG_PRESENTATION;
if (isSecure) {
flags |= DisplayManager.VIRTUAL_DISPLAY_FLAG_SECURE;
}
+ Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
- height, dpi);
+ height, dpi, windowContext.getWindowContextToken());
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
- return dm.createVirtualDisplay(this, builder.build(), callback, handler);
+ VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
+ windowContext);
+ return virtualDisplay;
}
/**
@@ -141,13 +145,17 @@
public VirtualDisplay createVirtualDisplay(@NonNull String name,
int width, int height, int dpi, int flags, @Nullable Surface surface,
@Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
+ TYPE_APPLICATION, null /* options */);
final VirtualDisplayConfig.Builder builder = buildMirroredVirtualDisplay(name, width,
- height, dpi);
+ height, dpi, windowContext.getWindowContextToken());
builder.setFlags(flags);
if (surface != null) {
builder.setSurface(surface);
}
- return createVirtualDisplay(builder.build(), callback, handler);
+ VirtualDisplay virtualDisplay = createVirtualDisplay(builder.build(), callback, handler,
+ windowContext);
+ return virtualDisplay;
}
/**
@@ -161,12 +169,10 @@
* @return a config representing a VirtualDisplay
*/
private VirtualDisplayConfig.Builder buildMirroredVirtualDisplay(@NonNull String name,
- int width, int height, int dpi) {
- Context windowContext = mContext.createWindowContext(mContext.getDisplayNoVerify(),
- TYPE_APPLICATION, null /* options */);
+ int width, int height, int dpi, IBinder windowContextToken) {
final VirtualDisplayConfig.Builder builder = new VirtualDisplayConfig.Builder(name, width,
height, dpi);
- builder.setWindowTokenClientToMirror(windowContext.getWindowContextToken());
+ builder.setWindowTokenClientToMirror(windowContextToken);
return builder;
}
@@ -176,20 +182,22 @@
*
* @param virtualDisplayConfig The arguments for the virtual display configuration. See
* {@link VirtualDisplayConfig} for using it.
- * @param callback Callback to call when the virtual display's state
- * changes, or null if none.
- * @param handler The {@link android.os.Handler} on which the callback should be
- * invoked, or null if the callback should be invoked on the calling
- * thread's main {@link android.os.Looper}.
+ * @param callback Callback to call when the virtual display's state changes, or null if none.
+ * @param handler The {@link android.os.Handler} on which the callback should be invoked, or
+ * null if the callback should be invoked on the calling thread's main
+ * {@link android.os.Looper}.
+ * @param windowContext the WindowContext associated with the caller.
*
* @see android.hardware.display.VirtualDisplay
* @hide
*/
@Nullable
public VirtualDisplay createVirtualDisplay(@NonNull VirtualDisplayConfig virtualDisplayConfig,
- @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler) {
+ @Nullable VirtualDisplay.Callback callback, @Nullable Handler handler,
+ Context windowContext) {
DisplayManager dm = mContext.getSystemService(DisplayManager.class);
- return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler);
+ return dm.createVirtualDisplay(this, virtualDisplayConfig, callback, handler,
+ windowContext);
}
/**
diff --git a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
index 5f107d6..34e7e3d 100644
--- a/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
+++ b/packages/PrintRecommendationService/src/com/android/printservice/recommendation/plugin/mdnsFilter/MDNSFilterPlugin.java
@@ -84,8 +84,7 @@
*/
public MDNSFilterPlugin(@NonNull Context context, @NonNull String name,
@NonNull CharSequence packageName, @NonNull List<String> mDNSNames) {
- mName = context.getResources().getIdentifier(name, null,
- "com.android.printservice.recommendation");
+ mName = context.getResources().getIdentifier(name, null, context.getPackageName());
mPackageName = packageName;
mMDNSFilteredDiscovery = new MDNSFilteredDiscovery(context, PRINTER_SERVICE_TYPES,
new VendorNameFilter(new HashSet<>(mDNSNames)));
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-in/arrays.xml b/packages/SettingsLib/res/values-in/arrays.xml
index 2dba96a..7b4c9b6 100644
--- a/packages/SettingsLib/res/values-in/arrays.xml
+++ b/packages/SettingsLib/res/values-in/arrays.xml
@@ -23,7 +23,7 @@
<string-array name="wifi_status">
<item msgid="1596683495752107015"></item>
<item msgid="3288373008277313483">"Memindai..."</item>
- <item msgid="6050951078202663628">"Menyambung…"</item>
+ <item msgid="6050951078202663628">"Menghubungkan…"</item>
<item msgid="8356618438494652335">"Mengautentikasi…"</item>
<item msgid="2837871868181677206">"Mendapatkan alamat IP…"</item>
<item msgid="4613015005934755724">"Terhubung"</item>
@@ -37,7 +37,7 @@
<string-array name="wifi_status_with_ssid">
<item msgid="5969842512724979061"></item>
<item msgid="1818677602615822316">"Memindai..."</item>
- <item msgid="8339720953594087771">"Menyambung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
+ <item msgid="8339720953594087771">"Menghubungkan ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="3028983857109369308">"Mengautentikasi dengan <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="4287401332778341890">"Mendapatkan alamat IP dari <xliff:g id="NETWORK_NAME">%1$s</xliff:g>…"</item>
<item msgid="1043944043827424501">"Terhubung ke <xliff:g id="NETWORK_NAME">%1$s</xliff:g>"</item>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index c140308..8b20b87 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -26,21 +26,21 @@
<string name="wifi_disconnected" msgid="7054450256284661757">"Terputus"</string>
<string name="wifi_disabled_generic" msgid="2651916945380294607">"Nonaktif"</string>
<string name="wifi_disabled_network_failure" msgid="2660396183242399585">"Kegagalan Konfigurasi IP"</string>
- <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Tidak tersambung karena jaringan berkualitas rendah"</string>
+ <string name="wifi_disabled_by_recommendation_provider" msgid="1302938248432705534">"Tidak terhubung karena jaringan berkualitas rendah"</string>
<string name="wifi_disabled_wifi_failure" msgid="8819554899148331100">"Kegagalan Sambungan Wi-Fi"</string>
<string name="wifi_disabled_password_failure" msgid="6892387079613226738">"Masalah autentikasi"</string>
- <string name="wifi_cant_connect" msgid="5718417542623056783">"Tidak dapat tersambung"</string>
- <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Tidak dapat tersambung ke \'<xliff:g id="AP_NAME">%1$s</xliff:g>\'"</string>
+ <string name="wifi_cant_connect" msgid="5718417542623056783">"Tidak dapat terhubung"</string>
+ <string name="wifi_cant_connect_to_ap" msgid="3099667989279700135">"Tidak dapat terhubung ke \'<xliff:g id="AP_NAME">%1$s</xliff:g>\'"</string>
<string name="wifi_check_password_try_again" msgid="8817789642851605628">"Periksa sandi dan coba lagi"</string>
<string name="wifi_not_in_range" msgid="1541760821805777772">"Tidak dalam jangkauan"</string>
- <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan tersambung otomatis"</string>
+ <string name="wifi_no_internet_no_reconnect" msgid="821591791066497347">"Tidak akan terhubung otomatis"</string>
<string name="wifi_no_internet" msgid="1774198889176926299">"Tidak ada akses internet"</string>
<string name="saved_network" msgid="7143698034077223645">"Disimpan oleh <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="connected_to_metered_access_point" msgid="9179693207918156341">"Terhubung ke jaringan berbayar"</string>
- <string name="connected_via_network_scorer" msgid="7665725527352893558">"Tersambung otomatis melalui %1$s"</string>
- <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis tersambung melalui penyedia rating jaringan"</string>
+ <string name="connected_via_network_scorer" msgid="7665725527352893558">"Terhubung otomatis melalui %1$s"</string>
+ <string name="connected_via_network_scorer_default" msgid="7973529709744526285">"Otomatis terhubung melalui penyedia rating jaringan"</string>
<string name="connected_via_passpoint" msgid="7735442932429075684">"Terhubung melalui %1$s"</string>
- <string name="connected_via_app" msgid="3532267661404276584">"Tersambung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
+ <string name="connected_via_app" msgid="3532267661404276584">"Terhubung melalui <xliff:g id="NAME">%1$s</xliff:g>"</string>
<string name="available_via_passpoint" msgid="1716000261192603682">"Tersedia melalui %1$s"</string>
<string name="tap_to_sign_up" msgid="5356397741063740395">"Ketuk untuk mendaftar"</string>
<string name="wifi_connected_no_internet" msgid="5087420713443350646">"Tidak ada internet"</string>
@@ -49,10 +49,10 @@
<string name="wifi_status_no_internet" msgid="3799933875988829048">"Tidak ada internet"</string>
<string name="wifi_status_sign_in_required" msgid="2236267500459526855">"Perlu login"</string>
<string name="wifi_ap_unable_to_handle_new_sta" msgid="5885145407184194503">"Titik akses penuh untuk sementara"</string>
- <string name="connected_via_carrier" msgid="1968057009076191514">"Tersambung melalui %1$s"</string>
+ <string name="connected_via_carrier" msgid="1968057009076191514">"Terhubung melalui %1$s"</string>
<string name="available_via_carrier" msgid="465598683092718294">"Tersedia melalui %1$s"</string>
<string name="osu_opening_provider" msgid="4318105381295178285">"Membuka <xliff:g id="PASSPOINTPROVIDER">%1$s</xliff:g>"</string>
- <string name="osu_connect_failed" msgid="9107873364807159193">"Tidak dapat tersambung"</string>
+ <string name="osu_connect_failed" msgid="9107873364807159193">"Tidak dapat terhubung"</string>
<string name="osu_completing_sign_up" msgid="8412636665040390901">"Menyelesaikan pendaftaran…"</string>
<string name="osu_sign_up_failed" msgid="5605453599586001793">"Tidak dapat menyelesaikan pendaftaran. Ketuk untuk mencoba lagi."</string>
<string name="osu_sign_up_complete" msgid="7640183358878916847">"Pendaftaran selesai. Menyambungkan…"</string>
@@ -66,7 +66,7 @@
<string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
<string name="bluetooth_disconnected" msgid="7739366554710388701">"Sambungan terputus"</string>
<string name="bluetooth_disconnecting" msgid="7638892134401574338">"Memutus sambungan..."</string>
- <string name="bluetooth_connecting" msgid="5871702668260192755">"Menyambung…"</string>
+ <string name="bluetooth_connecting" msgid="5871702668260192755">"Menghubungkan…"</string>
<string name="bluetooth_connected" msgid="8065345572198502293">"Terhubung<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
<string name="bluetooth_pairing" msgid="4269046942588193600">"Menyandingkan..."</string>
<string name="bluetooth_connected_no_headset" msgid="2224101138659967604">"Terhubung (tanpa ponsel)<xliff:g id="ACTIVE_DEVICE">%1$s</xliff:g>"</string>
@@ -96,12 +96,12 @@
<string name="bluetooth_profile_a2dp_high_quality_unknown_codec" msgid="2477639096903834374">"Audio HD"</string>
<string name="bluetooth_profile_hearing_aid" msgid="58154575573984914">"Alat Bantu Dengar"</string>
<string name="bluetooth_hearing_aid_profile_summary_connected" msgid="8191273236809964030">"Terhubung ke Alat Bantu Dengar"</string>
- <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Tersambung ke media audio"</string>
- <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Tersambung ke audio ponsel"</string>
+ <string name="bluetooth_a2dp_profile_summary_connected" msgid="7422607970115444153">"Terhubung ke media audio"</string>
+ <string name="bluetooth_headset_profile_summary_connected" msgid="2420981566026949688">"Terhubung ke audio ponsel"</string>
<string name="bluetooth_opp_profile_summary_connected" msgid="2393521801478157362">"Sambungkan ke server transfer file"</string>
- <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Tersambung ke peta"</string>
+ <string name="bluetooth_map_profile_summary_connected" msgid="4141725591784669181">"Terhubung ke peta"</string>
<string name="bluetooth_sap_profile_summary_connected" msgid="1280297388033001037">"Terhubung ke SAP"</string>
- <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Tidak tersambung kepada server transfer file"</string>
+ <string name="bluetooth_opp_profile_summary_not_connected" msgid="3959741824627764954">"Tidak terhubung kepada server transfer file"</string>
<string name="bluetooth_hid_profile_summary_connected" msgid="3923653977051684833">"Terhubung ke perangkat masukan"</string>
<string name="bluetooth_pan_user_profile_summary_connected" msgid="380469653827505727">"Terhubung ke perangkat untuk akses internet"</string>
<string name="bluetooth_pan_nap_profile_summary_connected" msgid="3744773111299503493">"Berbagi koneksi internet lokal dengan perangkat"</string>
@@ -116,7 +116,7 @@
<string name="bluetooth_pairing_accept" msgid="2054232610815498004">"Sambungkan"</string>
<string name="bluetooth_pairing_accept_all_caps" msgid="2734383073450506220">"SAMBUNGKAN"</string>
<string name="bluetooth_pairing_decline" msgid="6483118841204885890">"Batal"</string>
- <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Penyandingan memberi akses ke kontak dan histori panggilan saat tersambung"</string>
+ <string name="bluetooth_pairing_will_share_phonebook" msgid="3064334458659165176">"Penyandingan memberi akses ke kontak dan histori panggilan saat terhubung"</string>
<string name="bluetooth_pairing_error_message" msgid="6626399020672335565">"Tidak dapat menyambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
<string name="bluetooth_pairing_pin_error_message" msgid="264422127613704940">"Tidak dapat menyambungkan ke <xliff:g id="DEVICE_NAME">%1$s</xliff:g> karena PIN atau kode sandi salah."</string>
<string name="bluetooth_pairing_device_down_error_message" msgid="2554424863101358857">"Tidak dapat berkomunikasi dengan <xliff:g id="DEVICE_NAME">%1$s</xliff:g>."</string>
@@ -133,7 +133,7 @@
<string name="bluetooth_hearingaid_left_battery_level" msgid="7375621694748104876">"Kiri - baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="bluetooth_hearingaid_right_battery_level" msgid="1850094448499089312">"Kanan - baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
<string name="accessibility_wifi_off" msgid="1195445715254137155">"Wi-Fi tidak aktif."</string>
- <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak tersambung."</string>
+ <string name="accessibility_no_wifi" msgid="5297119459491085771">"Wi-Fi tidak terhubung."</string>
<string name="accessibility_wifi_one_bar" msgid="6025652717281815212">"Wi-Fi satu baris."</string>
<string name="accessibility_wifi_two_bars" msgid="687800024970972270">"Wi-Fi dua baris"</string>
<string name="accessibility_wifi_three_bars" msgid="779895671061950234">"Wi-Fi tiga baris."</string>
@@ -205,7 +205,7 @@
<string name="tethering_settings_not_available" msgid="266821736434699780">"Setelan Penambatan tidak tersedia untuk pengguna ini"</string>
<string name="apn_settings_not_available" msgid="1147111671403342300">"Setelan Nama Titik Akses tidak tersedia untuk pengguna ini"</string>
<string name="enable_adb" msgid="8072776357237289039">"Debugging USB"</string>
- <string name="enable_adb_summary" msgid="3711526030096574316">"Mode debug ketika USB tersambung"</string>
+ <string name="enable_adb_summary" msgid="3711526030096574316">"Mode debug ketika USB terhubung"</string>
<string name="clear_adb_keys" msgid="3010148733140369917">"Cabut otorisasi debug USB"</string>
<string name="enable_adb_wireless" msgid="6973226350963971018">"Proses debug nirkabel"</string>
<string name="enable_adb_wireless_summary" msgid="7344391423657093011">"Mode debug saat Wi-Fi terhubung"</string>
@@ -217,19 +217,19 @@
<string name="adb_pair_method_code_title" msgid="1122590300445142904">"Sambungkan perangkat dengan kode penyambungan"</string>
<string name="adb_pair_method_code_summary" msgid="6370414511333685185">"Sambungkan perangkat baru menggunakan kode enam digit"</string>
<string name="adb_paired_devices_title" msgid="5268997341526217362">"Perangkat disambungkan"</string>
- <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Saat ini tersambung"</string>
+ <string name="adb_wireless_device_connected_summary" msgid="3039660790249148713">"Saat ini terhubung"</string>
<string name="adb_wireless_device_details_title" msgid="7129369670526565786">"Detail perangkat"</string>
<string name="adb_device_forget" msgid="193072400783068417">"Lupakan"</string>
<string name="adb_device_fingerprint_title_format" msgid="291504822917843701">"Sidik jari perangkat: <xliff:g id="FINGERPRINT_PARAM">%1$s</xliff:g>"</string>
<string name="adb_wireless_connection_failed_title" msgid="664211177427438438">"Sambungan gagal"</string>
- <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Pastikan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> tersambung ke jaringan yang tepat"</string>
+ <string name="adb_wireless_connection_failed_message" msgid="9213896700171602073">"Pastikan <xliff:g id="DEVICE_NAME">%1$s</xliff:g> terhubung ke jaringan yang tepat"</string>
<string name="adb_pairing_device_dialog_title" msgid="7141739231018530210">"Sambungkan dengan perangkat"</string>
<string name="adb_pairing_device_dialog_pairing_code_label" msgid="3639239786669722731">"Kode penyambungan Wi-Fi"</string>
<string name="adb_pairing_device_dialog_failed_title" msgid="3426758947882091735">"Penyambungan perangkat gagal"</string>
<string name="adb_pairing_device_dialog_failed_msg" msgid="6611097519661997148">"Pastikan perangkat terhubung ke jaringan yang sama."</string>
<string name="adb_wireless_qrcode_summary" msgid="8051414549011801917">"Sambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string>
<string name="adb_wireless_verifying_qrcode_text" msgid="6123192424916029207">"Menyambungkan perangkat…"</string>
- <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menyambungkan perangkat. Kode QR salah, atau perangkat tidak tersambung ke jaringan yang sama."</string>
+ <string name="adb_qrcode_pairing_device_failed_msg" msgid="6936292092592914132">"Gagal menyambungkan perangkat. Kode QR salah, atau perangkat tidak terhubung ke jaringan yang sama."</string>
<string name="adb_wireless_ip_addr_preference_title" msgid="8335132107715311730">"Alamat IP & Port"</string>
<string name="adb_wireless_qrcode_pairing_title" msgid="1906409667944674707">"Memindai kode QR"</string>
<string name="adb_wireless_qrcode_pairing_description" msgid="6014121407143607851">"Sambungkan perangkat melalui Wi‑Fi dengan memindai Kode QR"</string>
@@ -335,7 +335,7 @@
<string name="pointer_location" msgid="7516929526199520173">"Lokasi penunjuk"</string>
<string name="pointer_location_summary" msgid="957120116989798464">"Hamparan layar menampilkan data sentuhan saat ini"</string>
<string name="show_touches" msgid="8437666942161289025">"Tampilkan ketukan"</string>
- <string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan masukan untuk ketukan"</string>
+ <string name="show_touches_summary" msgid="3692861665994502193">"Tampilkan efek visual untuk ketukan"</string>
<string name="show_screen_updates" msgid="2078782895825535494">"Lihat pembaruan permukaan"</string>
<string name="show_screen_updates_summary" msgid="2126932969682087406">"Sorot seluruh permukaan jendela saat diperbarui"</string>
<string name="show_hw_screen_updates" msgid="2021286231267747506">"Tampilkan update tampilan"</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 1c03e22..44f067c 100644
--- a/packages/SettingsLib/res/values-te/strings.xml
+++ b/packages/SettingsLib/res/values-te/strings.xml
@@ -89,7 +89,7 @@
<string name="bluetooth_profile_pan" msgid="1006235139308318188">"ఇంటర్నెట్ యాక్సెస్"</string>
<string name="bluetooth_profile_pbap" msgid="7064307749579335765">"కాంటాక్ట్ షేరింగ్"</string>
<string name="bluetooth_profile_pbap_summary" msgid="2955819694801952056">"కాంటాక్ట్ షేరింగ్ కోసం ఉపయోగించండి"</string>
- <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ భాగస్వామ్యం"</string>
+ <string name="bluetooth_profile_pan_nap" msgid="7871974753822470050">"ఇంటర్నెట్ కనెక్షన్ షేరింగ్"</string>
<string name="bluetooth_profile_map" msgid="8907204701162107271">"వచన మెసేజ్లు"</string>
<string name="bluetooth_profile_sap" msgid="8304170950447934386">"SIM యాక్సెస్"</string>
<string name="bluetooth_profile_a2dp_high_quality" msgid="4739440941324792775">"HD ఆడియో: <xliff:g id="CODEC_NAME">%1$s</xliff:g>"</string>
@@ -116,7 +116,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>
@@ -153,7 +153,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>
@@ -246,8 +246,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/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 90cec3f..4ac1938 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -763,9 +763,6 @@
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
GlobalSettingsProto.Gpu.ANGLE_GL_DRIVER_SELECTION_VALUES);
dumpSetting(s, p,
- Settings.Global.ANGLE_ALLOWLIST,
- GlobalSettingsProto.Gpu.ANGLE_ALLOWLIST);
- dumpSetting(s, p,
Settings.Global.ANGLE_EGL_FEATURES,
GlobalSettingsProto.Gpu.ANGLE_EGL_FEATURES);
dumpSetting(s, p,
@@ -1479,6 +1476,9 @@
Settings.Global.USE_OPEN_WIFI_PACKAGE,
GlobalSettingsProto.USE_OPEN_WIFI_PACKAGE);
dumpSetting(s, p,
+ Settings.Global.UWB_ENABLED,
+ GlobalSettingsProto.UWB_ENABLED);
+ dumpSetting(s, p,
Settings.Global.VT_IMS_ENABLED,
GlobalSettingsProto.VT_IMS_ENABLED);
dumpSetting(s, p,
diff --git a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
index 9362a18..4a896e7 100644
--- a/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
+++ b/packages/SettingsProvider/test/src/android/provider/SettingsBackupTest.java
@@ -508,7 +508,6 @@
Settings.Global.ANGLE_GL_DRIVER_ALL_ANGLE,
Settings.Global.ANGLE_GL_DRIVER_SELECTION_PKGS,
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES,
- Settings.Global.ANGLE_ALLOWLIST,
Settings.Global.ANGLE_EGL_FEATURES,
Settings.Global.UPDATABLE_DRIVER_ALL_APPS,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_OPT_IN_APPS,
@@ -518,6 +517,7 @@
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_DENYLIST,
Settings.Global.UPDATABLE_DRIVER_PRODUCTION_ALLOWLIST,
Settings.Global.UPDATABLE_DRIVER_SPHAL_LIBRARIES,
+ Settings.Global.UWB_ENABLED,
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX,
Settings.Global.GPU_DEBUG_LAYER_APP,
Settings.Global.ENABLE_GNSS_RAW_MEAS_FULL_TRACKING,
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/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 3cbe435..9c1e129 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -482,7 +482,7 @@
val endRadius = if (isExpandingFullyAbove) {
// Most of the time, expanding fully above the root view means expanding in full
// screen.
- ScreenDecorationsUtils.getWindowCornerRadius(context.resources)
+ ScreenDecorationsUtils.getWindowCornerRadius(context)
} else {
// This usually means we are in split screen mode, so 2 out of 4 corners will have
// a radius of 0.
diff --git a/packages/SystemUI/res/color/settingslib_state_off.xml b/packages/SystemUI/res/color/settingslib_state_off.xml
new file mode 100644
index 0000000..e821825
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_state_off.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentSecondaryVariant"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_state_on.xml b/packages/SystemUI/res/color/settingslib_state_on.xml
new file mode 100644
index 0000000..6d2133c
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_state_on.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentPrimary"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_track_off.xml b/packages/SystemUI/res/color/settingslib_track_off.xml
new file mode 100644
index 0000000..21d1dcc
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_track_off.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentSecondary"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/color/settingslib_track_on.xml b/packages/SystemUI/res/color/settingslib_track_on.xml
new file mode 100644
index 0000000..ba7848a
--- /dev/null
+++ b/packages/SystemUI/res/color/settingslib_track_on.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="utf-8"?>
+<selector xmlns:android="http://schemas.android.com/apk/res/android"
+ xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
+ <item android:color="?androidprv:attr/colorAccentPrimaryVariant"/>
+</selector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_media_home_devices.xml b/packages/SystemUI/res/drawable/ic_media_home_devices.xml
new file mode 100644
index 0000000..886c64d9
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_media_home_devices.xml
@@ -0,0 +1,16 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="24dp"
+ android:height="24dp"
+ android:viewportWidth="24"
+ android:viewportHeight="24"
+ android:tint="?attr/colorControlNormal">
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M20,4H4c-1.1,0 -2,0.9 -2,2v11c0,1.1 0.9,2 2,2h4v2h3v-4H4V6h16v1h2V6c0,-1.1 -0.9,-2 -2,-2z"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M17.5,16.5m-2.33,0a2.33,2.33 0,1 1,4.66 0a2.33,2.33 0,1 1,-4.66 0"/>
+ <path
+ android:fillColor="@android:color/white"
+ android:pathData="M21,8h-7c-0.55,0 -1,0.45 -1,1v11c0,0.55 0.45,1 1,1h7c0.55,0 1,-0.45 1,-1L22,9c0,-0.55 -0.45,-1 -1,-1zM17.5,9c0.83,0 1.5,0.67 1.5,1.5s-0.67,1.5 -1.5,1.5 -1.5,-0.67 -1.5,-1.5 0.67,-1.5 1.5,-1.5zM17.5,20c-1.93,0 -3.5,-1.57 -3.5,-3.5s1.57,-3.5 3.5,-3.5 3.5,1.57 3.5,3.5 -1.57,3.5 -3.5,3.5z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml b/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml
new file mode 100644
index 0000000..5cc8d6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_corner_bottom_secondary.xml
@@ -0,0 +1,16 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ 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.
+-->
+<!-- Overlay this resource to change rounded_corners_bottom -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/rounded_secondary"/>
diff --git a/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml b/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml
new file mode 100644
index 0000000..724e3ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_corner_top_secondary.xml
@@ -0,0 +1,16 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ 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.
+-->
+<!-- Overlay this resource to change rounded_corners_top -->
+<inset xmlns:android="http://schemas.android.com/apk/res/android"
+ android:drawable="@drawable/rounded_secondary"/>
diff --git a/packages/SystemUI/res/drawable/rounded_secondary.xml b/packages/SystemUI/res/drawable/rounded_secondary.xml
new file mode 100644
index 0000000..eb72fa1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/rounded_secondary.xml
@@ -0,0 +1,24 @@
+<!--
+ Copyright (C) 2021 The Android Open Source Project
+
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+ android:width="8dp"
+ android:height="8dp"
+ android:viewportWidth="8"
+ android:viewportHeight="8">
+
+ <path
+ android:fillColor="#000000"
+ android:pathData="M8,0H0v8C0,3.6,3.6,0,8,0z" />
+
+</vector>
diff --git a/packages/SystemUI/res/layout/global_screenshot_static.xml b/packages/SystemUI/res/layout/global_screenshot_static.xml
index e4a9694..6a9254c 100644
--- a/packages/SystemUI/res/layout/global_screenshot_static.xml
+++ b/packages/SystemUI/res/layout/global_screenshot_static.xml
@@ -36,7 +36,6 @@
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginEnd="@dimen/screenshot_action_container_margin_horizontal"
- android:layout_marginBottom="@dimen/screenshot_action_container_offset_y"
android:paddingEnd="@dimen/screenshot_action_container_padding_right"
android:paddingVertical="@dimen/screenshot_action_container_padding_vertical"
android:elevation="1dp"
diff --git a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
index 5b58fe8..b841419 100644
--- a/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
+++ b/packages/SystemUI/res/layout/internet_connectivity_dialog.xml
@@ -30,7 +30,7 @@
style="@style/Widget.SliceView.Panel"
android:gravity="center_vertical|center_horizontal"
android:layout_marginTop="24dp"
- android:layout_marginBottom="16dp"
+ android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
android:orientation="vertical">
<TextView
@@ -57,7 +57,7 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginBottom="16dp"
+ android:layout_marginBottom="@dimen/internet_dialog_network_layout_margin"
android:orientation="vertical">
<View
@@ -101,8 +101,8 @@
android:background="?android:attr/selectableItemBackground"
android:layout_gravity="center_vertical|start"
android:orientation="horizontal"
- android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
- android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+ android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
android:paddingStart="22dp"
android:paddingEnd="22dp">
@@ -130,24 +130,24 @@
<TextView
android:id="@+id/mobile_title"
android:textDirection="locale"
- android:layout_marginStart="16dp"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+ android:layout_marginEnd="7dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="16sp"
android:fontFamily="google-sans"/>
<TextView
android:id="@+id/mobile_summary"
android:textDirection="locale"
- android:layout_marginStart="16dp"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+ android:layout_marginEnd="34dp"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
@@ -179,8 +179,8 @@
android:background="?android:attr/selectableItemBackground"
android:gravity="center"
android:orientation="horizontal"
- android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
- android:layout_marginStart="@dimen/settingslib_switchbar_margin"
+ android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
android:paddingStart="22dp"
android:paddingEnd="22dp">
@@ -191,6 +191,7 @@
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
+ android:id="@+id/wifi_toggle_title"
android:text="@string/turn_on_wifi"
android:textDirection="locale"
android:layout_width="wrap_content"
@@ -229,10 +230,10 @@
android:visibility="gone"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
- android:layout_marginEnd="@dimen/settingslib_switchbar_margin"
- android:layout_marginStart="@dimen/settingslib_switchbar_margin"
- android:paddingStart="22dp"
- android:paddingEnd="22dp">
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
+ android:layout_marginEnd="@dimen/internet_dialog_network_layout_margin"
+ android:paddingStart="20dp"
+ android:paddingEnd="24dp">
<FrameLayout
android:layout_width="24dp"
@@ -247,12 +248,13 @@
</FrameLayout>
<LinearLayout
- android:layout_weight="3"
android:id="@+id/wifi_connected_list"
android:orientation="vertical"
android:clickable="false"
android:layout_width="wrap_content"
android:layout_height="72dp"
+ android:layout_marginEnd="30dp"
+ android:layout_weight="1"
android:gravity="start|center_vertical">
<TextView
android:id="@+id/wifi_connected_title"
@@ -260,9 +262,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
@@ -272,9 +273,8 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorTertiary"
android:textSize="14sp"
android:fontFamily="google-sans"/>
@@ -283,14 +283,14 @@
<FrameLayout
android:layout_width="24dp"
android:layout_height="match_parent"
- android:layout_marginEnd="5dp"
android:clickable="false"
+ android:layout_gravity="end|center_vertical"
android:gravity="center">
<ImageView
android:id="@+id/wifi_settings_icon"
android:src="@drawable/ic_settings_24dp"
android:layout_width="24dp"
- android:layout_gravity="center"
+ android:layout_gravity="end|center_vertical"
android:layout_height="wrap_content"/>
</FrameLayout>
@@ -323,7 +323,7 @@
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp">
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
<ImageView
android:id="@+id/arrow_forward"
android:src="@drawable/ic_arrow_forward"
@@ -337,7 +337,7 @@
android:clickable="false"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_marginStart="16dp">
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
<TextView
android:text="@string/see_all_networks"
android:textDirection="locale"
diff --git a/packages/SystemUI/res/layout/internet_list_item.xml b/packages/SystemUI/res/layout/internet_list_item.xml
index 19b1ef9..05352c5 100644
--- a/packages/SystemUI/res/layout/internet_list_item.xml
+++ b/packages/SystemUI/res/layout/internet_list_item.xml
@@ -31,15 +31,14 @@
android:focusable="true"
android:background="?android:attr/selectableItemBackground"
android:orientation="horizontal"
- android:paddingStart="22dp"
- android:paddingEnd="22dp">
-
+ android:paddingStart="20dp"
+ android:paddingEnd="40dp">
<FrameLayout
android:layout_width="24dp"
android:layout_height="24dp"
android:clickable="false"
android:layout_gravity="center_vertical|start"
- android:layout_marginStart="16dp">
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
<ImageView
android:id="@+id/wifi_icon"
android:layout_width="wrap_content"
@@ -48,52 +47,47 @@
</FrameLayout>
<LinearLayout
- android:layout_weight="3"
android:id="@+id/wifi_network_layout"
android:orientation="vertical"
android:clickable="false"
android:layout_width="wrap_content"
- android:layout_height="72dp">
+ android:layout_height="72dp"
+ android:layout_weight="1"
+ android:gravity="start|center_vertical"
+ android:layout_marginStart="@dimen/internet_dialog_network_layout_margin">
<TextView
android:id="@+id/wifi_title"
android:textDirection="locale"
- android:layout_weight="1"
android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_gravity="center_vertical|start"
+ android:layout_height="20dp"
android:gravity="start|center_vertical"
- android:layout_marginStart="16dp"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorPrimary"
android:textSize="14sp"
- android:fontFamily="google-sans"/>
+ android:fontFamily="google-sans"
+ android:layout_marginEnd="18dp"/>
<TextView
android:id="@+id/wifi_summary"
android:textDirection="locale"
- android:layout_weight="1"
android:layout_width="wrap_content"
- android:layout_height="0dp"
- android:layout_gravity="center_vertical|start"
+ android:layout_height="wrap_content"
android:gravity="start|center_vertical"
- android:layout_marginStart="16dp"
android:ellipsize="end"
- android:maxLines="1"
android:textColor="?android:attr/textColorSecondary"
android:textSize="14sp"
- android:fontFamily="google-sans"/>
+ android:fontFamily="google-sans"
+ android:layout_marginEnd="18dp"/>
</LinearLayout>
<FrameLayout
android:layout_width="24dp"
android:layout_height="match_parent"
- android:layout_marginEnd="@dimen/settingslib_switchbar_padding_right"
android:clickable="false"
- android:gravity="center">
+ android:layout_gravity="end|center_vertical">
<ImageView
- android:id="@+id/wifi_locked_icon"
+ android:id="@+id/wifi_end_icon"
+ android:layout_gravity="end|center_vertical"
android:layout_width="wrap_content"
- android:layout_gravity="center"
android:layout_height="wrap_content"/>
</FrameLayout>
diff --git a/packages/SystemUI/res/layout/media_view.xml b/packages/SystemUI/res/layout/media_view.xml
index 075473a..566cd25 100644
--- a/packages/SystemUI/res/layout/media_view.xml
+++ b/packages/SystemUI/res/layout/media_view.xml
@@ -163,18 +163,6 @@
</LinearLayout>
</LinearLayout>
- <ImageView
- android:id="@+id/media_seamless_fallback"
- android:layout_width="@dimen/qs_seamless_fallback_icon_size"
- android:layout_height="@dimen/qs_seamless_fallback_icon_size"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginStart="@dimen/qs_center_guideline_padding"
- android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
- android:tint="?android:attr/textColor"
- android:src="@drawable/ic_cast_connected"
- android:forceHasOverlappingRendering="false" />
-
<!-- Seek Bar -->
<!-- As per Material Design on Biderectionality, this is forced to LTR in code -->
<SeekBar
diff --git a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
index cc44b5e..b1e8c38 100644
--- a/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
+++ b/packages/SystemUI/res/layout/quick_status_bar_header_date_privacy.xml
@@ -49,6 +49,11 @@
/>
</FrameLayout>
+ <!-- We want this to be centered (to align with notches). In order to do that, the following
+ has to hold (in portrait):
+ * date_container and privacy_container must have the same width and weight
+ * header_text_container must be gone
+ -->
<android.widget.Space
android:id="@+id/space"
android:layout_width="0dp"
@@ -75,7 +80,7 @@
android:layout_weight="1"
android:gravity="center_vertical|end" >
- <include layout="@layout/ongoing_privacy_chip" />
+ <include layout="@layout/ongoing_privacy_chip" />
</FrameLayout>
</LinearLayout>
diff --git a/packages/SystemUI/res/layout/screen_record_dialog.xml b/packages/SystemUI/res/layout/screen_record_dialog.xml
index d1cc01f..c122829 100644
--- a/packages/SystemUI/res/layout/screen_record_dialog.xml
+++ b/packages/SystemUI/res/layout/screen_record_dialog.xml
@@ -113,6 +113,8 @@
android:layout_height="wrap_content"
android:minHeight="48dp"
android:layout_weight="1"
+ android:layout_gravity="fill_vertical"
+ android:gravity="center_vertical"
android:text="@string/screenrecord_taps_label"
android:textAppearance="?android:attr/textAppearanceMedium"
android:fontFamily="@*android:string/config_headlineFontFamily"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index d31d1df..4355751 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -115,6 +115,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/layout/udfps_enroll_view.xml b/packages/SystemUI/res/layout/udfps_enroll_view.xml
index f1ff6d6..e41a632 100644
--- a/packages/SystemUI/res/layout/udfps_enroll_view.xml
+++ b/packages/SystemUI/res/layout/udfps_enroll_view.xml
@@ -20,10 +20,23 @@
android:layout_width="match_parent"
android:layout_height="match_parent">
+ <!-- The layout height/width are placeholders, which will be overwritten by
+ FingerprintSensorPropertiesInternal. -->
+ <View
+ android:id="@+id/udfps_enroll_accessibility_view"
+ android:layout_gravity="center"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:contentDescription="@string/accessibility_fingerprint_label"/>
+
+ <ImageView
+ android:id="@+id/udfps_enroll_animation_fp_progress_view"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+
<!-- Fingerprint -->
<ImageView
android:id="@+id/udfps_enroll_animation_fp_view"
android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:contentDescription="@string/accessibility_fingerprint_label"/>
+ android:layout_height="match_parent"/>
</com.android.systemui.biometrics.UdfpsEnrollView>
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index b88962d..6d2bc31 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om oop te maak"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Stawing word vereis. Raak die vingerafdruksensor om te staaf."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Oproep aan die gang"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Gekoppel"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data sal nie outomaties koppel nie"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding nie"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen ander netwerke beskikbaar nie"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerke beskikbaar nie"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkbesonderhede"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op \'n netwerk om te koppel"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontsluit om netwerke te bekyk"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Soek tans na netwerke …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kon nie aan netwerk koppel nie"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Sien alles"</string>
</resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 1110c99..e9a971e 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ለመክፈት የጣት አሻራ ይጠቀሙ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ማረጋገጥ ያስፈልጋል። ለማረጋገጥ የጣት አሻራ ዳሳሹን ይንኩ።"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"በመካሄድ ላይ የስልክ ጥሪ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"የተንቀሳቃሽ ስልክ ውሂብ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ተገናኝቷል"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ግንኙነት የለም"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ሌላ አውታረ መረብ የሉም"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ምንም አውታረ መረቦች የሉም"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"የአውታረ መረብ ዝርዝሮች"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ለመገናኘት አንድ አውታረ መረብ መታ ያድርጉ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"አውታረ መረቦችን ለመመልከት ይክፈቱ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 6d66748..3f8b895 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -1186,4 +1186,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"يمكنك استخدام بصمة الإصبع للفتح"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"المصادقة مطلوبة. المس مستشعر بصمات الإصبع للمصادقة."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"مكالمة هاتفية جارية"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"بيانات الجوّال"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"متصلة بالإنترنت"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"لن يتم تلقائيًا الاتصال ببيانات الجوّال."</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"لا يتوفّر اتصال بالإنترنت"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"لا تتوفّر شبكات أخرى."</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"لا تتوفّر أي شبكات."</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"تفاصيل الشبكة"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"انقر على إحدى الشبكات للاتصال بالإنترنت"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"فتح القفل لعرض الشبكات"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index ee9ae88..d274dbe 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>
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলিবলৈ ফিংগাৰপ্ৰিণ্ট ব্যৱহাৰ কৰক"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"বিশ্বাসযোগ্যতা প্ৰমাণীকৰণৰ আৱশ্যক। বিশ্বাসযোগ্যতা প্ৰমাণীকৰণ কৰিবলৈ ফিংগাৰপ্ৰিণ্ট ছেন্সৰটো স্পৰ্শ কৰক।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"চলি থকা ফ’ন কল"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ম’বাইল ডেটা"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"সংযোজিত হৈ আছে"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"সংযোগ নাই"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"কোনো নেটৱৰ্ক উপলব্ধ নহয়"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ৱাই-ফাই"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"নেটৱৰ্কৰ সবিশেষ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"সংযোগ কৰিবলৈ এটা নেটৱৰ্কত টিপক"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটৱর্ক চাবলৈ আনলক কৰক"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index 6779834..1d33d1e 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmaq üçün barmaq izindən istifadə edin"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Doğrulanma tələb olunur. Doğrulamaq üçün barmaq izi sensoruna toxunun."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Davam edən zəng"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Qoşulub"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil data avtomatik qoşulmayacaq"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yoxdur"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Heç bir başqa şəbəkə əlçatan deyil"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Əlçatan şəbəkə yoxdur"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Şəbəkə məlumatları"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Qoşulmaq üçün şəbəkəyə toxunun"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Şəbəkələrə baxmaq üçün kilidi açın"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Şəbəkə axtarılır…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Şəbəkəyə qoşulmaq alınmadı"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Hamısına baxın"</string>
</resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 607391a..50fc2af 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -1014,7 +1014,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Aplikacije koriste <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Koristi <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Koristi: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Nedavno koristio/la <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(posao)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Telefonski poziv"</string>
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je potvrda identiteta. Dodirnite senzor za otisak prsta da biste potvrdili identitet."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktuelni telefonski poziv"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nije uspelo autom. povezivanje preko mob. podataka"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Veza nije uspostavljena"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da biste videli mreže"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traže se mreže…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje sa mrežom nije uspelo"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Pogledajte sve"</string>
</resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index d4954c1..a7be305 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Каб адкрыць, скарыстайце адбітак пальца"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Патрабуецца аўтэнтыфікацыя. Дакраніцеся да сканера адбіткаў пальцаў."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Бягучы тэлефонны выклік"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мабільная перадача даных"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Падключана"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мабільная перадача даных не ўключаецца аўтаматычна"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма падключэння"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Больш няма даступных сетак"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Няма даступных сетак"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Інфармацыя пра сетку"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Каб падключыцца, націсніце на сетку"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблакіраваць для прагляду сетак"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index b938880..34a8b92 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Използвайте отпечатък за отваряне"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Изисква се удостоверяване на самоличността. За целта докоснете сензора за отпечатъци."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущо телефонно обаждане"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни данни"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Свързано"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Връзката за мобилни данни няма да е автоматична"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Няма връзка"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Няма други налични мрежи"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Няма налични мрежи"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Подробности за мрежата"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Докоснете мрежа, за да се свържете"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отключване с цел преглед на мрежите"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 811b6a5..4213665 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"খুলতে ফিঙ্গারপ্রিন্ট ব্যবহার করুন"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"যাচাইকরণ করতে হবে। যাচাইকরণ করতে আঙুলের ছাপের সেন্সরে টাচ করুন।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ব্যবহারকারী এখন ফোনে কথা বলছেন"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"মোবাইল ডেটা"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"কানেক্ট করা আছে"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"কানেকশন নেই"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"অন্য কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"কোনও নেটওয়ার্ক উপলভ্য নেই"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ওয়াই-ফাই"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"নেটওয়ার্কের বিবরণ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"কানেক্ট করতে একটি নেটওয়ার্কে ট্যাপ করুন"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"নেটওয়ার্ক দেখার জন্য আনলক করুন"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index d326a51..990295f 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor za otisak prsta da autentificirate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u toku"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prijenos podataka na mobilnoj mreži"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Prijenos podataka se neće automatski povezati"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani s mrežom"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Druge mreže nisu dostupne"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalji o mreži"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da se povežete"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte da vidite mreže"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 4315057..9be892a 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -1009,7 +1009,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Algunes aplicacions estan fent servir el següent: <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" i "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En ús per <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"<xliff:g id="APPLICATION_NAME">%1$s</xliff:g> ho està utilitzant"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Utilitzat recentment per <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(feina)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Trucada"</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilitza l\'empremta digital per obrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticació necessària. Toca el sensor d\'empremtes digitals per autenticar-te."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Trucada en curs"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dades mòbils"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connectat"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Les dades mòbils no es connectaran automàticament"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sense connexió"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hi ha cap altra xarxa disponible"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No hi ha cap xarxa disponible"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalls de la xarxa"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una xarxa per connectar-te"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueja per veure xarxes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"S\'estan cercant xarxes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No s\'ha pogut connectar a la xarxa"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Mostra-ho tot"</string>
</resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 1cac5f7..4b02201 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"K otevření použijte otisk prstu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Je vyžadováno ověření. Dotkněte se snímače otisků prstů."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Probíhající hovor"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilní data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Připojeno"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilní data se nebudou připojovat automaticky"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Žádné připojení"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Žádné další sítě nejsou k dispozici"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nejsou k dispozici žádné sítě"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti sítě"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Klepněte na síť, ke které se chcete připojit"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sítě uvidíte po odemknutí"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhledávání sítí…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Připojení k síti se nezdařilo"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Zobrazit vše"</string>
</resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 48f8086..298438d 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -384,7 +384,7 @@
<string name="quick_settings_cast_no_wifi" msgid="6980194769795014875">"Manglende Wi-Fi-forbindelse"</string>
<string name="quick_settings_brightness_dialog_title" msgid="4980669966716685588">"Lysstyrke"</string>
<string name="quick_settings_brightness_dialog_auto_brightness_label" msgid="2325362583903258677">"AUTO"</string>
- <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Byt om på farver"</string>
+ <string name="quick_settings_inversion_label" msgid="5078769633069667698">"Ombyt farver"</string>
<string name="quick_settings_color_space_label" msgid="537528291083575559">"Farvekorrigeringstilstand"</string>
<string name="quick_settings_more_settings" msgid="2878235926753776694">"Flere indstillinger"</string>
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Brugerindstillinger"</string>
@@ -678,8 +678,8 @@
<string name="wallet_lockscreen_settings_label" msgid="3539105300870383570">"Lås skærmindstillinger"</string>
<string name="status_bar_work" msgid="5238641949837091056">"Arbejdsprofil"</string>
<string name="status_bar_airplane" msgid="4848702508684541009">"Flytilstand"</string>
- <string name="add_tile" msgid="6239678623873086686">"Tilføj et felt"</string>
- <string name="broadcast_tile" msgid="5224010633596487481">"Broadcast-ikon"</string>
+ <string name="add_tile" msgid="6239678623873086686">"Tilføj felt"</string>
+ <string name="broadcast_tile" msgid="5224010633596487481">"Broadcast-felt"</string>
<string name="zen_alarm_warning_indef" msgid="5252866591716504287">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>, medmindre du slår funktionen fra inden da"</string>
<string name="zen_alarm_warning" msgid="7844303238486849503">"Du vil ikke kunne høre din næste alarm <xliff:g id="WHEN">%1$s</xliff:g>"</string>
<string name="alarm_template" msgid="2234991538018805736">"kl. <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -911,15 +911,15 @@
</string-array>
<string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for notifikationer med lav prioritet"</string>
<string name="other" msgid="429768510980739978">"Andet"</string>
- <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern kortet"</string>
- <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj kortet til slutningen"</string>
- <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt kortet"</string>
- <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj et kort"</string>
+ <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern felt"</string>
+ <string name="accessibility_qs_edit_tile_add_action" msgid="5051211910345301833">"føj feltet til slutningen"</string>
+ <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt felt"</string>
+ <string name="accessibility_qs_edit_tile_start_add" msgid="7560798153975555772">"Tilføj felt"</string>
<string name="accessibility_qs_edit_tile_move_to_position" msgid="5198161544045930556">"Flyt til <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Placering <xliff:g id="POSITION">%1$d</xliff:g>"</string>
- <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet blev tilføjet"</string>
- <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet blev fjernet"</string>
+ <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Feltet blev tilføjet"</string>
+ <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Feltet blev fjernet"</string>
<string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g>-notifikation: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Åbn Indstillinger."</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Brug fingeraftryk for at åbne"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Godkendelse er påkrævet. Sæt fingeren på fingeraftrykslæseren for at godkende."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Igangværende telefonopkald"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Forbundet"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Der oprettes ikke automatisk mobildataforbindelse"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Der er ingen forbindelse"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Der er ingen andre tilgængelige netværk"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Der er ingen tilgængelige netværk"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Netværksoplysninger"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryk på et netværk for at oprette forbindelse"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås op for at se netværk"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søger efter netværk…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Der kunne ikke oprettes forbindelse til netværket"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
</resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4c4a876..8349368 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Mit Fingerabdruck öffnen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentifizierung erforderlich. Tippe dazu einfach auf den Fingerabdrucksensor."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktiver Anruf"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile Daten"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbunden"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Keine Verbindung"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Keine anderen Netzwerke verfügbar"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Keine Netzwerke verfügbar"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Netzwerkdetails"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tippe auf ein Netzwerk, um eine Verbindung herzustellen"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Entsperren, um Netzwerke anzuzeigen"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netzwerke werden gesucht…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Netzwerkverbindung konnte nicht hergestellt werden"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Alle ansehen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 0b37ed8..7226a85 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Χρήση δακτυλικού αποτυπώματος για άνοιγμα"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Απαιτείται έλεγχος ταυτότητας. Αγγίξτε τον αισθητήρα δακτυλικών αποτυπωμάτων για έλεγχο ταυτότητας."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Τηλεφωνική κλήση σε εξέλιξη"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Δεδομένα κινητής τηλεφωνίας"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Συνδέθηκε"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Χωρίς αυτόματη σύνδεση δεδομένων κινητ. τηλεφωνίας"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Χωρίς σύνδεση"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Δεν υπάρχουν άλλα διαθέσιμα δίκτυα"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Δεν υπάρχουν διαθέσιμα δίκτυα"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Λεπτομέρειες δικτύου"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Πατήστε ένα δίκτυο για να συνδεθείτε"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ξεκλειδώστε για προβολή δικτύων"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index e50c00e..427a7a9 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index fba313e..c684fa4 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index e50c00e..427a7a9 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index e50c00e..427a7a9 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
</resources>
diff --git a/packages/SystemUI/res/values-en-rXC/strings.xml b/packages/SystemUI/res/values-en-rXC/strings.xml
index a42a531..b6c78ec 100644
--- a/packages/SystemUI/res/values-en-rXC/strings.xml
+++ b/packages/SystemUI/res/values-en-rXC/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use fingerprint to open"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentication required. Touch the fingerprint sensor to authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ongoing phone call"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connected"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobile data won\'t auto‑connect"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"No connection"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No other networks available"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No networks available"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Network details"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tap a network to connect"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Unlock to view networks"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Searching for networks…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Failed to connect to network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"See all"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 9929020..0a39ddb 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella dactilar para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Se requiere de una autenticación. Toca el sensor de huellas dactilares para autenticarte."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conexión establecida"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"No se conectarán automáticamente los datos móviles"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Presiona una red para conectarte a ella"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver las redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Se produjo un error al establecer conexión con la red"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
index 5634f79..4f738c5 100644
--- a/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/tiles_states_strings.xml
@@ -58,8 +58,8 @@
</string-array>
<string-array name="tile_states_flashlight">
<item msgid="3465257127433353857">"No disponible"</item>
- <item msgid="5044688398303285224">"Desactivado"</item>
- <item msgid="8527389108867454098">"Activado"</item>
+ <item msgid="5044688398303285224">"Desactivada"</item>
+ <item msgid="8527389108867454098">"Activada"</item>
</string-array>
<string-array name="tile_states_rotation">
<item msgid="4578491772376121579">"No disponible"</item>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 6a42460..74ad8ed 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa la huella digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticación obligatoria. Toca el sensor de huellas digitales para autenticarte."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Llamada en curso"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móviles"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Los datos móviles no se conectarán automáticamente"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sin conexión"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"No hay otras redes disponibles"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"No hay redes disponibles"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles de la red"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca una red para conectarte"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea para ver redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"No se ha podido conectar a la red"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 10becfb..2032118 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Kasutage avamiseks sõrmejälge"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vajalik on autentimine. Puudutage autentimiseks sõrmejäljeandurit."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Käimasolev telefonikõne"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilne andmeside"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ühendatud"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilset andmesideühendust ei looda automaatselt"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ühendus puudub"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ühtegi muud võrku pole saadaval"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Ühtegi võrku pole saadaval"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Võrgu üksikasjad"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Puudutage ühendamiseks võrku"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Võrkude vaatamiseks avage"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Võrkude otsimine …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Võrguühenduse loomine ebaõnnestus"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Kuva kõik"</string>
</resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 3dbbc07..d3b65fb 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Erabili hatz-marka irekitzeko"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentifikazioa behar da. Autentifikatzeko, ukitu hatz-marken sentsorea."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefono-dei bat abian da"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datu-konexioa"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> (<xliff:g id="NETWORKMODE">%2$s</xliff:g>)"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Konektatuta"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Ez da automatikoki aktibatuko datu-konexioa"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Konexiorik gabe"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ez dago beste sare erabilgarririk"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Ez dago sare erabilgarririk"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wifia"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Sarearen xehetasunak"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Sakatu sare bat hartara konektatzeko"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sareak ikusteko, desblokeatu pantaila"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Sareak bilatzen…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ezin izan da konektatu sarera"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ikusi guztiak"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 4606ae7..5561491 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"از اثر انگشت برای باز کردن قفل استفاده کنید"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"اصالتسنجی لازم است. برای اصالتسنجی، حسگر اثر انگشت را لمس کنید."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"تماس تلفنی درحال انجام"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"داده تلفن همراه"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"متصل است"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"داده تلفن همراه بهطور خودکار متصل نخواهد شد"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"اتصال برقرار نیست"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"شبکه دیگری وجود ندارد"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"شبکهای در دسترس نیست"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"جزئیات شبکه"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"برای اتصال به شبکه روی آن ضربه بزنید"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"برای مشاهده شبکهها، قفل صفحه را باز کنید"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 9d9b152..1bed14b 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -861,7 +861,7 @@
<string name="accessibility_status_bar_headset" msgid="2699275863720926104">"Kuulokemikrofoni liitetty"</string>
<string name="data_saver" msgid="3484013368530820763">"Data Saver"</string>
<string name="accessibility_data_saver_on" msgid="5394743820189757731">"Data Saver on käytössä."</string>
- <string name="accessibility_data_saver_off" msgid="58339669022107171">"Data Saver on pois käytöstä."</string>
+ <string name="accessibility_data_saver_off" msgid="58339669022107171">"Data Saver on pois päältä."</string>
<string name="switch_bar_on" msgid="1770868129120096114">"Päällä"</string>
<string name="switch_bar_off" msgid="5669805115416379556">"Pois päältä"</string>
<string name="tile_unavailable" msgid="3095879009136616920">"Ei käytettävissä"</string>
@@ -976,9 +976,9 @@
<string name="mobile_data" msgid="4564407557775397216">"Mobiilitiedonsiirto"</string>
<string name="mobile_data_text_format" msgid="6806501540022589786">"<xliff:g id="ID_1">%1$s</xliff:g> – <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="mobile_carrier_text_format" msgid="8912204177152950766">"<xliff:g id="CARRIER_NAME">%1$s</xliff:g>, <xliff:g id="MOBILE_DATA_TYPE">%2$s</xliff:g>"</string>
- <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois käytöstä"</string>
+ <string name="wifi_is_off" msgid="5389597396308001471">"Wi-Fi on pois päältä"</string>
<string name="bt_is_off" msgid="7436344904889461591">"Bluetooth ei ole käytössä"</string>
- <string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois käytöstä"</string>
+ <string name="dnd_is_off" msgid="3185706903793094463">"Älä häiritse ‑tila on pois päältä"</string>
<string name="qs_dnd_prompt_auto_rule" msgid="3535469468310002616">"Automaattinen sääntö otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_app" msgid="4027984447935396820">"Sovellus otti käyttöön Älä häiritse ‑tilan (<xliff:g id="ID_1">%s</xliff:g>)."</string>
<string name="qs_dnd_prompt_auto_rule_app" msgid="1841469944118486580">"Automaattinen sääntö tai sovellus otti käyttöön Älä häiritse ‑tilan."</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Avaa sormenjäljellä"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Todennus vaaditaan. Todenna koskettamalla sormenjälkitunnistinta."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Puhelu käynnissä"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiilidata"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Yhdistetty"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiilidata ei yhdisty automaattisesti"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ei yhteyttä"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ei muita verkkoja käytettävissä"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Ei verkkoja käytettävissä"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Verkon tiedot"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Muodosta yhteys napauttamalla verkkoa"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Avaa lukitus nähdäksesi verkot"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Etsitään verkkoja…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yhteyden muodostaminen verkkoon epäonnistui"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Näytä kaikki"</string>
</resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 22e77a0..c612917 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>
@@ -1010,7 +1009,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Des applications utilisent votre <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" et "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En cours d\'utilisation par <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En cours d\'utilisation par : <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Récemment utilisé par <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(travail)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Appel téléphonique"</string>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Servez-vous de votre empreinte digitale pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Touchez le capteur d\'empreintes digitales pour vous authentifier."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours…"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données cellulaires"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connexion active"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau n\'est accessible"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau n\'est accessible"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Touchez un réseau pour vous y connecter"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouillez l\'écran pour afficher les réseaux Wi-Fi"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 5510ef1..e7d0beb 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilisez votre empreinte pour ouvrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Authentification requise. Appuyez sur le lecteur d\'empreintes digitales pour vous authentifier."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Appel téléphonique en cours"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Données mobiles"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connecté"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Pas de connexion automatique des données mobiles"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Aucune connexion"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Aucun autre réseau disponible"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Aucun réseau disponible"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Détails du réseau"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Appuyez sur un réseau pour vous connecter"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Déverrouiller pour afficher les réseaux"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Recherche de réseaux…"</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>
</resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index a9f0593..ec3e5e0 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -1009,7 +1009,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Hai aplicacións que están utilizando <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" e "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Opción en uso por <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"En uso por: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Opción usada recentemente por <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(traballo)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Chamada de teléfono"</string>
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa a impresión dixital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Requírese autenticación. Para autenticarte, toca o sensor de impresión dixital."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica en curso"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Datos móbiles"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectada"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sen conexión"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Non hai outras redes dispoñibles"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Non hai redes dispoñibles"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalles da rede"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toca unha rede para conectarte a ela"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloquea a pantalla para ver as redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Buscando redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Produciuse un erro ao conectarse á rede"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver todo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 9f05de5..a6545e4 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ખોલવા માટે ફિંગરપ્રિન્ટનો ઉપયોગ કરો"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"પ્રમાણીકરણ આવશ્યક છે. પ્રમાણિત કરવા માટે ફિંગરપ્રિન્ટ સેન્સરને ટચ કરો."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ફોન કૉલ ચાલુ છે"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"મોબાઇલ ડેટા"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"કનેક્ટ કરેલું"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"કોઈ કનેક્શન નથી"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"બીજાં કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"કોઈ નેટવર્ક ઉપલબ્ધ નથી"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"વાઇ-ફાઇ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"નેટવર્કની વિગતો"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"કનેક્ટ કરવા માટે નેટવર્ક પર ટૅપ કરો"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"વાઇ-ફાઇ નેટવર્ક જોવા માટે અનલૉક કરો"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index ffe3a5b..525482f 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>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"खोलने के लिए, फ़िंगरप्रिंट का इस्तेमाल करें"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि करना ज़रूरी है. पुष्टि करने के लिए, फ़िंगरप्रिंट सेंसर को छुएं."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फ़ोन कॉल चल रहा है"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट हो गया"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा अपने-आप कनेक्ट नहीं होगा"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"इंटरनेट कनेक्शन नहीं है"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"कोई दूसरा नेटवर्क उपलब्ध नहीं है"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"कोई नेटवर्क उपलब्ध नहीं है"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"वाई-फ़ाई"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्क की जानकारी"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इंटरनेट से कनेक्ट करने के लिए, किसी नेटवर्क पर टैप करें"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"वाई-फ़ाई नेटवर्क देखने के लिए, स्क्रीन को अनलॉक करें"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 260dba9..9d7ac2f 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorite pomoću otiska prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Potrebna je autentifikacija. Dodirnite senzor otiska prsta da biste se autentificirali."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonski poziv u tijeku"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilni podaci"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilni podaci neće se automatski povezati"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Niste povezani"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nije dostupna nijedna druga mreža"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nema dostupnih mreža"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Pojedinosti o mreži"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Dodirnite mrežu da biste se povezali"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Otključajte za prikaz mreža"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Traženje mreža…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Povezivanje s mrežom nije uspjelo"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Prikaži sve"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 4a71826..1452988 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -354,7 +354,7 @@
<string name="quick_settings_ime_label" msgid="3351174938144332051">"Beviteli módszer"</string>
<string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
<string name="quick_settings_location_off_label" msgid="7923929131443915919">"Hely kikapcsolva"</string>
- <string name="quick_settings_camera_label" msgid="5612076679385269339">"Kameraelérés"</string>
+ <string name="quick_settings_camera_label" msgid="5612076679385269339">"Hozzáférés a kamerához"</string>
<string name="quick_settings_mic_label" msgid="8392773746295266375">"Mikrofonelérés"</string>
<string name="quick_settings_camera_mic_available" msgid="1453719768420394314">"Rendelkezésre áll"</string>
<string name="quick_settings_camera_mic_blocked" msgid="4710884905006788281">"Letiltva"</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ujjlenyomat használata a megnyitáshoz"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Hitelesítés szükséges. Érintse meg az ujjlenyomat-érzékelőt a hitelesítéshez."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Folyamatban lévő telefonhívás"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiladat"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g>/<xliff:g id="STATE">%1$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Csatlakozva"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nincs automatikus mobiladat-kapcsolat"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nincs kapcsolat"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nincs több rendelkezésre álló hálózat"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nincs rendelkezésre álló hálózat"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Hálózati információk"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"A kapcsolódáshoz koppintson a kívánt hálózatra"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Zárolás feloldása a hálózatok megtekintéséhez"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Hálózatok keresése…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nem sikerült hálózathoz csatlakozni."</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Megtekintés"</string>
</resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index bdebdad..5a9d00b 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Բացելու համար օգտագործեք մատնահետքը"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Պահանջվում է նույնականացում։ Դրա համար մատը հպեք մատնահետքի սկաներին։"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ընթացիկ հեռախոսազանգ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Բջջային ինտերնետ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Միացած է"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Բջջային ինտերնետն ավտոմատ չի միանա"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Կապ չկա"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Այլ հասանելի ցանցեր չկան"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Հասանելի ցանցեր չկան"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Ցանցի տվյալներ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Հպեք ցանցին՝ միանալու համար"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ապակողպեք՝ ցանցերը դիտելու համար"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 15b64c6..7e2bad0 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -191,7 +191,7 @@
<string name="accessibility_face_dialog_face_icon" msgid="8335095612223716768">"Ikon wajah"</string>
<string name="accessibility_compatibility_zoom_button" msgid="5845799798708790509">"Tombol perbesar/perkecil kompatibilitas."</string>
<string name="accessibility_compatibility_zoom_example" msgid="2617218726091234073">"Perbesar dari layar kecil ke besar."</string>
- <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth tersambung."</string>
+ <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"Bluetooth terhubung."</string>
<string name="accessibility_bluetooth_disconnected" msgid="7195823280221275929">"Bluetooth terputus."</string>
<string name="accessibility_no_battery" msgid="3789287732041910804">"Tidak ada baterai."</string>
<string name="accessibility_battery_one_bar" msgid="8868347318237585329">"Baterai satu batang."</string>
@@ -216,8 +216,8 @@
<string name="accessibility_signal_full" msgid="5920148525598637311">"Sinyal penuh."</string>
<string name="accessibility_desc_on" msgid="2899626845061427845">"Aktif."</string>
<string name="accessibility_desc_off" msgid="8055389500285421408">"Nonaktif."</string>
- <string name="accessibility_desc_connected" msgid="3082590384032624233">"Tersambung."</string>
- <string name="accessibility_desc_connecting" msgid="8011433412112903614">"Menyambung."</string>
+ <string name="accessibility_desc_connected" msgid="3082590384032624233">"Terhubung."</string>
+ <string name="accessibility_desc_connecting" msgid="8011433412112903614">"Menghubungkan."</string>
<string name="data_connection_hspa" msgid="6096234094857660873">"HSPA"</string>
<string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
<string name="accessibility_data_connection_wifi" msgid="4422160347472742434">"Wi-Fi"</string>
@@ -272,7 +272,7 @@
<string name="accessibility_quick_settings_bluetooth_off" msgid="3795983516942423240">"Bluetooth nonaktif."</string>
<string name="accessibility_quick_settings_bluetooth_on" msgid="3819082137684078013">"Bluetooth aktif."</string>
<string name="accessibility_quick_settings_bluetooth_connecting" msgid="7362294657419149294">"Bluetooth menyambung."</string>
- <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth tersambung."</string>
+ <string name="accessibility_quick_settings_bluetooth_connected" msgid="5237625393869747261">"Bluetooth terhubung."</string>
<string name="accessibility_quick_settings_bluetooth_changed_off" msgid="3344226652293797283">"Bluetooth dinonaktifkan."</string>
<string name="accessibility_quick_settings_bluetooth_changed_on" msgid="1263282011749437549">"Bluetooth diaktifkan."</string>
<string name="accessibility_quick_settings_location_off" msgid="6122523378294740598">"Pelaporan lokasi nonaktif."</string>
@@ -390,9 +390,9 @@
<string name="quick_settings_more_user_settings" msgid="1064187451100861954">"Setelan pengguna"</string>
<string name="quick_settings_done" msgid="2163641301648855793">"Selesai"</string>
<string name="quick_settings_close_user_panel" msgid="5599724542275896849">"Tutup"</string>
- <string name="quick_settings_connected" msgid="3873605509184830379">"Tersambung"</string>
+ <string name="quick_settings_connected" msgid="3873605509184830379">"Terhubung"</string>
<string name="quick_settings_connected_battery_level" msgid="1322075669498906959">"Terhubung, baterai <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g>"</string>
- <string name="quick_settings_connecting" msgid="2381969772953268809">"Menyambung..."</string>
+ <string name="quick_settings_connecting" msgid="2381969772953268809">"Menghubungkan..."</string>
<string name="quick_settings_tethering_label" msgid="5257299852322475780">"Menambatkan"</string>
<string name="quick_settings_hotspot_label" msgid="1199196300038363424">"Hotspot"</string>
<string name="quick_settings_hotspot_secondary_label_transient" msgid="7585604088079160564">"Mengaktifkan…"</string>
@@ -563,30 +563,30 @@
<string name="monitoring_description_ca_certificate" msgid="448923057059097497">"Otoritas sertifikat diinstal di perangkat. Traffic jaringan aman Anda mungkin dipantau atau diubah."</string>
<string name="monitoring_description_management_network_logging" msgid="216983105036994771">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat."</string>
<string name="monitoring_description_managed_profile_network_logging" msgid="6932303843097006037">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di profil kerja, tetapi tidak di profil pribadi."</string>
- <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
- <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Anda tersambung ke <xliff:g id="VPN_APP_0">%1$s</xliff:g> dan <xliff:g id="VPN_APP_1">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
- <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Profil kerja Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
- <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Profil pribadi Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+ <string name="monitoring_description_named_vpn" msgid="5749932930634037027">"Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+ <string name="monitoring_description_two_named_vpns" msgid="3516830755681229463">"Anda terhubung ke <xliff:g id="VPN_APP_0">%1$s</xliff:g> dan <xliff:g id="VPN_APP_1">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+ <string name="monitoring_description_managed_profile_named_vpn" msgid="368812367182387320">"Profil kerja Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+ <string name="monitoring_description_personal_profile_named_vpn" msgid="8179722332380953673">"Profil pribadi Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
<string name="monitoring_description_do_header_generic" msgid="6130190408164834986">"Perangkat dikelola oleh <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> menggunakan <xliff:g id="DEVICE_OWNER_APP">%2$s</xliff:g> untuk mengelola perangkat Anda."</string>
<string name="monitoring_description_do_body" msgid="7700878065625769970">"Admin dapat memantau dan mengelola setelan, akses perusahaan, aplikasi, data terkait perangkat, dan informasi lokasi perangkat."</string>
<string name="monitoring_description_do_learn_more_separator" msgid="1467280496376492558">" "</string>
<string name="monitoring_description_do_learn_more" msgid="645149183455573790">"Pelajari lebih lanjut"</string>
- <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Anda tersambung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
+ <string name="monitoring_description_do_body_vpn" msgid="7699280130070502303">"Anda terhubung ke <xliff:g id="VPN_APP">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web."</string>
<string name="monitoring_description_vpn_settings_separator" msgid="8292589617720435430">" "</string>
<string name="monitoring_description_vpn_settings" msgid="5264167033247632071">"Buka setelan VPN"</string>
<string name="monitoring_description_ca_cert_settings_separator" msgid="7107390013344435439">" "</string>
<string name="monitoring_description_ca_cert_settings" msgid="8329781950135541003">"Buka kredensial terpercaya"</string>
<string name="monitoring_description_network_logging" msgid="577305979174002252">"Admin telah mengaktifkan pencatatan log jaringan, yang memantau traffic di perangkat.\n\nUntuk informasi selengkapnya, hubungi admin."</string>
<string name="monitoring_description_vpn" msgid="1685428000684586870">"Anda memberikan izin kepada aplikasi untuk menyiapkan sambungan VPN.\n\nAplikasi ini ini dapat memantau aktivitas perangkat dan jaringan, termasuk email, aplikasi, dan situs web."</string>
- <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga tersambung ke VPN, yang dapat memantau aktivitas jaringan."</string>
+ <string name="monitoring_description_vpn_profile_owned" msgid="4964237035412372751">"Profil kerja dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>.\n\nAdmin dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs web.\n\nUntuk informasi selengkapnya, hubungi admin.\n\nAnda juga terhubung ke VPN, yang dapat memantau aktivitas jaringan."</string>
<string name="monitoring_description_parental_controls" msgid="8184693528917051626">"Perangkat ini dikelola oleh orang tuamu. Orang tuamu bisa melihat dan mengelola berbagai informasi, seperti aplikasi yang kamu gunakan, lokasimu, dan lama pemakaian perangkat."</string>
<string name="legacy_vpn_name" msgid="4174223520162559145">"VPN"</string>
- <string name="monitoring_description_app" msgid="376868879287922929">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
- <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
- <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Anda tersambung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
- <string name="monitoring_description_app_work" msgid="3713084153786663662">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs.\n\nHubungi admin untuk mendapatkan informasi lebih lanjut."</string>
- <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil tersambung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga tersambung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
+ <string name="monitoring_description_app" msgid="376868879287922929">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs."</string>
+ <string name="monitoring_description_app_personal" msgid="1970094872688265987">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web."</string>
+ <string name="branded_monitoring_description_app_personal" msgid="1703511985892688885">"Anda terhubung ke <xliff:g id="APPLICATION">%1$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi, termasuk email, aplikasi, dan situs web.."</string>
+ <string name="monitoring_description_app_work" msgid="3713084153786663662">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil terhubung ke <xliff:g id="APPLICATION">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan kerja, termasuk email, aplikasi, dan situs.\n\nHubungi admin untuk mendapatkan informasi lebih lanjut."</string>
+ <string name="monitoring_description_app_personal_work" msgid="6175816356939166101">"Profil kerja Anda dikelola oleh <xliff:g id="ORGANIZATION">%1$s</xliff:g>. Profil terhubung ke <xliff:g id="APPLICATION_WORK">%2$s</xliff:g>, yang dapat memantau aktivitas jaringan, termasuk email, aplikasi, dan situs.\n\nAnda juga terhubung ke <xliff:g id="APPLICATION_PERSONAL">%3$s</xliff:g>, yang dapat memantau aktivitas jaringan pribadi."</string>
<string name="keyguard_indication_trust_unlocked" msgid="7395154975733744547">"Tetap terbuka kuncinya oleh TrustAgent"</string>
<string name="keyguard_indication_trust_disabled" msgid="6820793704816727918">"Perangkat akan tetap terkunci hingga Anda membukanya secara manual"</string>
<string name="keyguard_indication_trust_unlocked_plugged_in" msgid="2323452175329362855">"<xliff:g id="KEYGUARD_INDICATION">%1$s</xliff:g>\n<xliff:g id="POWER_INDICATION">%2$s</xliff:g>"</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan sidik jari untuk membuka"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Perlu autentikasi. Sentuh sensor sidik jari untuk melakukan autentikasi."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telepon sedang berlangsung"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data seluler"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Terhubung"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data seluler tidak akan terhubung otomatis"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tidak ada koneksi"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Jaringan lain tidak tersedia"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Jaringan tidak tersedia"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detail jaringan"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketuk jaringan untuk menghubungkan"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat jaringan"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Mencari jaringan …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Gagal menghubungkan ke jaringan"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Lihat semua"</string>
</resources>
diff --git a/packages/SystemUI/res/values-in/strings_tv.xml b/packages/SystemUI/res/values-in/strings_tv.xml
index d58cdc8..110eb09 100644
--- a/packages/SystemUI/res/values-in/strings_tv.xml
+++ b/packages/SystemUI/res/values-in/strings_tv.xml
@@ -21,7 +21,7 @@
xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="mic_active" msgid="5766614241012047024">"Mikrofon Aktif"</string>
<string name="app_accessed_mic" msgid="2754428675130470196">"%1$s mengakses mikrofon"</string>
- <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN tersambung"</string>
+ <string name="notification_vpn_connected" msgid="3891023882833274730">"VPN terhubung"</string>
<string name="notification_vpn_disconnected" msgid="7150747626448044843">"VPN terputus"</string>
<string name="notification_disclosure_vpn_text" msgid="3873532735584866236">"Melalui <xliff:g id="VPN_APP">%1$s</xliff:g>"</string>
<string name="tv_notification_panel_title" msgid="5311050946506276154">"Notifikasi"</string>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index e0ff373..b55e10e 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Opna með fingrafari"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Auðkenningar krafist. Auðkenndu með því að snerta fingrafaralesarann."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Símtal í gangi"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Farsímagögn"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Tengt"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Farsímagögn tengjast ekki sjálfkrafa"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Engin tenging"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Engin önnur net í boði"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Ekkert net í boði"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Upplýsingar um net"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ýttu á net til að tengjast"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Taktu úr lás til að skoða netkerfi"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Leitar að netum…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ekki tókst að tengjast neti"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Sjá allt"</string>
</resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 3d26cbb..f16a117 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Usa l\'impronta per aprire"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticazione obbligatoria. Eseguila toccando il sensore di impronte digitali."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonata in corso"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dati mobili"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Connessione attiva"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nessuna connessione dati mobili automatica"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nessuna connessione"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nessun\'altra rete disponibile"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nessuna rete disponibile"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Dettagli rete"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tocca una rete per connetterti"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Sblocca per visualizzare le reti"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ricerca di reti in corso…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Connessione alla rete non riuscita"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Mostra tutte"</string>
</resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index ed1ea36..ea19de7 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>
@@ -1175,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"שימוש בטביעת אצבע כדי לפתוח"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"נדרש אימות. יש לגעת בחיישן טביעות האצבע כדי לבצע אימות."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"מתקיימת שיחה"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"חבילת גלישה"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"מחובר"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"החיבור לנתונים סלולריים לא מתבצע באופן אוטומטי"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"אין חיבור"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"אין רשתות זמינות אחרות"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"אין רשתות זמינות"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"פרטי הרשת"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"צריך להקיש על רשת כדי להתחבר"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"צריך לבטל את הנעילה כדי להציג את הרשתות"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 502f962..bef2330 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"指紋を使って開いてください"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"認証が必要です。指紋認証センサーをタッチして認証してください。"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"モバイルデータ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"接続済み"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"モバイルデータには自動接続しません"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"接続なし"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"利用できるネットワークはありません"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ネットワークを利用できません"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ネットワークの詳細"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ネットワークをタップして接続"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ネットワークを表示するにはロック解除してください"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index 38c59bf..c2507d4 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"გასახსნელად გამოიყენეთ თითის ანაბეჭდი"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"საჭიროა ავტორიზაცია. ავტორიზაციისთვის შეეხეთ თითის ანაბეჭდის სენსორს."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"მიმდინარე სატელეფონო ზარი"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"მობილური ინტერნეტი"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"დაკავშირებული"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"მობილურ ინტერნეტს ავტომატურად არ დაუკავშირდება"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"კავშირი არ არის"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"სხვა ქსელები მიუწვდომელია"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ქსელები მიუწვდომელია"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ქსელის დეტალები"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"დასაკავშირებლად შეეხეთ ქსელს"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"განბლოკვა ქსელების სანახავად"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index afb46e8..6879d32 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ашу үшін саусақ ізін пайдаланыңыз."</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аутентификациядан өту қажет. Ол үшін саусақ ізін оқу сканерін түртіңіз."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Телефон қоңырауы бар"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильдік интернет"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Жалғанды"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобильдік интернет автоматты түрде қосылмайды."</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыс жоқ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Басқа қолжетімді желі жоқ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Қолжетімді желілер жоқ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Желі деректері"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Желіге қосылу үшін оны түртіңіз."</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Желілерді көру үшін құлыпты ашыңыз."</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 9f4ddf3..676150a 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ប្រើស្នាមម្រាមដៃ ដើម្បីបើក"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"តម្រូវឱ្យមានការផ្ទៀងផ្ទាត់។ សូមចុចឧបករណ៍ចាប់ស្នាមម្រាមដៃ ដើម្បីផ្ទៀងផ្ទាត់។"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ការហៅទូរសព្ទដែលកំពុងដំណើរការ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ទិន្នន័យទូរសព្ទចល័ត"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"បានភ្ជាប់"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"ទិន្នន័យទូរសព្ទចល័តនឹងមិនភ្ជាប់ដោយស្វ័យប្រវត្តិទេ"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"មិនមានការតភ្ជាប់ទេ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"មិនមានបណ្ដាញផ្សេងទៀតដែលអាចប្រើបានទេ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"មិនមានបណ្ដាញដែលអាចប្រើបានទេ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ព័ត៌មានលម្អិតអំពីបណ្ដាញ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ចុចលើបណ្ដាញណាមួយ ដើម្បីភ្ជាប់"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ដោះសោដើម្បីមើលបណ្ដាញ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index 36d3d7d..385eee2 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ತೆರೆಯುವುದಕ್ಕಾಗಿ ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಅನ್ನು ಬಳಸಿ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ದೃಢೀಕರಣದ ಅವಶ್ಯಕತೆಯಿದೆ. ದೃಢೀಕರಿಸಲು ಫಿಂಗರ್ಪ್ರಿಂಟ್ ಸೆನ್ಸರ್ ಅನ್ನು ಸ್ಪರ್ಶಿಸಿ."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ಚಾಲ್ತಿಯಲ್ಲಿರುವ ಫೋನ್ ಕರೆ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ಮೊಬೈಲ್ ಡೇಟಾ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ಯಾವುದೇ ಕನೆಕ್ಷನ್ ಇಲ್ಲ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ಇತರ ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ಯಾವುದೇ ನೆಟ್ವರ್ಕ್ಗಳು ಲಭ್ಯವಿಲ್ಲ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ವೈ‑ಫೈ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ನೆಟ್ವರ್ಕ್ ವಿವರಗಳು"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ಕನೆಕ್ಟ್ ಮಾಡಲು ಒಂದು ನೆಟ್ವರ್ಕ್ ಅನ್ನು ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ನೆಟ್ವರ್ಕ್ಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಅನ್ಲಾಕ್ ಮಾಡಿ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index a846bc1..3292cbb 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"지문으로 열기"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"인증이 필요합니다. 지문 센서를 터치하여 인증하세요."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"진행 중인 전화 통화"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"모바일 데이터"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"연결됨"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"모바일 데이터가 자동으로 연결되지 않음"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"연결되지 않음"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"사용 가능한 다른 네트워크가 없음"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"사용 가능한 네트워크가 없음"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"네트워크 세부정보"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"연결하려면 네트워크를 탭하세요"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"네트워크를 보려면 잠금 해제하세요"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index 124dc53..3aca45a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Манжаңыздын изи менен ачыңыз"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Аныктыкты текшерүү талап кылынат. Аныктыгын текшерүү үчүн манжа изинин сенсоруна тийип коюңуз."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Учурдагы телефон чалуу"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилдик трафик"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Туташты"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилдик трафик автоматтык түрдө туташтырылбайт"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Байланыш жок"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Башка тармактар жеткиликсиз"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Тармактар жеткиликтүү эмес"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Тармактын чоо-жайы"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Кайсы тармакка туташасыз?"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Тармактарды көрүү үчүн кулпусун ачыңыз"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index c27394c..c80c00b 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ໃຊ້ລາຍນິ້ວມືເພື່ອເປີດ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ຕ້ອງພິສູດຢືນຢັນ. ແຕະໃສ່ເຊັນເຊີລາຍນິ້ວມືເພື່ອພິສູດຢືນຢັນ."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ສາຍໂທອອກ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ອິນເຕີເນັດມືຖື"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"ຈະບໍ່ເຊື່ອມຕໍ່ອິນເຕີເນັດມືຖືອັດຕະໂນມັດ"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ບໍ່ມີການເຊື່ອມຕໍ່"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ບໍ່ມີເຄືອຂ່າຍອື່ນທີ່ສາມາດໃຊ້ໄດ້"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ບໍ່ມີເຄືອຂ່າຍທີ່ສາມາດໃຊ້ໄດ້"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ລາຍລະອຽດເຄືອຂ່າຍ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ແຕະເຄືອຂ່າຍໃດໜຶ່ງເພື່ອເຊື່ອມຕໍ່"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ປົດລັອກເພື່ອເບິ່ງເຄືອຂ່າຍ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index a1cd602..3cfa0ca 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Naudokite kontrolinį kodą, kad atidarytumėte"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Reikia nustatyti tapatybę. Nustatykite tapatybę palietę kontrolinio kodo jutiklį."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Vykstantis telefono skambutis"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiliojo ryšio duomenys"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Prisijungta"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Naud. mob. r. duomenis nebus autom. prisijungiama"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nėra ryšio"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nėra kitų pasiekiamų tinklų"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nėra pasiekiamų tinklų"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Išsami tinklo informacija"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Palieskite tinklą, kad prisijungtumėte"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Atrakinkite, kad peržiūrėtumėte visus tinklus"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ieškoma tinklų…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Jungiantis prie tinklo įvyko klaida"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Žiūrėti viską"</string>
</resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index b0da7f7..a444a5a 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Atvēršanai izmantojiet pirksta nospiedumu"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Nepieciešama autentifikācija. Pieskarieties pirksta nospieduma sensoram, lai veiktu autentificēšanu."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Notiekošs tālruņa zvans"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilie dati"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ir izveidots savienojums"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilo datu savienojums netiks veidots automātiski"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nav savienojuma"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nav pieejams neviens cits tīkls"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nav pieejams neviens tīkls"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Dati par tīklu"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Pieskarieties tīklam, lai izveidotu savienojumu"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lai skatītu tīklus, atbloķējiet"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Notiek tīklu meklēšana…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Neizdevās izveidot savienojumu ar tīklu"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Visu tīklu skatīšana"</string>
</resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index bee9bff..341fca8 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Користете отпечаток за да се отвори"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна е проверка. Допрете го сензорот за отпечаток за да автентицирате."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Тековен телефонски повик"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилен интернет"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Поврзано"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобилниот интернет не може автоматски да се поврзе"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нема интернет-врска"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нема други достапни мрежи"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Нема достапни мрежи"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Детали за мрежата"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Допрете на мрежа за да се поврзете"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Отклучете за да се прикажат мрежите"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index 061f43c..f308c97 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>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"തുറക്കുന്നതിന് നിങ്ങളുടെ ഫിംഗർപ്രിന്റ് ഉപയോഗിക്കുക"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"പരിശോധിച്ചുറപ്പിക്കേണ്ടതുണ്ട്. പരിശോധിച്ചുറപ്പിക്കാൻ, വിരലടയാള സെൻസറിൽ സ്പർശിക്കുക."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"സജീവമായ ഫോൺ കോൾ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"മൊബൈൽ ഡാറ്റ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"കണക്റ്റ് ചെയ്തു"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"മൊബൈൽ ഡാറ്റ സ്വയമേവ കണക്റ്റ് ചെയ്യില്ല"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"കണക്ഷനില്ല"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"മറ്റ് നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"നെറ്റ്വർക്കുകളൊന്നും ലഭ്യമല്ല"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"വൈഫൈ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"നെറ്റ്വർക്ക് വിശദാംശങ്ങൾ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"കണക്റ്റ് ചെയ്യാൻ ഒരു നെറ്റ്വർക്കിൽ ടാപ്പ് ചെയ്യുക"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"നെറ്റ്വർക്കുകൾ കാണാൻ അൺലോക്ക് ചെയ്യുക"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 8bf0dbc..dd25334 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -659,7 +659,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"Системийн UI Тохируулагч"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"Залгаатай тэжээлийн хувийг харуулах"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"Тэжээлийн хувийг цэнэглээгүй байх үед статусын хэсэгт харуулна уу"</string>
- <string name="quick_settings" msgid="6211774484997470203">"Түргэвчилсэн Tохиргоо"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"Шуурхай тохиргоо"</string>
<string name="status_bar" msgid="4357390266055077437">"Статус самбар"</string>
<string name="overview" msgid="3522318590458536816">"Тойм"</string>
<string name="demo_mode" msgid="263484519766901593">"Системийн UI демо горим"</string>
@@ -684,7 +684,7 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>-т та дараагийн сэрүүлгээ сонсохгүй"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> цагт"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g>-т"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Түргэн Тохиргоо, <xliff:g id="TITLE">%s</xliff:g>."</string>
+ <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"Шуурхай тохиргоо, <xliff:g id="TITLE">%s</xliff:g>."</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"Сүлжээний цэг"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"Ажлын профайл"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"Зарим хүнд хөгжилтэй байж болох ч бүх хүнд тийм биш"</string>
@@ -697,8 +697,8 @@
<string name="activity_not_found" msgid="8711661533828200293">"Аппыг таны төхөөрөмжид суулгаагүй байна"</string>
<string name="clock_seconds" msgid="8709189470828542071">"Цагийн секундыг харуулах"</string>
<string name="clock_seconds_desc" msgid="2415312788902144817">"Статус талбарт цагийн секундыг харуулах. Энэ нь тэжээлийн цэнэгт нөлөөлж болно."</string>
- <string name="qs_rearrange" msgid="484816665478662911">"Түргэн тохиргоог дахин засварлах"</string>
- <string name="show_brightness" msgid="6700267491672470007">"Түргэн тохиргоонд гэрэлтүүлэг харах"</string>
+ <string name="qs_rearrange" msgid="484816665478662911">"Шуурхай тохиргоог дахин засварлах"</string>
+ <string name="show_brightness" msgid="6700267491672470007">"Шуурхай тохиргоонд гэрэлтүүлэг харах"</string>
<string name="experimental" msgid="3549865454812314826">"Туршилтын"</string>
<string name="enable_bluetooth_title" msgid="866883307336662596">"Bluetooth-г асаах уу?"</string>
<string name="enable_bluetooth_message" msgid="6740938333772779717">"Компьютерийн гараа таблетад холбохын тулд эхлээд Bluetooth-г асаана уу."</string>
@@ -920,11 +920,11 @@
<string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
<string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Хавтан нэмсэн"</string>
<string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Хавтанг хассан"</string>
- <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Түргэн тохиргоо засварлагч."</string>
+ <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Шуурхай тохиргоо засварлагч."</string>
<string name="accessibility_desc_notification_icon" msgid="7331265967584178674">"<xliff:g id="ID_1">%1$s</xliff:g> мэдэгдэл: <xliff:g id="ID_2">%2$s</xliff:g>"</string>
<string name="accessibility_quick_settings_settings" msgid="7098489591715844713">"Тохиргоог нээнэ үү."</string>
<string name="accessibility_quick_settings_expand" msgid="2609275052412521467">"Шуурхай тохиргоог нээнэ үү."</string>
- <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Хурдан тохиргоог хаана уу."</string>
+ <string name="accessibility_quick_settings_collapse" msgid="4674876336725041982">"Шуурхай тохиргоог хаана уу."</string>
<string name="accessibility_quick_settings_alarm_set" msgid="7237918261045099853">"Сэрүүлэг тавьсан."</string>
<string name="accessibility_quick_settings_user" msgid="505821942882668619">"<xliff:g id="ID_1">%s</xliff:g>-р нэвтэрсэн"</string>
<string name="accessibility_quick_settings_choose_user_action" msgid="4554388498186576087">"хэрэглэгчийг сонгох"</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Нээхийн тулд хурууны хээг ашиглана уу"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Баталгаажуулалт шаардлагатай. Баталгаажуулахын тулд хурууны хээ мэдрэгчид хүрнэ үү."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Үргэлжилж буй утасны дуудлага"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобайл дата"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Холбогдсон"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобайл дата автоматаар холбогдохгүй"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Холболт алга"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Өөр боломжтой сүлжээ байхгүй байна"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Боломжтой сүлжээ байхгүй байна"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Сүлжээний дэлгэрэнгүй мэдээлэл"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Холбогдохын тулд сүлжээг товшино уу"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Сүлжээг харахын тулд түгжээг тайлах"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index 7d23729..a8798fd 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"उघडण्यासाठी फिंगरप्रिंट वापरा"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ऑथेंटिकेशन आवश्यक आहे. ऑथेंटिकेट करण्यासाठी फिंगरप्रिंट सेन्सरला स्पर्श करा."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"फोन कॉल सुरू आहे"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"कनेक्ट केले आहे"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"कोणतेही कनेक्शन नाही"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"इतर कोणतेही नेटवर्क उपलब्ध नाहीत"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"कोणतेही नेटवर्क उपलब्ध नाही"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"वाय-फाय"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कचे तपशील"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"कनेक्ट करण्यासाठी नेटवर्कवर टॅप करा"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्क पाहण्यासाठी स्क्रीन अनलॉक करा"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index b662271..1c730281 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gunakan cap jari untuk membuka"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Pengesahan diperlukan. Sentuh penderia cap jari untuk pengesahan."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Panggilan telefon yang sedang berjalan"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data mudah alih"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Disambungkan"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data mudah alih tidak akan autosambung"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Tiada sambungan"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Tiada rangkaian lain yang tersedia"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Tiada rangkaian tersedia"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Butiran rangkaian"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ketik rangkaian untuk membuat sambungan"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Buka kunci untuk melihat rangkaian"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index 900b98a..206ccad 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ဖွင့်ရန် လက်ဗွေကို သုံးပါ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"အထောက်အထားစိစစ်ခြင်း လိုအပ်သည်။ အထောက်အထားစိစစ်ရန် လက်ဗွေ အာရုံခံကိရိယာကို ထိပါ။"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"လက်ရှိ ဖုန်းခေါ်ဆိုမှု"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"မိုဘိုင်းဒေတာ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ချိတ်ဆက်ထားသည်"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"မိုဘိုင်းဒေတာက အလိုအလျောက် ချိတ်ဆက်မည်မဟုတ်ပါ"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ချိတ်ဆက်မှုမရှိပါ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"အခြားကွန်ရက်များ မရှိပါ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ကွန်ရက်များ မရှိပါ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ကွန်ရက် အသေးစိတ်များ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ချိတ်ဆက်ရန် ကွန်ရက်ကို တို့ပါ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ကွန်ရက်များကြည့်ရန် ဖွင့်ပါ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 938234d..cdad0e8 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Bruk fingeravtrykk for å åpne"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering kreves. Trykk på fingeravtrykkssensoren for å autentisere."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående telefonsamtale"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Tilkoblet"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobildata kobler ikke til automatisk"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen tilkobling"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Ingen andre nettverk er tilgjengelige"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Ingen nettverk er tilgjengelige"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Nettverksdetaljer"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trykk på et nettverk for å koble til"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås opp for å se nettverk"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Søker etter nettverk …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kunne ikke koble til nettverket"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Se alle"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 440e8af..3ead44f0 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>
@@ -1163,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"फिंगरप्रिन्ट प्रयोग गरी खोल्नुहोस्"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"पुष्टि गर्नु पर्ने हुन्छ। पुष्टि गर्न फिंगरप्रिन्ट सेन्सर छुनुहोस्।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"जारी फोन कल"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"मोबाइल डेटा"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"इन्टरनेटमा कनेक्ट गरिएको छ"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"मोबाइल डेटा स्वतः कनेक्ट हुँदैन"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"इन्टरनेट छैन"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"अन्य नेटवर्क उपलब्ध छैनन्"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"कुनै पनि नेटवर्क उपलब्ध छैन"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"नेटवर्कसम्बन्धी विवरण"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"इन्टरनेट कनेक्ट गर्न कुनै नेटवर्कमा ट्याप गर्नुहोस्"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"नेटवर्कहरू हेर्न आफ्नो स्क्रिन अनलक गर्नुहोस्"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 66ec98a..331fb64 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gebruik vingerafdruk om te openen"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Verificatie vereist. Raak de vingerafdruksensor aan om de verificatie uit te voeren."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Actief telefoongesprek"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobiele data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Verbonden"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobiele data maakt niet automatisch verbinding"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Geen verbinding"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Geen andere netwerken beschikbaar"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Geen netwerken beschikbaar"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Netwerkgegevens"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tik op een netwerk om verbinding te maken"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ontgrendel het scherm om netwerken te bekijken"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Netwerken zoeken…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Kan geen verbinding maken met het netwerk"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Alles tonen"</string>
</resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index f76adfa..ea08032 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>
@@ -249,7 +248,7 @@
<skip />
<string name="accessibility_notification_dismissed" msgid="4411652015138892952">"ବିଜ୍ଞପ୍ତି ଖାରଜ କରାଗଲା।"</string>
<string name="accessibility_desc_notification_shade" msgid="5355229129428759989">"ବିଜ୍ଞପ୍ତି ଶେଡ୍।"</string>
- <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"ଦ୍ରୁତ ସେଟିଂସ୍।"</string>
+ <string name="accessibility_desc_quick_settings" msgid="4374766941484719179">"କ୍ୱିକ୍ ସେଟିଂସ୍।"</string>
<string name="accessibility_desc_lock_screen" msgid="5983125095181194887">"ଲକ୍ ସ୍କ୍ରୀନ୍।"</string>
<string name="accessibility_desc_settings" msgid="6728577365389151969">"ସେଟିଂସ୍"</string>
<string name="accessibility_desc_recent_apps" msgid="1748675199348914194">"ସଂକ୍ଷିପ୍ତ ବିବରଣୀ"</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>
@@ -660,7 +659,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"ସିଷ୍ଟମ୍ UI ଟ୍ୟୁନର୍"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"ଏମ୍ବେଡ୍ ହୋଇଥିବା ବ୍ୟାଟେରୀ ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"ଚାର୍ଜ ହେଉନଥିବାବେଳେ ଷ୍ଟାଟସ୍ ବାର୍ ଆଇକନ୍ ଭିତରେ ବ୍ୟାଟେରୀ ସ୍ତର ଶତକଡ଼ା ଦେଖାନ୍ତୁ"</string>
- <string name="quick_settings" msgid="6211774484997470203">"ଦ୍ରୁତ ସେଟିଂସ୍"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"କ୍ୱିକ୍ ସେଟିଂସ୍"</string>
<string name="status_bar" msgid="4357390266055077437">"ଷ୍ଟାଟସ୍ ବାର୍"</string>
<string name="overview" msgid="3522318590458536816">"ଅବଲୋକନ"</string>
<string name="demo_mode" msgid="263484519766901593">"ସିଷ୍ଟମ୍ UI ଡେମୋ ମୋଡ୍"</string>
@@ -685,7 +684,7 @@
<string name="zen_alarm_warning" msgid="7844303238486849503">"<xliff:g id="WHEN">%1$s</xliff:g>ବେଳେ ଆପଣ ନିଜର ପରବର୍ତ୍ତୀ ଆଲାର୍ମ ଶୁଣିପାରିବେ ନାହିଁ"</string>
<string name="alarm_template" msgid="2234991538018805736">"<xliff:g id="WHEN">%1$s</xliff:g> ହେଲେ"</string>
<string name="alarm_template_far" msgid="3561752195856839456">"<xliff:g id="WHEN">%1$s</xliff:g> ବେଳେ"</string>
- <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"ଦ୍ରୁତ ସେଟିଙ୍ଗ, <xliff:g id="TITLE">%s</xliff:g>।"</string>
+ <string name="accessibility_quick_settings_detail" msgid="544463655956179791">"କ୍ୱିକ୍ ସେଟିଂସ୍, <xliff:g id="TITLE">%s</xliff:g>।"</string>
<string name="accessibility_status_bar_hotspot" msgid="2888479317489131669">"ହଟସ୍ପଟ୍"</string>
<string name="accessibility_managed_profile" msgid="4703836746209377356">"ୱର୍କ ପ୍ରୋଫାଇଲ୍"</string>
<string name="tuner_warning_title" msgid="7721976098452135267">"କେତେକଙ୍କ ପାଇଁ ମଜାଦାର, କିନ୍ତୁ ସମସ୍ତଙ୍କ ପାଇଁ ନୁହେଁ"</string>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ଖୋଲିବାକୁ ଟିପଚିହ୍ନ ବ୍ୟବହାର କରନ୍ତୁ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ପ୍ରମାଣୀକରଣ ଆବଶ୍ୟକ। ପ୍ରମାଣୀକରଣ କରିବାକୁ ଟିପଚିହ୍ନ ସେନ୍ସରକୁ ସ୍ପର୍ଶ କରନ୍ତୁ।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ଚାଲୁଥିବା ଫୋନ୍ କଲ୍"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ମୋବାଇଲ ଡାଟା"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ସଂଯୋଗ କରାଯାଇଛି"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ସଂଯୋଗ ନାହିଁ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ଅନ୍ୟ କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"କୌଣସି ନେଟୱାର୍କ ଉପଲବ୍ଧ ନାହିଁ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ୱାଇ-ଫାଇ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ନେଟୱାର୍କ ବିବରଣୀ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ସଂଯୋଗ କରିବାକୁ ଏକ ନେଟୱାର୍କରେ ଟାପ୍ କରନ୍ତୁ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ନେଟୱାର୍କଗୁଡ଼ିକୁ ଦେଖିବା ପାଇଁ ଅନଲକ୍ କରନ୍ତୁ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 9d1edfa..24dae87 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ਖੋਲ੍ਹਣ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਵਰਤੋ"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ਪ੍ਰਮਾਣੀਕਰਨ ਲੋੜੀਂਦਾ ਹੈ। ਪ੍ਰਮਾਣਿਤ ਕਰਨ ਲਈ ਫਿੰਗਰਪ੍ਰਿੰਟ ਸੈਂਸਰ ਨੂੰ ਸਪਰਸ਼ ਕਰੋ।"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ਜਾਰੀ ਫ਼ੋਨ ਕਾਲ"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ਮੋਬਾਈਲ ਡਾਟਾ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"ਕਨੈਕਟ ਹੈ"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ਕੋਈ ਕਨੈਕਸ਼ਨ ਨਹੀਂ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ਕੋਈ ਹੋਰ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ਕੋਈ ਨੈੱਟਵਰਕ ਉਪਲਬਧ ਨਹੀਂ ਹੈ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"ਵਾਈ-ਫਾਈ"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ਨੈੱਟਵਰਕ ਵੇਰਵੇ"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"ਕਨੈਕਟ ਕਰਨ ਲਈ ਕਿਸੇ ਨੈੱਟਵਰਕ \'ਤੇ ਟੈਪ ਕਰੋ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ਨੈੱਟਵਰਕਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਅਣਲਾਕ ਕਰੋ"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index b6412e7..1e4e586 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"By otworzyć, użyj odcisku palca"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Wymagane uwierzytelnienie. Dotknij czytnika liniii papilarnych, by uwierzytelnić."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Aktywne połączenie"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilna transmisja danych"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Połączono"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna transmisja danych nie połączy się automatycznie"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Brak połączenia"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Brak innych dostępnych sieci"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Brak dostępnych sieci"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Szczegóły sieci"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Kliknij sieć, aby połączyć"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odblokuj, by wyświetlić sieci"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Szukam sieci…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nie udało się połączyć z siecią"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Pokaż wszystko"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 7c3f864..5969a0e 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index df48773..408b972 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Utilize a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação necessária. Toque no sensor de impressões digitais para autenticar."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada telefónica em curso"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ligado"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Não é efetuada ligação de dados móveis automática"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem ligação"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Sem redes disponíveis"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque numa rede para estabelecer ligação"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"A procurar redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Não foi possível estabelecer ligação à rede"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Veja tudo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 7c3f864..5969a0e 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Use a impressão digital para abrir"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autenticação obrigatória. Toque no sensor de impressão digital para autenticar."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Chamada em andamento"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dados móveis"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectado"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Sem conexão automática com dados móveis"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Sem conexão"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nenhuma outra rede disponível"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nenhuma rede disponível"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalhes da rede"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Toque em uma rede para se conectar"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Desbloqueie para ver as redes"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Procurando redes…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Falha ao conectar à rede"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Ver tudo"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index c36f7e7..dfb6d48 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Folosiți amprenta ca să deschideți"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentificare obligatorie. Atingeți senzorul de amprentă pentru a vă autentifica."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Apel telefonic în desfășurare"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Date mobile"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Conectat"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Nu se conectează automat la date mobile"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nicio conexiune"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nu sunt disponibile alte rețele"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nicio rețea disponibilă"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detalii despre rețea"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Atingeți o rețea pentru a vă conecta"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Deblocați pentru a vedea rețelele"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Se caută rețele…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nu s-a realizat conexiunea la rețea"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Afișează-le pe toate"</string>
</resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index cc63a91..72f12ff 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Используйте отпечаток пальца для входа."</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Требуется аутентификация. Приложите палец к сканеру отпечатков."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Текущий вызов"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобильный интернет"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Подключено"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Без автоподключения к мобильному интернету"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Нет подключения к интернету"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Нет других доступных сетей"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Нет доступных сетей"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Сведения о сети"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Выберите сеть, чтобы подключиться"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Разблокируйте, чтобы посмотреть сети Wi-Fi."</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index c08d6f7..790e514 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"විවෘත කිරීමට ඇඟිලි සලකුණ භාවිත කරන්න"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"සත්යාපනය අවශ්යයි. සත්යාපනය කිරීමට ඇඟිලි සලකුණු සංවේදකය ස්පර්ශ කරන්න."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ක්රියාත්මක වන දුරකථන ඇමතුම"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"ජංගම දත්ත"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"සම්බන්ධයි"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"ජංගම දත්ත ස්වංක්රියව සම්බන්ධ නොවනු ඇත"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"සම්බන්ධතාවයක් නැත"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ලබා ගත හැකි වෙනත් ජාල නැත"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ජාලය නොතිබේ"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"ජාල විස්තර"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"සම්බන්ධ වීමට ජාලයක් තට්ටු කරන්න"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ජාල බැලීමට අගුලු හරින්න"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 0aabf7c..9e94ae5 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Otvorte odtlačkom prsta"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Vyžaduje sa overenie. Dotknite sa senzora odtlačkov prstov."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Prebiehajúci telefonický hovor"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobilné dáta"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Pripojené"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Automatické pripojenie cez mobilné dáta nefunguje"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bez pripojenia"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nie sú k dispozícii žiadne ďalšie siete"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nie sú k dispozícii žiadne siete"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Podrobnosti siete"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ak sa chcete pripojiť, klepnite na sieť"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odomknutím si zobrazte siete"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Vyhľadávajú sa siete…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Nepodarilo sa pripojiť k sieti"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Zobraziť všetko"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index ecf5ca7..27d15e7 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Odprite s prstnim odtisom"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Zahtevano je preverjanje pristnosti. Za preverjanje pristnosti se dotaknite tipala prstnih odtisov."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Poteka klic"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Prenos podatkov v mobilnem omrežju"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Povezano"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobilna podatkovna povezava ne bo samodejna."</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ni povezave"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nobeno drugo omrežje ni na voljo"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Na voljo ni nobeno omrežje"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Podatki o omrežju"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Za vzpostavitev povezave se dotaknite omrežja."</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Odklenite za ogled omrežij"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iskanje omrežij …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Vzpostavljanje povezave z omrežjem ni uspelo."</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Prikaz vseh omrežij"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 86bd5a1..711e9f6 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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Përdor gjurmën e gishtit për ta hapur"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kërkohet vërtetimi. Prek sensorin e gjurmës së gishtit për t\'u vërtetuar."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Telefonatë në vazhdim"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Të dhënat celulare"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Lidhur"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Nuk ka lidhje"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Nuk ofrohet asnjë rrjet tjetër"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Nuk ofrohet asnjë rrjet"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Detajet e rrjetit"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Trokit te një rrjet për t\'u lidhur"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Shkyçe për të parë rrjetet"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 83317d2..5c51ad9 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -1014,7 +1014,7 @@
<string name="ongoing_privacy_chip_content_multiple_apps" msgid="8341216022442383954">"Апликације користе <xliff:g id="TYPES_LIST">%s</xliff:g>."</string>
<string name="ongoing_privacy_dialog_separator" msgid="1866222499727706187">", "</string>
<string name="ongoing_privacy_dialog_last_separator" msgid="5615876114268009767">" и "</string>
- <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Користи <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
+ <string name="ongoing_privacy_dialog_using_op" msgid="426635338010011796">"Користи: <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_recent_op" msgid="2736290123662790026">"Недавно користио/ла <xliff:g id="APPLICATION_NAME">%1$s</xliff:g>"</string>
<string name="ongoing_privacy_dialog_enterprise" msgid="3003314125311966061">"(посао)"</string>
<string name="ongoing_privacy_dialog_phonecall" msgid="4487370562589839298">"Телефонски позив"</string>
@@ -1168,4 +1168,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Отворите помоћу отиска прста"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Потребна је потврда идентитета. Додирните сензор за отисак прста да бисте потврдили идентитет."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Актуелни телефонски позив"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобилни подаци"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Повезано"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Није успело аутом. повезивање преко моб. података"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Веза није успостављена"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Није доступна ниједна друга мрежа"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Нема доступних мрежа"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WiFi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Детаљи о мрежи"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Додирните мрежу да бисте се повезали"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Откључајте да бисте видели мреже"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 86b0fc7..e3ef48f 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Öppna med fingeravtryck"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Autentisering krävs. Identifiera dig genom att trycka på fingeravtryckssensorn."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Pågående samtal"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobildata"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ansluten"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Du ansluts inte till mobildata automatiskt"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Ingen anslutning"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Inga andra nätverk är tillgängliga"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Det finns inga tillgängliga nätverk"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wifi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Nätverksinformation"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Tryck på ett nätverk för att ansluta"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Lås upp för att visa nätverk"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Söker efter nätverk …"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Det gick inte att ansluta till nätverket"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Visa alla"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 58401b5..502c056 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Tumia alama ya kidole kufungua"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Uthibitishaji unahitajika. Gusa kitambua alama ya kidole ili uthibitishe."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Simu inayoendelea"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Data ya mtandao wa simu"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Imeunganishwa"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Data ya mtandao wa simu haitaunganishwa kiotomatiki"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Hakuna muunganisho"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Hakuna mitandao mingine inayopatikana"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Hakuna mitandao inayopatikana"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Maelezo ya mtandao"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Gusa mtandao ili uunganishe"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Fungua ili uangalie mitandao"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Inatafuta mitandao…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Imeshindwa kuunganisha kwenye mtandao"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Angalia yote"</string>
</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index c2aad2d..d921d49 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -103,4 +103,7 @@
<!-- When split shade is used, this panel should be aligned to the top -->
<dimen name="qs_detail_margin_top">0dp</dimen>
+
+ <!-- Internet panel related dimensions -->
+ <dimen name="internet_dialog_list_max_width">624dp</dimen>
</resources>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index efb704f..a5f1d68 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -452,7 +452,7 @@
<string name="zen_silence_introduction" msgid="6117517737057344014">"இது அலாரங்கள், இசை, வீடியோக்கள் மற்றும் கேம்ஸ் உட்பட எல்லா ஒலிகளையும் அதிர்வுகளையும் தடுக்கும்."</string>
<string name="keyguard_more_overflow_text" msgid="5819512373606638727">"+<xliff:g id="NUMBER_OF_NOTIFICATIONS">%d</xliff:g>"</string>
<string name="speed_bump_explanation" msgid="7248696377626341060">"அவசர நிலைக் குறைவான அறிவிப்புகள் கீழே உள்ளன"</string>
- <string name="notification_tap_again" msgid="4477318164947497249">"திறக்க, மீண்டும் தட்டவும்"</string>
+ <string name="notification_tap_again" msgid="4477318164947497249">"அன்லாக் செய்ய, மீண்டும் தட்டவும்"</string>
<string name="tap_again" msgid="1315420114387908655">"மீண்டும் தட்டவும்"</string>
<string name="keyguard_unlock" msgid="8031975796351361601">"திறப்பதற்கு மேல் நோக்கி ஸ்வைப் செய்யவும்"</string>
<string name="keyguard_unlock_press" msgid="8488350566398524740">"திறப்பதற்கு அழுத்தவும்"</string>
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"கைரேகையைப் பயன்படுத்தி திறந்திடுங்கள்"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"அங்கீகாரம் தேவை. கைரேகை சென்சாரைத் தொட்டு அங்கீகரியுங்கள்."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"செயலில் உள்ள மொபைல் அழைப்பு"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"மொபைல் டேட்டா"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"இணைக்கப்பட்டது"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"மொபைல் டேட்டாவுடன் தானாக இணைக்காது"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"இணைப்பு இல்லை"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"வேறு நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"நெட்வொர்க்குகள் எதுவும் கிடைக்கவில்லை"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"வைஃபை"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"நெட்வொர்க் விவரங்கள்"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"இணையத்துடன் இணைய நெட்வொர்க்கைத் தட்டுங்கள்"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"நெட்வொர்க்குகளைப் பார்க்க அன்லாக் செய்யுங்கள்"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 6546059..7b66c3b 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,10 +275,10 @@
<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_changed_off" msgid="5132776369388699133">"స్థాన నివేదన ఆఫ్ చేయబడింది."</string>
- <string name="accessibility_quick_settings_location_changed_on" msgid="7159115433070112154">"స్థాన నివేదన ఆన్ చేయబడింది."</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>
<string name="accessibility_quick_settings_close" msgid="2974895537860082341">"ప్యానెల్ను మూసివేయి."</string>
<string name="accessibility_quick_settings_more_time" msgid="7646479831704665284">"ఎక్కువ సమయం."</string>
@@ -309,8 +308,8 @@
<string name="data_usage_disabled_dialog" msgid="7933201635215099780">"మీరు సెట్ చేసిన డేటా పరిమితిని చేరుకున్నారు. మీరు ఇప్పుడు మొబైల్ డేటాను ఉపయోగించడం లేదు.\n\nమీరు పునఃప్రారంభిస్తే, డేటా వినియోగానికి ఛార్జీలు చెల్లించాల్సి రావచ్చు."</string>
<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="gps_notification_found_text" msgid="3145873880174658526">"లొకేషన్ GPS ద్వారా సెట్ చేయబడింది"</string>
+ <string name="accessibility_location_active" msgid="2845747916764660369">"లొకేషన్ రిక్వెస్ట్లు యాక్టివ్గా ఉన్నాయి"</string>
<string name="accessibility_sensors_off_active" msgid="2619725434618911551">"సెన్సార్లు ఆఫ్ యాక్టివ్లో ఉంది"</string>
<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>
@@ -660,7 +659,7 @@
<string name="system_ui_tuner" msgid="1471348823289954729">"సిస్టమ్ UI ట్యూనర్"</string>
<string name="show_battery_percentage" msgid="6235377891802910455">"పొందుపరిచిన బ్యాటరీ శాతం చూపు"</string>
<string name="show_battery_percentage_summary" msgid="9053024758304102915">"ఛార్జింగ్లో లేనప్పుడు స్థితి పట్టీ చిహ్నం లోపల బ్యాటరీ స్థాయి శాతం చూపుతుంది"</string>
- <string name="quick_settings" msgid="6211774484997470203">"శీఘ్ర సెట్టింగ్లు"</string>
+ <string name="quick_settings" msgid="6211774484997470203">"క్విక్ సెట్టింగ్లు"</string>
<string name="status_bar" msgid="4357390266055077437">"స్థితి పట్టీ"</string>
<string name="overview" msgid="3522318590458536816">"ఓవర్వ్యూ"</string>
<string name="demo_mode" msgid="263484519766901593">"సిస్టమ్ UI డెమో మోడ్"</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>
@@ -1163,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"తెరవడానికి వేలిముద్రను ఉపయోగించండి"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ప్రామాణీకరణ అవసరం. ప్రామాణీకరించడానికి వేలిముద్ర సెన్సార్ను తాకండి."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"ఫోన్ కాల్ జరుగుతోంది"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"మొబైల్ డేటా"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"కనెక్ట్ చేయబడింది"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"కనెక్షన్ లేదు"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ఇతర నెట్వర్క్లేవీ అందుబాటులో లేవు"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"నెట్వర్క్లు అందుబాటులో లేవు"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"నెట్వర్క్ వివరాలు"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"కనెక్ట్ చేయడానికి నెట్వర్క్ను ట్యాప్ చేయండి"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"నెట్వర్క్లను చూడటానికి అన్లాక్ చేయండి"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index df358a3..232c46a 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"ใช้ลายนิ้วมือเพื่อเปิด"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"ต้องมีการตรวจสอบสิทธิ์ แตะเซ็นเซอร์ลายนิ้วมือเพื่อตรวจสอบสิทธิ์"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"กำลังโทรอยู่"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"อินเทอร์เน็ตมือถือ"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"เชื่อมต่อแล้ว"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"อินเทอร์เน็ตมือถือจะไม่เชื่อมต่ออัตโนมัติ"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"ไม่มีการเชื่อมต่อ"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"ไม่มีเครือข่ายอื่นๆ ที่พร้อมใช้งาน"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"ไม่มีเครือข่ายที่พร้อมใช้งาน"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"รายละเอียดเครือข่าย"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"แตะเครือข่ายเพื่อเชื่อมต่อ"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"ปลดล็อกเพื่อดูเครือข่าย"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index a74345d..9ed9bbc 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Gamitin ang fingerprint para buksan"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kailangan ng pag-authenticate. Pindutin ang sensor para sa fingerprint para mag-authenticate."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Kasalukuyang may tawag sa telepono"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobile data"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Nakakonekta"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Hindi awtomatikong kokonekta ang mobile data"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Walang koneksyon"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Walang available na iba pang network"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Walang available na network"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Mga detalye ng network"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Mag-tap ng network para kumonekta"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"I-unlock para tingnan ang mga network"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Naghahanap ng mga network…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Hind nakakonekta sa network"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Tingnan lahat"</string>
</resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 51e32458..e79daea 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Açmak için parmak izi kullanın"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Kimlik doğrulaması gerekiyor. Kimlik doğrulaması için parmak izi sensörüne dokunun."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Devam eden telefon görüşmesi"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil veri"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Bağlı"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Mobil veri otomatik olarak bağlanmıyor"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Bağlantı yok"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Kullanılabilir başka ağ yok"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Kullanılabilir ağ yok"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Kablosuz"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Ağ bilgileri"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Bağlanmak için bir ağa dokunun"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Ağları görmek için kilidi açın"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Ağlar aranıyor…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Ağa bağlanılamadı"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Tümünü göster"</string>
</resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index b1febf5..bb4ae00 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -1174,4 +1174,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Щоб відкрити, використайте відбиток пальця"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Пройдіть автентифікацію. Для цього торкніться сканера відбитків пальців."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Активний телефонний виклик"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Мобільний трафік"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Підключено"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Мобільний Інтернет не підключатиметься автоматично"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Немає з\'єднання"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Інші мережі недоступні"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Немає доступних мереж"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Деталі мережі"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Натисніть мережу, до якої потрібно підключитися"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Розблокувати, щоб переглянути мережі"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index fcb53a4..be07552 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"کھولنے کے لیے فنگر پرنٹ کا استعمال کریں"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"توثیق مطلوب ہے۔ توثیق کرنے کے لیے فنگر پرنٹ سینسر کو ٹچ کریں۔"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"جاری فون کال"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"موبائل ڈیٹا"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="NETWORKMODE">%2$s</xliff:g> / <xliff:g id="STATE">%1$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"منسلک ہے"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"کوئی کنکشن نہیں"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"کوئی دوسرا نیٹ ورک دستیاب نہیں ہے"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"کوئی نیٹ ورکس دستیاب نہیں ہیں"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"نیٹ ورک کی تفصیلات"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"منسلک کرنے کے لیے نیٹ ورک پر تھپتھپائیں"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"نیٹ ورکس کو دیکھنے کے لیے غیر مقفل کریں"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index 7822b84..dc6afec 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -1162,4 +1162,19 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Ochish uchun barmoq izidan foydalaning"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Haqiqiylikni tekshirish talab etiladi. Autentifikatsiya uchun barmoq izi skaneriga tegining."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Joriy telefon chaqiruvi"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Mobil internet"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ulandi"</string>
+ <!-- no translation found for mobile_data_off_summary (3663995422004150567) -->
+ <skip />
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Internetga ulanmagansiz"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Boshqa tarmoqlar mavjud emas"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Hech qanday tarmoq mavjud emas"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Tarmoq tafsilotlari"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Ulanish uchun tarmoq ustiga bosing"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Tarmoqlarni koʻrish uchun qulfdan chiqaring"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Tarmoqlar qidirilmoqda…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Tarmoqqa ulanmadi"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Hammasi"</string>
</resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 5a1ea4c..d22b74d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Dùng vân tay để mở"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Bạn cần phải xác thực. Hãy chạm vào cảm biến vân tay để xác thực."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Đang gọi điện thoại"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Dữ liệu di động"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Đã kết nối"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Dữ liệu di động sẽ không tự động kết nối"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Không có kết nối mạng"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Không có mạng nào khác"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Không có mạng"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Thông tin chi tiết về mạng"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Nhấn vào một mạng để kết nối"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Mở khóa để xem mạng"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Đang tìm mạng…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Không kết nối được với mạng"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Xem tất cả"</string>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index b1968ee..276fac8 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指纹即可打开"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要进行身份验证。请轻触指纹传感器以验证身份。"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"正在进行通话"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"移动数据网络"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"已连接"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"系统将不会自动连接到移动数据网络"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"无网络连接"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"没有其他可用网络"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"没有可用网络"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"WLAN"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"网络详情"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"点按要连接的网络"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解锁即可查看网络"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 7c048ea..5f519c0 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。掂一下指紋感應器就可以驗證。"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"流動數據"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"不會自動連線至流動數據"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有連線"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網絡"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網絡"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi-Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"網絡詳細資料"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕按網絡以連線"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖即可查看網絡"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 8647aed..f5f669d 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"使用指紋即可開啟"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"需要驗證。輕觸指紋感應器即可進行驗證。"</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"通話中"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"行動數據"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"已連線"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"系統將不會自動使用行動數據連線"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"沒有網路連線"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"沒有可用的其他網路"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"沒有可用的網路"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"網路詳細資料"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"輕觸要連線的網路"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"解鎖螢幕即可查看網路"</string>
+ <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>
</resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index b0c8121..560f31d 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -1162,4 +1162,18 @@
<string name="keyguard_try_fingerprint" msgid="2825130772993061165">"Sebenzisa izigxivizo zeminwe ukuvula"</string>
<string name="accessibility_fingerprint_bouncer" msgid="7189102492498735519">"Ukufakazela ubuqiniso budingekile. Thinta inzwa yezigxivizo zeminwe ukuze uqinisekise."</string>
<string name="ongoing_phone_call_content_description" msgid="5332334388483099947">"Ikholi yefoni eqhubekayo"</string>
+ <string name="mobile_data_settings_title" msgid="3955246641380064901">"Idatha yeselula"</string>
+ <string name="preference_summary_default_combination" msgid="8453246369903749670">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="NETWORKMODE">%2$s</xliff:g>"</string>
+ <string name="mobile_data_connection_active" msgid="944490013299018227">"Ixhunyiwe"</string>
+ <string name="mobile_data_off_summary" msgid="3663995422004150567">"Idatha yeselula ngeke ikwazi ukuxhuma ngokuzenzekelayo"</string>
+ <string name="mobile_data_no_connection" msgid="1713872434869947377">"Alukho uxhumano"</string>
+ <string name="non_carrier_network_unavailable" msgid="770049357024492372">"Awekho amanye amanethiwekhi atholakalayo"</string>
+ <string name="all_network_unavailable" msgid="4112774339909373349">"Awekho amanethiwekhi atholakalayo"</string>
+ <string name="turn_on_wifi" msgid="1308379840799281023">"Wi‑Fi"</string>
+ <string name="pref_title_network_details" msgid="1639455355897668883">"Imininingwane yenethiwekhi"</string>
+ <string name="tap_a_network_to_connect" msgid="1565073330852369558">"Thepha inethiwekhi ukuze uxhume"</string>
+ <string name="unlock_to_view_networks" msgid="5072880496312015676">"Vula ukuze ubuke amanethiwekhi"</string>
+ <string name="wifi_empty_list_wifi_on" msgid="3864376632067585377">"Iseshela amanethiwekhi…"</string>
+ <string name="wifi_failed_connect_message" msgid="4161863112079000071">"Yehlulekile ukuxhuma kunethiwekhi"</string>
+ <string name="see_all_networks" msgid="3773666844913168122">"Bona konke"</string>
</resources>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index b5ac0c6..2c19212 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -189,7 +189,8 @@
<!-- UDFPS colors -->
<color name="udfps_enroll_icon">#000000</color> <!-- 100% black -->
<color name="udfps_moving_target_fill">#cc4285f4</color> <!-- 80% blue -->
- <color name="udfps_enroll_progress">#ff669DF6</color> <!-- 100% blue -->
+ <color name="udfps_enroll_progress">#ff669DF6</color> <!-- blue 400 -->
+ <color name="udfps_enroll_progress_help">#ffEE675C</color> <!-- red 400 -->
<!-- Logout button -->
<color name="logout_button_bg_color">#ccffffff</color>
@@ -286,13 +287,13 @@
<!-- Internet Dialog -->
<!-- Material next state on color-->
- <color name="settingslib_state_on_color">?androidprv:attr/colorAccentPrimary</color>
+ <color name="settingslib_state_on_color">@color/settingslib_state_on</color>
<!-- Material next state off color-->
- <color name="settingslib_state_off_color">?androidprv:attr/colorAccentSecondary</color>
+ <color name="settingslib_state_off_color">@color/settingslib_state_off</color>
<!-- Material next track on color-->
- <color name="settingslib_track_on_color">?androidprv:attr/colorAccentPrimaryVariant</color>
+ <color name="settingslib_track_on_color">@color/settingslib_track_on</color>
<!-- Material next track off color-->
- <color name="settingslib_track_off_color">?androidprv:attr/colorAccentSecondaryVariant</color>
+ <color name="settingslib_track_off_color">@color/settingslib_track_off</color>
<color name="connected_network_primary_color">#191C18</color>
<color name="connected_network_secondary_color">#41493D</color>
</resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 9f2938e..37cc42e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -679,4 +679,36 @@
<!-- Flag to activate notification to contents feature -->
<bool name="config_notificationToContents">false</bool>
+
+ <!-- Respect drawable/rounded_secondary.xml intrinsic size for multiple radius corner path
+ customization for secondary display-->
+ <bool name="config_roundedCornerMultipleRadiusSecondary">false</bool>
+
+ <!-- Whether the rounded corners are multiple radius for each display in a multi-display device.
+ {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+ <array name="config_roundedCornerMultipleRadiusArray">
+ <item>@bool/config_roundedCornerMultipleRadius</item>
+ <item>@bool/config_roundedCornerMultipleRadiusSecondary</item>
+ </array>
+
+ <!-- The rounded corner drawable for each display in a multi-display device.
+ {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+ <array name="config_roundedCornerDrawableArray">
+ <item>@drawable/rounded</item>
+ <item>@drawable/rounded_secondary</item>
+ </array>
+
+ <!-- The top rounded corner drawable for each display in a multi-display device.
+ {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+ <array name="config_roundedCornerTopDrawableArray">
+ <item>@drawable/rounded_corner_top</item>
+ <item>@drawable/rounded_corner_top_secondary</item>
+ </array>
+
+ <!-- The bottom rounded corner drawable for each display in a multi-display device.
+ {@see com.android.internal.R.array#config_displayUniqueIdArray} -->
+ <array name="config_roundedCornerBottomDrawableArray">
+ <item>@drawable/rounded_corner_bottom</item>
+ <item>@drawable/rounded_corner_bottom_secondary</item>
+ </array>
</resources>
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 5699cd5..26ee5ea 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -328,11 +328,10 @@
<dimen name="global_screenshot_x_scale">80dp</dimen>
<dimen name="screenshot_bg_protection_height">242dp</dimen>
<dimen name="screenshot_preview_elevation">4dp</dimen>
- <dimen name="screenshot_offset_y">24dp</dimen>
+ <dimen name="screenshot_offset_y">8dp</dimen>
<dimen name="screenshot_offset_x">16dp</dimen>
<dimen name="screenshot_dismiss_button_tappable_size">48dp</dimen>
<dimen name="screenshot_dismiss_button_margin">8dp</dimen>
- <dimen name="screenshot_action_container_offset_y">16dp</dimen>
<dimen name="screenshot_action_container_corner_radius">18dp</dimen>
<dimen name="screenshot_action_container_padding_vertical">4dp</dimen>
<dimen name="screenshot_action_container_margin_horizontal">8dp</dimen>
@@ -1307,8 +1306,6 @@
<dimen name="qs_media_action_margin">12dp</dimen>
<dimen name="qs_seamless_height">24dp</dimen>
<dimen name="qs_seamless_icon_size">12dp</dimen>
- <dimen name="qs_seamless_fallback_icon_size">@dimen/qs_seamless_icon_size</dimen>
- <dimen name="qs_seamless_fallback_margin">20dp</dimen>
<dimen name="qs_footer_horizontal_margin">22dp</dimen>
<dimen name="qs_media_disabled_seekbar_height">1dp</dimen>
<dimen name="qs_media_enabled_seekbar_height">2dp</dimen>
@@ -1339,6 +1336,7 @@
<dimen name="magnifier_up_down_controls_height">40dp</dimen>
<!-- The extra padding to show the whole outer border -->
<dimen name="magnifier_drag_handle_padding">3dp</dimen>
+ <dimen name="magnification_max_frame_size">300dp</dimen>
<!-- Home Controls -->
<dimen name="controls_header_side_margin">4dp</dimen>
@@ -1602,15 +1600,16 @@
<!-- Internet panel related dimensions -->
<dimen name="internet_dialog_list_margin">12dp</dimen>
<dimen name="internet_dialog_list_max_height">646dp</dimen>
- <dimen name="internet_dialog_list_max_width">412dp</dimen>
+ <dimen name="internet_dialog_list_max_width">@dimen/match_parent</dimen>
<!-- Signal icon in internet dialog -->
<dimen name="signal_strength_icon_size">24dp</dimen>
<!-- Internet dialog related dimensions -->
<dimen name="internet_dialog_corner_radius">24dp</dimen>
-
- <!-- Size of internet dialog -->
+ <!-- End margin of network layout -->
+ <dimen name="internet_dialog_network_layout_margin">16dp</dimen>
+ <!-- Size of switch bar in internet dialog -->
<dimen name="settingslib_switchbar_margin">16dp</dimen>
<!-- Minimum width of switch -->
<dimen name="settingslib_min_switch_width">52dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 4093726..03ba28a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1008,7 +1008,7 @@
<string name="sensor_privacy_start_use_mic_camera_dialog_content">This unblocks access for all apps and services allowed to use your camera or microphone.</string>
<!-- Default name for the media device shown in the output switcher when the name is not available [CHAR LIMIT=30] -->
- <string name="media_seamless_remote_device">Device</string>
+ <string name="media_seamless_other_device">Other device</string>
<!-- QuickStep: Accessibility to toggle overview [CHAR LIMIT=40] -->
<string name="quick_step_accessibility_toggle_overview">Toggle Overview</string>
@@ -2990,8 +2990,6 @@
<!-- Content description for a chip in the status bar showing that the user is currently on a phone call. [CHAR LIMIT=NONE] -->
<string name="ongoing_phone_call_content_description">Ongoing phone call</string>
- <!-- Provider Model: Title of the airplane mode in the internet dialog. [CHAR LIMIT=50] -->
- <string name="airplane_mode">Airplane mode</string>
<!-- Provider Model: Default title of the mobile network in the mobile layout. [CHAR LIMIT=50] -->
<string name="mobile_data_settings_title">Mobile data</string>
<!-- Provider Model: Summary text separator for preferences including a short description
@@ -3002,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/res/xml/media_collapsed.xml b/packages/SystemUI/res/xml/media_collapsed.xml
index d6c6a60..c3510b6 100644
--- a/packages/SystemUI/res/xml/media_collapsed.xml
+++ b/packages/SystemUI/res/xml/media_collapsed.xml
@@ -44,23 +44,6 @@
/>
<Constraint
- android:id="@+id/media_seamless_fallback"
- android:layout_width="@dimen/qs_seamless_fallback_icon_size"
- android:layout_height="@dimen/qs_seamless_fallback_icon_size"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="@dimen/qs_media_padding"
- android:layout_marginStart="@dimen/qs_center_guideline_padding"
- android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
- android:alpha="0.5"
- android:visibility="gone"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintBottom_toTopOf="@id/center_horizontal_guideline"
- app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
- app:layout_constraintEnd_toEndOf="parent"
- />
-
- <Constraint
android:id="@+id/album_art"
android:layout_width="@dimen/qs_media_album_size_small"
android:layout_height="@dimen/qs_media_album_size_small"
diff --git a/packages/SystemUI/res/xml/media_expanded.xml b/packages/SystemUI/res/xml/media_expanded.xml
index 0e284e6..6b83aae 100644
--- a/packages/SystemUI/res/xml/media_expanded.xml
+++ b/packages/SystemUI/res/xml/media_expanded.xml
@@ -45,22 +45,6 @@
android:layout_marginBottom="4dp" />
<Constraint
- android:id="@+id/media_seamless_fallback"
- android:layout_width="@dimen/qs_seamless_fallback_icon_size"
- android:layout_height="@dimen/qs_seamless_fallback_icon_size"
- android:layout_marginTop="@dimen/qs_media_padding"
- android:layout_marginBottom="16dp"
- android:layout_marginStart="@dimen/qs_center_guideline_padding"
- android:layout_marginEnd="@dimen/qs_seamless_fallback_margin"
- android:alpha="0.5"
- android:visibility="gone"
- app:layout_constraintHorizontal_bias="1"
- app:layout_constraintTop_toTopOf="parent"
- app:layout_constraintStart_toEndOf="@id/center_vertical_guideline"
- app:layout_constraintEnd_toEndOf="parent"
- />
-
- <Constraint
android:id="@+id/album_art"
android:layout_width="@dimen/qs_media_album_size"
android:layout_height="@dimen/qs_media_album_size"
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
index bcfb774..9808374 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/navigationbar/RegionSamplingHelper.java
@@ -72,6 +72,8 @@
private boolean mWindowVisible;
private boolean mWindowHasBlurs;
private SurfaceControl mRegisteredStopLayer = null;
+ // A copy of mRegisteredStopLayer where we own the life cycle and can access from a bg thread.
+ private SurfaceControl mWrappedStopLayer = null;
private ViewTreeObserver.OnDrawListener mUpdateOnDraw = new ViewTreeObserver.OnDrawListener() {
@Override
public void onDraw() {
@@ -184,16 +186,21 @@
}
if (!mSamplingRequestBounds.equals(mRegisteredSamplingBounds)
|| mRegisteredStopLayer != stopLayerControl) {
- // We only want to reregister if something actually changed
+ // We only want to re-register if something actually changed
unregisterSamplingListener();
mSamplingListenerRegistered = true;
- SurfaceControl registeredStopLayer = stopLayerControl;
+ SurfaceControl wrappedStopLayer = stopLayerControl == null
+ ? null : new SurfaceControl(stopLayerControl, "regionSampling");
mBackgroundExecutor.execute(() -> {
+ if (wrappedStopLayer != null && !wrappedStopLayer.isValid()) {
+ return;
+ }
CompositionSamplingListener.register(mSamplingListener, DEFAULT_DISPLAY,
- registeredStopLayer, mSamplingRequestBounds);
+ wrappedStopLayer, mSamplingRequestBounds);
});
mRegisteredSamplingBounds.set(mSamplingRequestBounds);
- mRegisteredStopLayer = registeredStopLayer;
+ mRegisteredStopLayer = stopLayerControl;
+ mWrappedStopLayer = wrappedStopLayer;
}
mFirstSamplingAfterStart = false;
} else {
@@ -204,10 +211,14 @@
private void unregisterSamplingListener() {
if (mSamplingListenerRegistered) {
mSamplingListenerRegistered = false;
+ SurfaceControl wrappedStopLayer = mWrappedStopLayer;
mRegisteredStopLayer = null;
mRegisteredSamplingBounds.setEmpty();
mBackgroundExecutor.execute(() -> {
CompositionSamplingListener.unregister(mSamplingListener);
+ if (wrappedStopLayer != null && wrappedStopLayer.isValid()) {
+ wrappedStopLayer.release();
+ }
});
}
}
@@ -262,6 +273,7 @@
pw.println(" mWindowHasBlurs: " + mWindowHasBlurs);
pw.println(" mWaitingOnDraw: " + mWaitingOnDraw);
pw.println(" mRegisteredStopLayer: " + mRegisteredStopLayer);
+ pw.println(" mWrappedStopLayer: " + mWrappedStopLayer);
pw.println(" mIsDestroyed: " + mIsDestroyed);
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
index b827356..196e6f3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/QuickStepContract.java
@@ -285,8 +285,8 @@
* These values are expressed in pixels because they should not respect display or font
* scaling, this means that we don't have to reload them on config changes.
*/
- public static float getWindowCornerRadius(Resources resources) {
- return ScreenDecorationsUtils.getWindowCornerRadius(resources);
+ public static float getWindowCornerRadius(Context context) {
+ return ScreenDecorationsUtils.getWindowCornerRadius(context);
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
index 025d7ef..7aee721 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationAdapterCompat.java
@@ -37,6 +37,7 @@
import android.view.SurfaceControl;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import java.util.ArrayList;
@@ -62,7 +63,8 @@
/** Helper to just build a remote transition. Use this if the legacy adapter isn't needed. */
public static RemoteTransitionCompat buildRemoteTransition(RemoteAnimationRunnerCompat runner) {
- return new RemoteTransitionCompat(wrapRemoteTransition(runner));
+ return new RemoteTransitionCompat(
+ new RemoteTransition(wrapRemoteTransition(runner)));
}
public RemoteTransitionCompat getRemoteTransition() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
index 0a14657..30db136 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteAnimationTargetCompat.java
@@ -71,11 +71,11 @@
public final boolean allowEnterPip;
public final int rotationChange;
public final int windowType;
+ public final WindowConfiguration windowConfiguration;
private final SurfaceControl mStartLeash;
// Fields used only to unrap into RemoteAnimationTarget
- private final WindowConfiguration windowConfiguration;
private final Rect startBounds;
public RemoteAnimationTargetCompat(RemoteAnimationTarget app) {
@@ -235,8 +235,9 @@
rotationChange = change.getEndRotation() - change.getStartRotation();
windowType = INVALID_WINDOW_TYPE;
- // TODO this probably isn't right but it's unused for now /shrug
- windowConfiguration = new WindowConfiguration();
+ windowConfiguration = change.getTaskInfo() != null
+ ? change.getTaskInfo().configuration.windowConfiguration
+ : new WindowConfiguration();
startBounds = change.getStartAbsBounds();
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
index aac5235..9ec95a3 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java
@@ -42,6 +42,7 @@
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
import android.window.PictureInPictureSurfaceTransaction;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
import android.window.WindowContainerToken;
@@ -63,16 +64,16 @@
public class RemoteTransitionCompat implements Parcelable {
private static final String TAG = "RemoteTransitionCompat";
- @NonNull final IRemoteTransition mTransition;
+ @NonNull final RemoteTransition mTransition;
@Nullable TransitionFilter mFilter = null;
- RemoteTransitionCompat(IRemoteTransition transition) {
+ RemoteTransitionCompat(RemoteTransition transition) {
mTransition = transition;
}
public RemoteTransitionCompat(@NonNull RemoteTransitionRunner runner,
@NonNull Executor executor) {
- mTransition = new IRemoteTransition.Stub() {
+ IRemoteTransition remote = new IRemoteTransition.Stub() {
@Override
public void startAnimation(IBinder transition, TransitionInfo info,
SurfaceControl.Transaction t,
@@ -102,12 +103,13 @@
finishAdapter));
}
};
+ mTransition = new RemoteTransition(remote);
}
/** Constructor specifically for recents animation */
public RemoteTransitionCompat(RecentsAnimationListener recents,
RecentsAnimationControllerCompat controller) {
- mTransition = new IRemoteTransition.Stub() {
+ IRemoteTransition remote = new IRemoteTransition.Stub() {
final RecentsControllerWrap mRecentsSession = new RecentsControllerWrap();
IBinder mToken = null;
@@ -166,6 +168,7 @@
}
}
};
+ mTransition = new RemoteTransition(remote);
}
/** Adds a filter check that restricts this remote transition to home open transitions. */
@@ -381,7 +384,7 @@
- // Code below generated by codegen v1.0.21.
+ // Code below generated by codegen v1.0.23.
//
// DO NOT MODIFY!
// CHECKSTYLE:OFF Generated code
@@ -393,8 +396,21 @@
// Settings > Editor > Code Style > Formatter Control
//@formatter:off
+
@DataClass.Generated.Member
- public @NonNull IRemoteTransition getTransition() {
+ /* package-private */ RemoteTransitionCompat(
+ @NonNull RemoteTransition transition,
+ @Nullable TransitionFilter filter) {
+ this.mTransition = transition;
+ com.android.internal.util.AnnotationValidations.validate(
+ NonNull.class, null, mTransition);
+ this.mFilter = filter;
+
+ // onConstructed(); // You can define this method to get a callback
+ }
+
+ @DataClass.Generated.Member
+ public @NonNull RemoteTransition getTransition() {
return mTransition;
}
@@ -412,7 +428,7 @@
byte flg = 0;
if (mFilter != null) flg |= 0x2;
dest.writeByte(flg);
- dest.writeStrongInterface(mTransition);
+ dest.writeTypedObject(mTransition, flags);
if (mFilter != null) dest.writeTypedObject(mFilter, flags);
}
@@ -428,7 +444,7 @@
// static FieldType unparcelFieldName(Parcel in) { ... }
byte flg = in.readByte();
- IRemoteTransition transition = IRemoteTransition.Stub.asInterface(in.readStrongBinder());
+ RemoteTransition transition = (RemoteTransition) in.readTypedObject(RemoteTransition.CREATOR);
TransitionFilter filter = (flg & 0x2) == 0 ? null : (TransitionFilter) in.readTypedObject(TransitionFilter.CREATOR);
this.mTransition = transition;
@@ -460,20 +476,20 @@
@DataClass.Generated.Member
public static class Builder {
- private @NonNull IRemoteTransition mTransition;
+ private @NonNull RemoteTransition mTransition;
private @Nullable TransitionFilter mFilter;
private long mBuilderFieldsSet = 0L;
public Builder(
- @NonNull IRemoteTransition transition) {
+ @NonNull RemoteTransition transition) {
mTransition = transition;
com.android.internal.util.AnnotationValidations.validate(
NonNull.class, null, mTransition);
}
@DataClass.Generated.Member
- public @NonNull Builder setTransition(@NonNull IRemoteTransition value) {
+ public @NonNull Builder setTransition(@NonNull RemoteTransition value) {
checkNotUsed();
mBuilderFieldsSet |= 0x1;
mTransition = value;
@@ -496,8 +512,9 @@
if ((mBuilderFieldsSet & 0x2) == 0) {
mFilter = null;
}
- RemoteTransitionCompat o = new RemoteTransitionCompat(mTransition);
- o.mFilter = this.mFilter;
+ RemoteTransitionCompat o = new RemoteTransitionCompat(
+ mTransition,
+ mFilter);
return o;
}
@@ -510,10 +527,10 @@
}
@DataClass.Generated(
- time = 1606862689344L,
- codegenVersion = "1.0.21",
+ time = 1629321609807L,
+ codegenVersion = "1.0.23",
sourceFile = "frameworks/base/packages/SystemUI/shared/src/com/android/systemui/shared/system/RemoteTransitionCompat.java",
- inputSignatures = "final @android.annotation.NonNull com.android.systemui.shared.system.IRemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic void addHomeOpenCheck()\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass")
+ inputSignatures = "private static final java.lang.String TAG\nfinal @android.annotation.NonNull android.window.RemoteTransition mTransition\n @android.annotation.Nullable android.window.TransitionFilter mFilter\npublic void addHomeOpenCheck(android.content.ComponentName)\nclass RemoteTransitionCompat extends java.lang.Object implements [android.os.Parcelable]\nprivate com.android.systemui.shared.system.RecentsAnimationControllerCompat mWrapped\nprivate android.window.IRemoteTransitionFinishedCallback mFinishCB\nprivate android.window.WindowContainerToken mPausingTask\nprivate android.window.WindowContainerToken mPipTask\nprivate android.window.TransitionInfo mInfo\nprivate android.view.SurfaceControl mOpeningLeash\nprivate android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl> mLeashMap\nprivate android.window.PictureInPictureSurfaceTransaction mPipTransaction\nprivate android.os.IBinder mTransition\n void setup(com.android.systemui.shared.system.RecentsAnimationControllerCompat,android.window.TransitionInfo,android.window.IRemoteTransitionFinishedCallback,android.window.WindowContainerToken,android.window.WindowContainerToken,android.util.ArrayMap<android.view.SurfaceControl,android.view.SurfaceControl>,android.os.IBinder)\n @android.annotation.SuppressLint boolean merge(android.window.TransitionInfo,android.view.SurfaceControl.Transaction,com.android.systemui.shared.system.RecentsAnimationListener)\npublic @java.lang.Override com.android.systemui.shared.recents.model.ThumbnailData screenshotTask(int)\npublic @java.lang.Override void setInputConsumerEnabled(boolean)\npublic @java.lang.Override void setAnimationTargetsBehindSystemBars(boolean)\npublic @java.lang.Override void hideCurrentInputMethod()\npublic @java.lang.Override void setFinishTaskTransaction(int,android.window.PictureInPictureSurfaceTransaction,android.view.SurfaceControl)\npublic @java.lang.Override @android.annotation.SuppressLint void finish(boolean,boolean)\npublic @java.lang.Override void setDeferCancelUntilNextTransition(boolean,boolean)\npublic @java.lang.Override void cleanupScreenshot()\npublic @java.lang.Override void setWillFinishToHome(boolean)\npublic @java.lang.Override boolean removeTask(int)\npublic @java.lang.Override void detachNavigationBarFromApp(boolean)\npublic @java.lang.Override void animateNavigationBarToApp(long)\nclass RecentsControllerWrap extends com.android.systemui.shared.system.RecentsAnimationControllerCompat implements []\n@com.android.internal.util.DataClass")
@Deprecated
private void __metadata() {}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
index b38270c..85d5de0 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/WindowManagerWrapper.java
@@ -27,10 +27,12 @@
import android.os.Handler;
import android.os.RemoteException;
import android.util.Log;
+import android.view.InsetsController;
import android.view.InsetsState;
import android.view.SurfaceControl;
import android.view.WindowManager;
import android.view.WindowManagerGlobal;
+import android.view.animation.Interpolator;
import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture;
import com.android.systemui.shared.recents.view.RecentsTransition;
@@ -89,6 +91,9 @@
public static final int ITYPE_BOTTOM_TAPPABLE_ELEMENT =
InsetsState.ITYPE_BOTTOM_TAPPABLE_ELEMENT;
+ public static final int ANIMATION_DURATION_RESIZE = InsetsController.ANIMATION_DURATION_RESIZE;
+ public static final Interpolator RESIZE_INTERPOLATOR = InsetsController.RESIZE_INTERPOLATOR;
+
private static final WindowManagerWrapper sInstance = new WindowManagerWrapper();
public static WindowManagerWrapper getInstance() {
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
index 9b5eae8..49cd279 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/UnfoldTransitionFactory.kt
@@ -29,6 +29,7 @@
import com.android.systemui.unfold.progress.PhysicsBasedUnfoldTransitionProgressProvider
import com.android.systemui.unfold.updates.DeviceFoldStateProvider
import com.android.systemui.unfold.updates.hinge.EmptyHingeAngleProvider
+import com.android.systemui.unfold.updates.hinge.HingeSensorAngleProvider
import com.android.systemui.unfold.updates.hinge.RotationSensorHingeAngleProvider
import java.lang.IllegalStateException
import java.util.concurrent.Executor
@@ -50,7 +51,13 @@
val hingeAngleProvider =
if (config.mode == ANIMATION_MODE_HINGE_ANGLE) {
- RotationSensorHingeAngleProvider(sensorManager)
+ // TODO: after removing temporary "config.mode" we should just
+ // switch between fixed timing and hinge sensor based on this flag
+ if (config.isHingeAngleEnabled) {
+ HingeSensorAngleProvider(sensorManager)
+ } else {
+ RotationSensorHingeAngleProvider(sensorManager)
+ }
} else {
EmptyHingeAngleProvider()
}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
index fa6b5de..e7c6998a 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/ResourceUnfoldTransitionConfig.kt
@@ -25,6 +25,9 @@
override val isEnabled: Boolean
get() = readIsEnabled() && mode != ANIMATION_MODE_DISABLED
+ override val isHingeAngleEnabled: Boolean
+ get() = readIsHingeAngleEnabled()
+
@AnimationMode
override val mode: Int
get() = SystemProperties.getInt(UNFOLD_TRANSITION_MODE_PROPERTY_NAME,
@@ -32,6 +35,9 @@
private fun readIsEnabled(): Boolean = context.resources
.getBoolean(com.android.internal.R.bool.config_unfoldTransitionEnabled)
+
+ private fun readIsHingeAngleEnabled(): Boolean = context.resources
+ .getBoolean(com.android.internal.R.bool.config_unfoldTransitionHingeAngle)
}
/**
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
index 75d9dc3..a569757 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/config/UnfoldTransitionConfig.kt
@@ -19,6 +19,7 @@
interface UnfoldTransitionConfig {
val isEnabled: Boolean
+ val isHingeAngleEnabled: Boolean
@AnimationMode
val mode: Int
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
index b111892..10e6c2b 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/progress/PhysicsBasedUnfoldTransitionProgressProvider.kt
@@ -16,6 +16,7 @@
package com.android.systemui.unfold.progress
import android.os.Handler
+import android.util.MathUtils.saturate
import androidx.dynamicanimation.animation.DynamicAnimation
import androidx.dynamicanimation.animation.FloatPropertyCompat
import androidx.dynamicanimation.animation.SpringAnimation
@@ -24,6 +25,7 @@
import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_CLOSED
import com.android.systemui.unfold.updates.FOLD_UPDATE_FINISH_FULL_OPEN
+import com.android.systemui.unfold.updates.FOLD_UPDATE_START_CLOSING
import com.android.systemui.unfold.updates.FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE
import com.android.systemui.unfold.updates.FoldStateProvider
import com.android.systemui.unfold.updates.FoldStateProvider.FoldUpdate
@@ -33,7 +35,6 @@
* Maps fold updates to unfold transition progress using DynamicAnimation.
*
* TODO(b/193793338) Current limitations:
- * - doesn't handle folding transition
* - doesn't handle postures
*/
internal class PhysicsBasedUnfoldTransitionProgressProvider(
@@ -75,14 +76,20 @@
override fun onHingeAngleUpdate(angle: Float) {
if (!isTransitionRunning || isAnimatedCancelRunning) return
- springAnimation.animateToFinalPosition(angle / 180f)
+ val progress = saturate(angle / FINAL_HINGE_ANGLE_POSITION)
+ springAnimation.animateToFinalPosition(progress)
}
override fun onFoldUpdate(@FoldUpdate update: Int) {
when (update) {
FOLD_UPDATE_UNFOLDED_SCREEN_AVAILABLE -> {
- onStartTransition()
startTransition(startValue = 0f)
+
+ // Stop the animation if the device has already opened by the time when
+ // the display is available as we won't receive the full open event anymore
+ if (foldStateProvider.isFullyOpened) {
+ cancelTransition(endValue = 1f, animate = true)
+ }
}
FOLD_UPDATE_FINISH_FULL_OPEN -> {
cancelTransition(endValue = 1f, animate = true)
@@ -90,13 +97,16 @@
FOLD_UPDATE_FINISH_CLOSED -> {
cancelTransition(endValue = 0f, animate = false)
}
+ FOLD_UPDATE_START_CLOSING -> {
+ startTransition(startValue = 1f)
+ }
}
}
private fun cancelTransition(endValue: Float, animate: Boolean) {
handler.removeCallbacks(timeoutRunnable)
- if (animate) {
+ if (isTransitionRunning && animate) {
isAnimatedCancelRunning = true
springAnimation.animateToFinalPosition(endValue)
} else {
@@ -182,3 +192,4 @@
private const val TRANSITION_TIMEOUT_MILLIS = 2000L
private const val SPRING_STIFFNESS = 200.0f
private const val MINIMAL_VISIBLE_CHANGE = 0.001f
+private const val FINAL_HINGE_ANGLE_POSITION = 165f
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
index 949652b..c37ab06 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/DeviceFoldStateProvider.kt
@@ -68,20 +68,29 @@
outputListeners.remove(listener)
}
+ override val isFullyOpened: Boolean
+ get() = !isFolded && lastFoldUpdate == FOLD_UPDATE_FINISH_FULL_OPEN
+
private fun onHingeAngle(angle: Float) {
when (lastFoldUpdate) {
FOLD_UPDATE_FINISH_FULL_OPEN -> {
- if (FULLY_OPEN_DEGREES - angle > MOVEMENT_THRESHOLD_DEGREES) {
+ if (FULLY_OPEN_DEGREES - angle > START_CLOSING_THRESHOLD_DEGREES) {
lastFoldUpdate = FOLD_UPDATE_START_CLOSING
outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_START_CLOSING) }
}
}
- FOLD_UPDATE_START_OPENING, FOLD_UPDATE_START_CLOSING -> {
+ FOLD_UPDATE_START_OPENING -> {
if (FULLY_OPEN_DEGREES - angle < FULLY_OPEN_THRESHOLD_DEGREES) {
lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
}
}
+ FOLD_UPDATE_START_CLOSING -> {
+ if (FULLY_OPEN_DEGREES - angle < START_CLOSING_THRESHOLD_DEGREES) {
+ lastFoldUpdate = FOLD_UPDATE_FINISH_FULL_OPEN
+ outputListeners.forEach { it.onFoldUpdate(FOLD_UPDATE_FINISH_FULL_OPEN) }
+ }
+ }
}
outputListeners.forEach { it.onHingeAngleUpdate(angle) }
@@ -120,5 +129,5 @@
}
}
-private const val MOVEMENT_THRESHOLD_DEGREES = 10f
-private const val FULLY_OPEN_THRESHOLD_DEGREES = 10f
\ No newline at end of file
+private const val START_CLOSING_THRESHOLD_DEGREES = 95f
+private const val FULLY_OPEN_THRESHOLD_DEGREES = 15f
\ No newline at end of file
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
index 4c6d241..11984b93 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/FoldStateProvider.kt
@@ -28,6 +28,8 @@
fun start()
fun stop()
+ val isFullyOpened: Boolean
+
interface FoldUpdatesListener {
fun onHingeAngleUpdate(@FloatRange(from = 0.0, to = 180.0) angle: Float)
fun onFoldUpdate(@FoldUpdate update: Int)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
index 8549913..2520d35 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeAngleProvider.kt
@@ -3,6 +3,12 @@
import androidx.core.util.Consumer
import com.android.systemui.statusbar.policy.CallbackController
+/**
+ * Emits device hinge angle values (angle between two integral parts of the device).
+ * The hinge angle could be from 0 to 360 degrees inclusive.
+ * For foldable devices usually 0 corresponds to fully closed (folded) state and
+ * 180 degrees corresponds to fully open (flat) state
+ */
internal interface HingeAngleProvider : CallbackController<Consumer<Float>> {
fun start()
fun stop()
diff --git a/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
new file mode 100644
index 0000000..a42ebef
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/unfold/updates/hinge/HingeSensorAngleProvider.kt
@@ -0,0 +1,42 @@
+package com.android.systemui.unfold.updates.hinge
+
+import android.hardware.Sensor
+import android.hardware.SensorEvent
+import android.hardware.SensorEventListener
+import android.hardware.SensorManager
+import androidx.core.util.Consumer
+
+internal class HingeSensorAngleProvider(
+ private val sensorManager: SensorManager
+) : HingeAngleProvider {
+
+ private val sensorListener = HingeAngleSensorListener()
+ private val listeners: MutableList<Consumer<Float>> = arrayListOf()
+
+ override fun start() {
+ val sensor = sensorManager.getDefaultSensor(Sensor.TYPE_HINGE_ANGLE)
+ sensorManager.registerListener(sensorListener, sensor, SensorManager.SENSOR_DELAY_FASTEST)
+ }
+
+ override fun stop() {
+ sensorManager.unregisterListener(sensorListener)
+ }
+
+ override fun removeCallback(listener: Consumer<Float>) {
+ listeners.remove(listener)
+ }
+
+ override fun addCallback(listener: Consumer<Float>) {
+ listeners.add(listener)
+ }
+
+ private inner class HingeAngleSensorListener : SensorEventListener {
+
+ override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {
+ }
+
+ override fun onSensorChanged(event: SensorEvent) {
+ listeners.forEach { it.accept(event.values[0]) }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index 840e8c8..26059068 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -317,7 +317,8 @@
mRunningOneHandedAnimator = null;
}
- int targetTranslation = mIsSecurityViewLeftAligned ? 0 : (int) (getMeasuredWidth() / 2f);
+ int targetTranslation = mIsSecurityViewLeftAligned
+ ? 0 : (int) (getMeasuredWidth() - mSecurityViewFlipper.getWidth());
if (animate) {
mRunningOneHandedAnimator =
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
index 28a54d5..e115c34 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardVisibilityHelper.java
@@ -132,8 +132,7 @@
.alpha(1f)
.withEndAction(mAnimateKeyguardStatusViewVisibleEndRunnable)
.start();
- } else if (mUnlockedScreenOffAnimationController
- .isScreenOffLightRevealAnimationPlaying()) {
+ } else if (mUnlockedScreenOffAnimationController.shouldAnimateInKeyguard()) {
mKeyguardViewVisibilityAnimating = true;
// Ask the screen off animation controller to animate the keyguard visibility for us
diff --git a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
index 47f0714..2a4022c 100644
--- a/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/LockIconViewController.java
@@ -501,8 +501,10 @@
if (!wasClickableOnDownEvent()) {
return;
}
+ mDetectedLongPress = true;
- if (mVibrator != null) {
+ if (onAffordanceClick() && mVibrator != null) {
+ // only vibrate if the click went through and wasn't intercepted by falsing
mVibrator.vibrate(
Process.myUid(),
getContext().getOpPackageName(),
@@ -510,8 +512,6 @@
"lockIcon-onLongPress",
VIBRATION_SONIFICATION_ATTRIBUTES);
}
- mDetectedLongPress = true;
- onAffordanceClick();
}
public boolean onSingleTapUp(MotionEvent e) {
@@ -535,9 +535,14 @@
return mDownDetected;
}
- private void onAffordanceClick() {
+ /**
+ * Whether we tried to launch the affordance.
+ *
+ * If falsing intercepts the click, returns false.
+ */
+ private boolean onAffordanceClick() {
if (mFalsingManager.isFalseTouch(LOCK_ICON)) {
- return;
+ return false;
}
// pre-emptively set to true to hide view
@@ -547,6 +552,7 @@
}
updateVisibility();
mKeyguardViewController.showBouncer(/* scrim */ true);
+ return true;
}
});
diff --git a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
index 0b0e430..153da4b 100644
--- a/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
+++ b/packages/SystemUI/src/com/android/keyguard/dagger/KeyguardStatusBarViewComponent.java
@@ -19,6 +19,7 @@
import com.android.keyguard.KeyguardStatusViewController;
import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
import com.android.systemui.statusbar.phone.KeyguardStatusBarViewController;
+import com.android.systemui.statusbar.phone.NotificationPanelViewController;
import dagger.BindsInstance;
import dagger.Subcomponent;
@@ -36,8 +37,8 @@
interface Factory {
KeyguardStatusBarViewComponent build(
@BindsInstance KeyguardStatusBarView view,
- @BindsInstance KeyguardStatusBarViewController.ViewStateProvider
- viewStateProvider);
+ @BindsInstance NotificationPanelViewController.NotificationPanelViewStateProvider
+ notificationPanelViewStateProvider);
}
/** Builds a {@link KeyguardStatusViewController}. */
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index f653088..19d029bf 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -42,6 +42,7 @@
import android.content.res.ColorStateList;
import android.content.res.Configuration;
import android.content.res.Resources;
+import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Matrix;
@@ -59,6 +60,7 @@
import android.os.UserHandle;
import android.provider.Settings.Secure;
import android.util.DisplayMetrics;
+import android.util.DisplayUtils;
import android.util.Log;
import android.view.Display;
import android.view.DisplayCutout;
@@ -66,6 +68,7 @@
import android.view.DisplayInfo;
import android.view.Gravity;
import android.view.LayoutInflater;
+import android.view.RoundedCorners;
import android.view.Surface;
import android.view.View;
import android.view.View.OnLayoutChangeListener;
@@ -159,6 +162,10 @@
private boolean mIsRoundedCornerMultipleRadius;
private int mStatusBarHeightPortrait;
private int mStatusBarHeightLandscape;
+ private Drawable mRoundedCornerDrawable;
+ private Drawable mRoundedCornerDrawableTop;
+ private Drawable mRoundedCornerDrawableBottom;
+ private String mDisplayUniqueId;
private CameraAvailabilityListener.CameraTransitionCallback mCameraTransitionCallback =
new CameraAvailabilityListener.CameraTransitionCallback() {
@@ -244,10 +251,11 @@
private void startOnScreenDecorationsThread() {
mRotation = mContext.getDisplay().getRotation();
+ mDisplayUniqueId = mContext.getDisplay().getUniqueId();
+ mIsRoundedCornerMultipleRadius = isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
mWindowManager = mContext.getSystemService(WindowManager.class);
mDisplayManager = mContext.getSystemService(DisplayManager.class);
- mIsRoundedCornerMultipleRadius = mContext.getResources().getBoolean(
- R.bool.config_roundedCornerMultipleRadius);
+ updateRoundedCornerDrawable();
updateRoundedCornerRadii();
setupDecorations();
setupCameraListener();
@@ -287,6 +295,14 @@
}
}
}
+ final String newUniqueId = mContext.getDisplay().getUniqueId();
+ if ((newUniqueId != null && !newUniqueId.equals(mDisplayUniqueId))
+ || (mDisplayUniqueId != null && !mDisplayUniqueId.equals(newUniqueId))) {
+ mDisplayUniqueId = newUniqueId;
+ mIsRoundedCornerMultipleRadius =
+ isRoundedCornerMultipleRadius(mContext, mDisplayUniqueId);
+ updateRoundedCornerDrawable();
+ }
updateOrientation();
}
};
@@ -474,6 +490,7 @@
updateRoundedCornerView(pos, R.id.left);
updateRoundedCornerView(pos, R.id.right);
updateRoundedCornerSize(mRoundedDefault, mRoundedDefaultTop, mRoundedDefaultBottom);
+ updateRoundedCornerImageView();
// update cutout view rotation
if (mCutoutViews != null && mCutoutViews[pos] != null) {
@@ -551,7 +568,8 @@
}
}
- private static int getBoundPositionFromRotation(@BoundsPosition int pos, int rotation) {
+ @VisibleForTesting
+ static int getBoundPositionFromRotation(@BoundsPosition int pos, int rotation) {
return (pos - rotation) < 0
? pos - rotation + DisplayCutout.BOUNDS_POSITION_LENGTH
: pos - rotation;
@@ -677,27 +695,26 @@
// upgrading all of the configs to contain (width, height) pairs. Instead assume that a
// device configured using the single integer config value is okay with drawing the corners
// as a square
- final int newRoundedDefault = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.rounded_corner_radius);
- final int newRoundedDefaultTop = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.rounded_corner_radius_top);
- final int newRoundedDefaultBottom = mContext.getResources().getDimensionPixelSize(
- com.android.internal.R.dimen.rounded_corner_radius_bottom);
+ final int newRoundedDefault = RoundedCorners.getRoundedCornerRadius(
+ mContext.getResources(), mDisplayUniqueId);
+ final int newRoundedDefaultTop = RoundedCorners.getRoundedCornerTopRadius(
+ mContext.getResources(), mDisplayUniqueId);
+ final int newRoundedDefaultBottom = RoundedCorners.getRoundedCornerBottomRadius(
+ mContext.getResources(), mDisplayUniqueId);
final boolean changed = mRoundedDefault.x != newRoundedDefault
|| mRoundedDefaultTop.x != newRoundedDefaultTop
|| mRoundedDefaultBottom.x != newRoundedDefaultBottom;
-
if (changed) {
// If config_roundedCornerMultipleRadius set as true, ScreenDecorations respect the
// (width, height) size of drawable/rounded.xml instead of rounded_corner_radius
if (mIsRoundedCornerMultipleRadius) {
- Drawable d = mContext.getDrawable(R.drawable.rounded);
- mRoundedDefault.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
- d = mContext.getDrawable(R.drawable.rounded_corner_top);
- mRoundedDefaultTop.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
- d = mContext.getDrawable(R.drawable.rounded_corner_bottom);
- mRoundedDefaultBottom.set(d.getIntrinsicWidth(), d.getIntrinsicHeight());
+ mRoundedDefault.set(mRoundedCornerDrawable.getIntrinsicWidth(),
+ mRoundedCornerDrawable.getIntrinsicHeight());
+ mRoundedDefaultTop.set(mRoundedCornerDrawableTop.getIntrinsicWidth(),
+ mRoundedCornerDrawableTop.getIntrinsicHeight());
+ mRoundedDefaultBottom.set(mRoundedCornerDrawableBottom.getIntrinsicWidth(),
+ mRoundedCornerDrawableBottom.getIntrinsicHeight());
} else {
mRoundedDefault.set(newRoundedDefault, newRoundedDefault);
mRoundedDefaultTop.set(newRoundedDefaultTop, newRoundedDefaultTop);
@@ -707,6 +724,89 @@
}
}
+ /**
+ * Gets whether the rounded corners are multiple radii for current display.
+ *
+ * Loads the default config {@link R.bool#config_roundedCornerMultipleRadius} if
+ * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static boolean isRoundedCornerMultipleRadius(Context context, String displayUniqueId) {
+ final Resources res = context.getResources();
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerMultipleRadiusArray);
+ boolean isMultipleRadius;
+ if (index >= 0 && index < array.length()) {
+ isMultipleRadius = array.getBoolean(index, false);
+ } else {
+ isMultipleRadius = res.getBoolean(R.bool.config_roundedCornerMultipleRadius);
+ }
+ array.recycle();
+ return isMultipleRadius;
+ }
+
+ /**
+ * Gets the rounded corner drawable for current display.
+ *
+ * Loads the default config {@link R.drawable#rounded} if
+ * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static Drawable getRoundedCornerDrawable(Context context, String displayUniqueId) {
+ final Resources res = context.getResources();
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerDrawableArray);
+ Drawable drawable;
+ if (index >= 0 && index < array.length()) {
+ drawable = array.getDrawable(index);
+ } else {
+ drawable = context.getDrawable(R.drawable.rounded);
+ }
+ array.recycle();
+ return drawable;
+ }
+
+ /**
+ * Gets the rounded corner top drawable for current display.
+ *
+ * Loads the default config {@link R.drawable#rounded_corner_top} if
+ * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static Drawable getRoundedCornerTopDrawable(Context context, String displayUniqueId) {
+ final Resources res = context.getResources();
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(R.array.config_roundedCornerTopDrawableArray);
+ Drawable drawable;
+ if (index >= 0 && index < array.length()) {
+ drawable = array.getDrawable(index);
+ } else {
+ drawable = context.getDrawable(R.drawable.rounded_corner_top);
+ }
+ array.recycle();
+ return drawable;
+ }
+
+ /**
+ * Gets the rounded corner bottom drawable for current display.
+ *
+ * Loads the default config {@link R.drawable#rounded_corner_bottom} if
+ * {@link com.android.internal.R.array#config_displayUniqueIdArray} is not set.
+ */
+ private static Drawable getRoundedCornerBottomDrawable(
+ Context context, String displayUniqueId) {
+ final Resources res = context.getResources();
+ final int index = DisplayUtils.getDisplayUniqueIdConfigIndex(res, displayUniqueId);
+ final TypedArray array = res.obtainTypedArray(
+ R.array.config_roundedCornerBottomDrawableArray);
+ Drawable drawable;
+ if (index >= 0 && index < array.length()) {
+ drawable = array.getDrawable(index);
+ } else {
+ drawable = context.getDrawable(R.drawable.rounded_corner_bottom);
+ }
+ array.recycle();
+ return drawable;
+ }
+
private void updateRoundedCornerView(@BoundsPosition int pos, int id) {
final View rounded = mOverlays[pos].findViewById(id);
if (rounded == null) {
@@ -837,6 +937,52 @@
});
}
+ private void updateRoundedCornerDrawable() {
+ mRoundedCornerDrawable = getRoundedCornerDrawable(mContext, mDisplayUniqueId);
+ mRoundedCornerDrawableTop = getRoundedCornerTopDrawable(mContext, mDisplayUniqueId);
+ mRoundedCornerDrawableBottom = getRoundedCornerBottomDrawable(mContext, mDisplayUniqueId);
+ updateRoundedCornerImageView();
+ }
+
+ private void updateRoundedCornerImageView() {
+ final Drawable top = mRoundedCornerDrawableTop != null
+ ? mRoundedCornerDrawableTop : mRoundedCornerDrawable;
+ final Drawable bottom = mRoundedCornerDrawableBottom != null
+ ? mRoundedCornerDrawableBottom : mRoundedCornerDrawable;
+
+ if (mOverlays == null) {
+ return;
+ }
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ if (mOverlays[i] == null) {
+ continue;
+ }
+ ((ImageView) mOverlays[i].findViewById(R.id.left)).setImageDrawable(
+ isTopRoundedCorner(i, R.id.left) ? top : bottom);
+ ((ImageView) mOverlays[i].findViewById(R.id.right)).setImageDrawable(
+ isTopRoundedCorner(i, R.id.right) ? top : bottom);
+ }
+ }
+
+ @VisibleForTesting
+ boolean isTopRoundedCorner(@BoundsPosition int pos, int id) {
+ switch (pos) {
+ case BOUNDS_POSITION_LEFT:
+ case BOUNDS_POSITION_RIGHT:
+ if (mRotation == ROTATION_270) {
+ return id == R.id.left ? false : true;
+ } else {
+ return id == R.id.left ? true : false;
+ }
+ case BOUNDS_POSITION_TOP:
+ return true;
+ case BOUNDS_POSITION_BOTTOM:
+ return false;
+ default:
+ throw new IllegalArgumentException("Unknown bounds position");
+ }
+ }
+
private void updateRoundedCornerSize(
Point sizeDefault,
Point sizeTop,
@@ -855,21 +1001,10 @@
if (mOverlays[i] == null) {
continue;
}
- if (i == BOUNDS_POSITION_LEFT || i == BOUNDS_POSITION_RIGHT) {
- if (mRotation == ROTATION_270) {
- setSize(mOverlays[i].findViewById(R.id.left), sizeBottom);
- setSize(mOverlays[i].findViewById(R.id.right), sizeTop);
- } else {
- setSize(mOverlays[i].findViewById(R.id.left), sizeTop);
- setSize(mOverlays[i].findViewById(R.id.right), sizeBottom);
- }
- } else if (i == BOUNDS_POSITION_TOP) {
- setSize(mOverlays[i].findViewById(R.id.left), sizeTop);
- setSize(mOverlays[i].findViewById(R.id.right), sizeTop);
- } else if (i == BOUNDS_POSITION_BOTTOM) {
- setSize(mOverlays[i].findViewById(R.id.left), sizeBottom);
- setSize(mOverlays[i].findViewById(R.id.right), sizeBottom);
- }
+ setSize(mOverlays[i].findViewById(R.id.left),
+ isTopRoundedCorner(i, R.id.left) ? sizeTop : sizeBottom);
+ setSize(mOverlays[i].findViewById(R.id.right),
+ isTopRoundedCorner(i, R.id.right) ? sizeTop : sizeBottom);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
index a51e3fc..0893e89 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/WindowMagnificationController.java
@@ -499,9 +499,12 @@
}
private void setMagnificationFrameWith(Rect windowBounds, int centerX, int centerY) {
- // Sets the initial frame area for the mirror and places it in the center of the display.
- final int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2
- + 2 * mMirrorSurfaceMargin;
+ // Sets the initial frame area for the mirror and place it to the given center on the
+ // display.
+ int initSize = Math.min(windowBounds.width(), windowBounds.height()) / 2;
+ initSize = Math.min(mResources.getDimensionPixelSize(R.dimen.magnification_max_frame_size),
+ initSize);
+ initSize += 2 * mMirrorSurfaceMargin;
final int initX = centerX - initSize / 2;
final int initY = centerY - initSize / 2;
mMagnificationFrame.set(initX, initY, initX + initSize, initY + initSize);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 3f61d3c..fd37b35 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -126,6 +126,7 @@
boolean mCredentialAllowed;
boolean mSkipIntro;
long mOperationId;
+ long mRequestId;
@BiometricMultiSensorMode int mMultiSensorConfig;
}
@@ -172,6 +173,12 @@
return this;
}
+ /** Unique id for this request. */
+ public Builder setRequestId(long requestId) {
+ mConfig.mRequestId = requestId;
+ return this;
+ }
+
/** The multi-sensor mode. */
public Builder setMultiSensorConfig(@BiometricMultiSensorMode int multiSensorConfig) {
mConfig.mMultiSensorConfig = multiSensorConfig;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index ab5f2b828..0790af9 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -42,6 +42,7 @@
import android.hardware.face.FaceSensorPropertiesInternal;
import android.hardware.fingerprint.FingerprintManager;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintAuthenticatorsRegisteredCallback;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Bundle;
@@ -49,6 +50,7 @@
import android.os.Looper;
import android.os.RemoteException;
import android.util.Log;
+import android.util.SparseBooleanArray;
import android.view.MotionEvent;
import android.view.WindowManager;
@@ -76,6 +78,9 @@
/**
* Receives messages sent from {@link com.android.server.biometrics.BiometricService} and shows the
* appropriate biometric UI (e.g. BiometricDialogView).
+ *
+ * Also coordinates biometric-related things, such as UDFPS, with
+ * {@link com.android.keyguard.KeyguardUpdateMonitor}
*/
@SysUISingleton
public class AuthController extends SystemUI implements CommandQueue.Callbacks,
@@ -115,6 +120,8 @@
@Nullable private List<FingerprintSensorPropertiesInternal> mUdfpsProps;
@Nullable private List<FingerprintSensorPropertiesInternal> mSidefpsProps;
+ @NonNull private final SparseBooleanArray mUdfpsEnrolledForUser;
+
private class BiometricTaskStackListener extends TaskStackListener {
@Override
public void onTaskStackChanged() {
@@ -122,6 +129,21 @@
}
}
+ private final FingerprintStateListener mFingerprintStateListener =
+ new FingerprintStateListener() {
+ @Override
+ public void onEnrollmentsChanged(int userId, int sensorId, boolean hasEnrollments) {
+ Log.d(TAG, "onEnrollmentsChanged, userId: " + userId
+ + ", sensorId: " + sensorId
+ + ", hasEnrollments: " + hasEnrollments);
+ for (FingerprintSensorPropertiesInternal prop : mUdfpsProps) {
+ if (prop.sensorId == sensorId) {
+ mUdfpsEnrolledForUser.put(userId, hasEnrollments);
+ }
+ }
+ }
+ };
+
@NonNull
private final IFingerprintAuthenticatorsRegisteredCallback
mFingerprintAuthenticatorsRegisteredCallback =
@@ -436,6 +458,7 @@
mUdfpsControllerFactory = udfpsControllerFactory;
mSidefpsControllerFactory = sidefpsControllerFactory;
mWindowManager = windowManager;
+ mUdfpsEnrolledForUser = new SparseBooleanArray();
mOrientationListener = new BiometricOrientationEventListener(context,
() -> {
onOrientationChanged();
@@ -474,6 +497,7 @@
if (mFingerprintManager != null) {
mFingerprintManager.addAuthenticatorsRegisteredCallback(
mFingerprintAuthenticatorsRegisteredCallback);
+ mFingerprintManager.registerFingerprintStateListener(mFingerprintStateListener);
}
mTaskStackListener = new BiometricTaskStackListener();
@@ -501,7 +525,7 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId,
+ int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) {
@Authenticators.Types final int authenticators = promptInfo.getAuthenticators();
@@ -515,6 +539,7 @@
+ ", credentialAllowed: " + credentialAllowed
+ ", requireConfirmation: " + requireConfirmation
+ ", operationId: " + operationId
+ + ", requestId: " + requestId
+ ", multiSensorConfig: " + multiSensorConfig);
}
SomeArgs args = SomeArgs.obtain();
@@ -526,6 +551,7 @@
args.argi1 = userId;
args.arg6 = opPackageName;
args.arg7 = operationId;
+ args.arg8 = requestId;
args.argi2 = multiSensorConfig;
boolean skipAnimation = false;
@@ -629,6 +655,7 @@
if (mCurrentDialog == null) {
// Could be possible if the caller canceled authentication after credential success
// but before the client was notified.
+ if (DEBUG) Log.d(TAG, "dialog already gone");
return;
}
@@ -670,7 +697,7 @@
return false;
}
- return mFingerprintManager.hasEnrolledTemplatesForAnySensor(userId, mUdfpsProps);
+ return mUdfpsEnrolledForUser.get(userId);
}
private void showDialog(SomeArgs args, boolean skipAnimation, Bundle savedState) {
@@ -683,6 +710,7 @@
final int userId = args.argi1;
final String opPackageName = (String) args.arg6;
final long operationId = (long) args.arg7;
+ final long requestId = (long) args.arg8;
final @BiometricMultiSensorMode int multiSensorConfig = args.argi2;
// Create a new dialog but do not replace the current one yet.
@@ -695,6 +723,7 @@
opPackageName,
skipAnimation,
operationId,
+ requestId,
multiSensorConfig);
if (newDialog == null) {
@@ -772,7 +801,7 @@
protected AuthDialog buildDialog(PromptInfo promptInfo, boolean requireConfirmation,
int userId, int[] sensorIds, boolean credentialAllowed, String opPackageName,
- boolean skipIntro, long operationId,
+ boolean skipIntro, long operationId, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) {
return new AuthContainerView.Builder(mContext)
.setCallback(this)
@@ -782,6 +811,7 @@
.setOpPackageName(opPackageName)
.setSkipIntro(skipIntro)
.setOperationId(operationId)
+ .setRequestId(requestId)
.setMultiSensorConfig(multiSensorConfig)
.build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index c323bf7..ae426b6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -163,7 +163,8 @@
public static final AudioAttributes VIBRATION_SONIFICATION_ATTRIBUTES =
new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
- .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+ // vibration will bypass battery saver mode:
+ .setUsage(AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY)
.build();
public static final VibrationEffect EFFECT_CLICK =
@@ -768,6 +769,7 @@
UdfpsEnrollView enrollView = (UdfpsEnrollView) mInflater.inflate(
R.layout.udfps_enroll_view, null);
mView.addView(enrollView);
+ enrollView.updateSensorLocation(mSensorProps);
return new UdfpsEnrollViewController(
enrollView,
mServerRequest.mEnrollHelper,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
index ea69b1d..d407756 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollDrawable.java
@@ -43,7 +43,6 @@
// 1 + SCALE_MAX is the maximum that the moving target will animate to
private static final float SCALE_MAX = 0.25f;
- @NonNull private final UdfpsEnrollProgressBarDrawable mProgressDrawable;
@NonNull private final Drawable mMovingTargetFpIcon;
@NonNull private final Paint mSensorOutlinePaint;
@NonNull private final Paint mBlueFill;
@@ -62,7 +61,6 @@
UdfpsEnrollDrawable(@NonNull Context context) {
super(context);
- mProgressDrawable = new UdfpsEnrollProgressBarDrawable(context, this);
mSensorOutlinePaint = new Paint(0 /* flags */);
mSensorOutlinePaint.setAntiAlias(true);
@@ -100,8 +98,6 @@
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
-
if (mEnrollHelper.isCenterEnrollmentComplete()) {
if (mAnimatorSet != null && mAnimatorSet.isRunning()) {
mAnimatorSet.end();
@@ -139,14 +135,8 @@
}
}
- void onLastStepAcquired() {
- mProgressDrawable.onLastStepAcquired();
- }
-
@Override
public void draw(@NonNull Canvas canvas) {
- mProgressDrawable.draw(canvas);
-
if (isIlluminationShowing()) {
return;
}
@@ -175,11 +165,6 @@
}
@Override
- public void onBoundsChange(@NonNull Rect rect) {
- mProgressDrawable.setBounds(rect);
- }
-
- @Override
public void setAlpha(int alpha) {
super.setAlpha(alpha);
mSensorOutlinePaint.setAlpha(alpha);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
index 6a918a6..19148e3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollHelper.java
@@ -50,6 +50,7 @@
interface Listener {
void onEnrollmentProgress(int remaining, int totalSteps);
void onLastStepAcquired();
+ void onEnrollmentHelp();
}
@NonNull private final Context mContext;
@@ -138,7 +139,9 @@
}
void onEnrollmentHelp() {
-
+ if (mListener != null) {
+ mListener.onEnrollmentHelp();
+ }
}
void setListener(Listener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
index 4195009..373d17c8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollProgressBarDrawable.java
@@ -16,7 +16,9 @@
package com.android.systemui.biometrics;
+import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
+import android.annotation.ColorInt;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
@@ -41,19 +43,26 @@
private static final float PROGRESS_BAR_THICKNESS_DP = 12;
@NonNull private final Context mContext;
- @NonNull private final UdfpsEnrollDrawable mParent;
@NonNull private final Paint mBackgroundCirclePaint;
@NonNull private final Paint mProgressPaint;
@Nullable private ValueAnimator mProgressAnimator;
+ @Nullable private ValueAnimator mProgressShowingHelpAnimator;
+ @Nullable private ValueAnimator mProgressHidingHelpAnimator;
+ @ColorInt private final int mProgressColor;
+ @ColorInt private final int mProgressHelpColor;
+ private final int mShortAnimationDuration;
private float mProgress;
private int mRotation; // After last step, rotate the progress bar once
private boolean mLastStepAcquired;
- public UdfpsEnrollProgressBarDrawable(@NonNull Context context,
- @NonNull UdfpsEnrollDrawable parent) {
+ public UdfpsEnrollProgressBarDrawable(@NonNull Context context) {
mContext = context;
- mParent = parent;
+
+ mShortAnimationDuration = context.getResources()
+ .getInteger(com.android.internal.R.integer.config_shortAnimTime);
+ mProgressColor = context.getColor(R.color.udfps_enroll_progress);
+ mProgressHelpColor = context.getColor(R.color.udfps_enroll_progress_help);
mBackgroundCirclePaint = new Paint();
mBackgroundCirclePaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
@@ -74,7 +83,7 @@
// Progress should not be color extracted
mProgressPaint = new Paint();
mProgressPaint.setStrokeWidth(Utils.dpToPixels(context, PROGRESS_BAR_THICKNESS_DP));
- mProgressPaint.setColor(context.getColor(R.color.udfps_enroll_progress));
+ mProgressPaint.setColor(mProgressColor);
mProgressPaint.setAntiAlias(true);
mProgressPaint.setStyle(Paint.Style.STROKE);
mProgressPaint.setStrokeCap(Paint.Cap.ROUND);
@@ -92,7 +101,9 @@
return;
}
- long animationDuration = 150;
+ long animationDuration = mShortAnimationDuration;
+
+ hideEnrollmentHelp();
if (progress == 1.f) {
animationDuration = 400;
@@ -101,7 +112,7 @@
rotationAnimator.addUpdateListener(animation -> {
Log.d(TAG, "Rotation: " + mRotation);
mRotation = (int) animation.getAnimatedValue();
- mParent.invalidateSelf();
+ invalidateSelf();
});
rotationAnimator.start();
}
@@ -114,11 +125,7 @@
mProgressAnimator.setDuration(animationDuration);
mProgressAnimator.addUpdateListener(animation -> {
mProgress = (float) animation.getAnimatedValue();
- // Use the parent to invalidate, since it's the one that's attached as the view's
- // drawable and has its callback set automatically. Invalidating via
- // `this.invalidateSelf` actually does not invoke draw(), since this drawable's callback
- // is not really set.
- mParent.invalidateSelf();
+ invalidateSelf();
});
mProgressAnimator.start();
}
@@ -128,6 +135,46 @@
mLastStepAcquired = true;
}
+ void onEnrollmentHelp() {
+ if (mProgressShowingHelpAnimator != null || mProgressAnimator == null) {
+ return; // already showing or at 0% (no progress bar visible)
+ }
+
+ if (mProgressHidingHelpAnimator != null && mProgressHidingHelpAnimator.isRunning()) {
+ mProgressHidingHelpAnimator.cancel();
+ }
+ mProgressHidingHelpAnimator = null;
+
+ mProgressShowingHelpAnimator = getProgressColorAnimator(
+ mProgressPaint.getColor(), mProgressHelpColor);
+ mProgressShowingHelpAnimator.start();
+ }
+
+ private void hideEnrollmentHelp() {
+ if (mProgressHidingHelpAnimator != null || mProgressShowingHelpAnimator == null) {
+ return; // already hidden or help never shown
+ }
+
+ if (mProgressShowingHelpAnimator != null && mProgressShowingHelpAnimator.isRunning()) {
+ mProgressShowingHelpAnimator.cancel();
+ }
+ mProgressShowingHelpAnimator = null;
+
+ mProgressHidingHelpAnimator = getProgressColorAnimator(
+ mProgressPaint.getColor(), mProgressColor);
+ mProgressHidingHelpAnimator.start();
+ }
+
+ private ValueAnimator getProgressColorAnimator(@ColorInt int from, @ColorInt int to) {
+ final ValueAnimator animator = ValueAnimator.ofObject(
+ ArgbEvaluator.getInstance(), from, to);
+ animator.setDuration(mShortAnimationDuration);
+ animator.addUpdateListener(animation -> {
+ mProgressPaint.setColor((int) animation.getAnimatedValue());
+ });
+ return animator;
+ }
+
@Override
public void draw(@NonNull Canvas canvas) {
canvas.save();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
index 2cdf49d..d9edef4 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollView.java
@@ -17,9 +17,12 @@
package com.android.systemui.biometrics;
import android.content.Context;
+import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.NonNull;
@@ -32,20 +35,25 @@
*/
public class UdfpsEnrollView extends UdfpsAnimationView {
@NonNull private final UdfpsEnrollDrawable mFingerprintDrawable;
+ @NonNull private final UdfpsEnrollProgressBarDrawable mFingerprintProgressDrawable;
@NonNull private final Handler mHandler;
@NonNull private ImageView mFingerprintView;
+ @NonNull private ImageView mFingerprintProgressView;
public UdfpsEnrollView(Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
mFingerprintDrawable = new UdfpsEnrollDrawable(mContext);
+ mFingerprintProgressDrawable = new UdfpsEnrollProgressBarDrawable(context);
mHandler = new Handler(Looper.getMainLooper());
}
@Override
protected void onFinishInflate() {
mFingerprintView = findViewById(R.id.udfps_enroll_animation_fp_view);
+ mFingerprintProgressView = findViewById(R.id.udfps_enroll_animation_fp_progress_view);
mFingerprintView.setImageDrawable(mFingerprintDrawable);
+ mFingerprintProgressView.setImageDrawable(mFingerprintProgressDrawable);
}
@Override
@@ -53,15 +61,35 @@
return mFingerprintDrawable;
}
+ void updateSensorLocation(@NonNull FingerprintSensorPropertiesInternal sensorProps) {
+ View fingerprintAccessibilityView = findViewById(R.id.udfps_enroll_accessibility_view);
+ final int sensorHeight = sensorProps.sensorRadius * 2;
+ final int sensorWidth = sensorHeight;
+ ViewGroup.LayoutParams params = fingerprintAccessibilityView.getLayoutParams();
+ params.width = sensorWidth;
+ params.height = sensorHeight;
+ fingerprintAccessibilityView.setLayoutParams(params);
+ fingerprintAccessibilityView.requestLayout();
+ }
+
void setEnrollHelper(UdfpsEnrollHelper enrollHelper) {
mFingerprintDrawable.setEnrollHelper(enrollHelper);
}
void onEnrollmentProgress(int remaining, int totalSteps) {
- mHandler.post(() -> mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps));
+ mHandler.post(() -> {
+ mFingerprintProgressDrawable.setEnrollmentProgress(remaining, totalSteps);
+ mFingerprintDrawable.onEnrollmentProgress(remaining, totalSteps);
+ });
}
void onLastStepAcquired() {
- mHandler.post(mFingerprintDrawable::onLastStepAcquired);
+ mHandler.post(() -> {
+ mFingerprintProgressDrawable.onLastStepAcquired();
+ });
+ }
+
+ void onEnrollmentHelp() {
+ mHandler.post(mFingerprintProgressDrawable::onEnrollmentHelp);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
index 54244a1..33fbe7b 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsEnrollViewController.java
@@ -44,6 +44,11 @@
public void onLastStepAcquired() {
mView.onLastStepAcquired();
}
+
+ @Override
+ public void onEnrollmentHelp() {
+ mView.onEnrollmentHelp();
+ }
};
protected UdfpsEnrollViewController(
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
index d46426a..9015396 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardView.java
@@ -155,6 +155,13 @@
updateAlpha();
}
+ /**
+ * @return alpha between 0 and 255
+ */
+ int getUnpausedAlpha() {
+ return mAlpha;
+ }
+
@Override
protected int updateAlpha() {
int alpha = super.updateAlpha();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
index 4d9675c..44ab69f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardViewController.java
@@ -168,7 +168,7 @@
pw.println("mIsBouncerVisible=" + mIsBouncerVisible);
pw.println("mInputBouncerHiddenAmount=" + mInputBouncerHiddenAmount);
pw.println("mStatusBarExpansion=" + mStatusBarExpansion);
- pw.println("mAlpha=" + mView.getAlpha());
+ pw.println("unpausedAlpha=" + mView.getUnpausedAlpha());
pw.println("mUdfpsRequested=" + mUdfpsRequested);
pw.println("mView.mUdfpsRequested=" + mView.mUdfpsRequested);
pw.println("mLaunchTransitionFadingAway=" + mLaunchTransitionFadingAway);
@@ -183,13 +183,13 @@
return false;
}
+ boolean udfpsAffordanceWasNotShowing = shouldPauseAuth();
mShowingUdfpsBouncer = show;
if (mShowingUdfpsBouncer) {
mLastUdfpsBouncerShowTime = mSystemClock.uptimeMillis();
}
- updatePauseAuth();
if (mShowingUdfpsBouncer) {
- if (mStatusBarState == StatusBarState.SHADE_LOCKED) {
+ if (udfpsAffordanceWasNotShowing) {
mView.animateInUdfpsBouncer(null);
}
@@ -202,6 +202,8 @@
} else {
mKeyguardUpdateMonitor.requestFaceAuthOnOccludingApp(false);
}
+ updateAlpha();
+ updatePauseAuth();
return true;
}
@@ -335,6 +337,7 @@
public void requestUdfps(boolean request, int color) {
mUdfpsRequested = request;
mView.requestUdfps(request, color);
+ updateAlpha();
updatePauseAuth();
}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
index e1349f2..40c28fa 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ZigZagClassifier.java
@@ -21,6 +21,7 @@
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_PRIMARY_DEVIANCE;
import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.BRIGHTLINE_FALSING_ZIGZAG_Y_SECONDARY_DEVIANCE;
import static com.android.systemui.classifier.Classifier.BRIGHTNESS_SLIDER;
+import static com.android.systemui.classifier.Classifier.LOCK_ICON;
import static com.android.systemui.classifier.Classifier.SHADE_DRAG;
import android.graphics.Point;
@@ -89,7 +90,9 @@
Result calculateFalsingResult(
@Classifier.InteractionType int interactionType,
double historyBelief, double historyConfidence) {
- if (interactionType == BRIGHTNESS_SLIDER || interactionType == SHADE_DRAG) {
+ if (interactionType == BRIGHTNESS_SLIDER
+ || interactionType == SHADE_DRAG
+ || interactionType == LOCK_ICON) {
return Result.passed(0);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
index c093219..e7974bc 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/DependencyProvider.java
@@ -196,9 +196,11 @@
@SysUISingleton
@Provides
static ThemeOverlayApplier provideThemeOverlayManager(Context context,
- @Background Executor bgExecutor, OverlayManager overlayManager,
+ @Background Executor bgExecutor,
+ @Main Executor mainExecutor,
+ OverlayManager overlayManager,
DumpManager dumpManager) {
- return new ThemeOverlayApplier(overlayManager, bgExecutor,
+ return new ThemeOverlayApplier(overlayManager, bgExecutor, mainExecutor,
context.getString(R.string.launcher_overlayable_package),
context.getString(R.string.themepicker_overlayable_package), dumpManager);
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 3577395..a5dd6a1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -67,6 +67,7 @@
import android.view.WindowManagerPolicyConstants;
import android.window.IRemoteTransition;
import android.window.IRemoteTransitionFinishedCallback;
+import android.window.RemoteTransition;
import android.window.TransitionFilter;
import android.window.TransitionInfo;
@@ -236,7 +237,8 @@
Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_GOING_AWAY");
TransitionFilter f = new TransitionFilter();
f.mFlags = TRANSIT_FLAG_KEYGUARD_GOING_AWAY;
- shellTransitions.registerRemote(f, wrap(mExitAnimationRunner));
+ shellTransitions.registerRemote(f,
+ new RemoteTransition(wrap(mExitAnimationRunner)));
}
if (sEnableRemoteKeyguardOccludeAnimation) {
Slog.d(TAG, "KeyguardService registerRemote: TRANSIT_KEYGUARD_(UN)OCCLUDE");
@@ -255,7 +257,7 @@
f.mRequirements[1].mMustBeIndependent = false;
f.mRequirements[1].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[1].mModes = new int[]{TRANSIT_CLOSE, TRANSIT_TO_BACK};
- shellTransitions.registerRemote(f, mOccludeAnimation);
+ shellTransitions.registerRemote(f, new RemoteTransition(mOccludeAnimation));
// Now register for un-occlude.
f = new TransitionFilter();
@@ -275,7 +277,7 @@
f.mRequirements[0].mMustBeIndependent = false;
f.mRequirements[0].mFlags = FLAG_OCCLUDES_KEYGUARD;
f.mRequirements[0].mModes = new int[]{TRANSIT_OPEN, TRANSIT_TO_FRONT};
- shellTransitions.registerRemote(f, mUnoccludeAnimation);
+ shellTransitions.registerRemote(f, new RemoteTransition(mUnoccludeAnimation));
}
} else {
RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
index 2facf3d..db5dbb0 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaCarouselController.kt
@@ -212,14 +212,32 @@
isSsReactivated: Boolean
) {
if (addOrUpdatePlayer(key, oldKey, data)) {
+ // Log card received if a new resumable media card is added
MediaPlayerData.getMediaPlayer(key)?.let {
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
+ it.mUid,
/* isRecommendationCard */ false,
it.surfaceForSmartspaceLogging,
rank = MediaPlayerData.getMediaPlayerIndex(key))
}
}
+ if (isSsReactivated) {
+ // If resumable media is reactivated by headphone connection, update instance
+ // id for each card and log a receive event.
+ MediaPlayerData.players().forEachIndexed { index, it ->
+ if (it.recommendationViewHolder == null) {
+ it.mInstanceId = SmallHash.hash(it.mUid +
+ systemClock.currentTimeMillis().toInt())
+ logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
+ it.mInstanceId,
+ it.mUid,
+ /* isRecommendationCard */ false,
+ it.surfaceForSmartspaceLogging,
+ rank = index)
+ }
+ }
+ }
if (mediaCarouselScrollHandler.visibleToUser &&
isSsReactivated && !mediaCarouselScrollHandler.qsExpanded) {
// It could happen that reactived media player isn't visible to user because
@@ -252,6 +270,7 @@
MediaPlayerData.getMediaPlayer(key)?.let {
logSmartspaceCardReported(759, // SMARTSPACE_CARD_RECEIVED
it.mInstanceId,
+ it.mUid,
/* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging,
rank = MediaPlayerData.getMediaPlayerIndex(key))
@@ -261,6 +280,7 @@
MediaPlayerData.getMediaPlayerIndex(key)) {
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
it.mInstanceId,
+ it.mUid,
/* isRecommendationCard */ true,
it.surfaceForSmartspaceLogging)
}
@@ -339,9 +359,9 @@
if (activeMediaIndex != -1) {
previousVisiblePlayerKey?.let {
val previousVisibleIndex = MediaPlayerData.playerKeys()
- .indexOfFirst { key -> it == key }
+ .indexOfFirst { key -> it == key }
mediaCarouselScrollHandler
- .scrollToPlayer(previousVisibleIndex, activeMediaIndex)
+ .scrollToPlayer(previousVisibleIndex, activeMediaIndex)
} ?: {
mediaCarouselScrollHandler.scrollToPlayer(destIndex = activeMediaIndex)
}
@@ -355,11 +375,11 @@
MediaPlayerData.moveIfExists(oldKey, key)
val existingPlayer = MediaPlayerData.getMediaPlayer(key)
val curVisibleMediaKey = MediaPlayerData.playerKeys()
- .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
if (existingPlayer == null) {
var newPlayer = mediaControlPanelFactory.get()
newPlayer.attachPlayer(
- PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
+ PlayerViewHolder.create(LayoutInflater.from(context), mediaContent))
newPlayer.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
@@ -407,14 +427,14 @@
var newRecs = mediaControlPanelFactory.get()
newRecs.attachRecommendation(
- RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent))
+ RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent))
newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
val lp = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT)
+ ViewGroup.LayoutParams.WRAP_CONTENT)
newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
newRecs.bindRecommendation(data.copy(backgroundColor = bgColor))
val curVisibleMediaKey = MediaPlayerData.playerKeys()
- .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
+ .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
MediaPlayerData.addMediaRecommendation(key, data, newRecs, shouldPrioritize, systemClock)
updatePlayerToState(newRecs, noAnimation = true)
reorderAllPlayers(curVisibleMediaKey)
@@ -462,7 +482,7 @@
removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
smartspaceMediaData?.let {
addSmartspaceMediaRecommendations(
- it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
+ it.targetId, it, MediaPlayerData.shouldPrioritizeSs)
}
} else {
removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
@@ -585,7 +605,7 @@
?: endShowsActive
if (currentlyShowingOnlyActive != endShowsActive ||
((currentTransitionProgress != 1.0f && currentTransitionProgress != 0.0f) &&
- startShowsActive != endShowsActive)) {
+ startShowsActive != endShowsActive)) {
// Whenever we're transitioning from between differing states or the endstate differs
// we reset the translation
currentlyShowingOnlyActive = endShowsActive
@@ -696,23 +716,43 @@
}
logSmartspaceCardReported(800, // SMARTSPACE_CARD_SEEN
mediaControlPanel.mInstanceId,
+ mediaControlPanel.mUid,
isRecommendationCard,
mediaControlPanel.surfaceForSmartspaceLogging)
}
}
@JvmOverloads
+ /**
+ * Log Smartspace events
+ *
+ * @param eventId UI event id (e.g. 800 for SMARTSPACE_CARD_SEEN)
+ * @param instanceId id to uniquely identify a card, e.g. each headphone generates a new
+ * instanceId
+ * @param uid uid for the application that media comes from
+ * @param isRecommendationCard whether the card is media recommendation
+ * @param surface which display surface the media card is on (e.g. lockscreen, shade)
+ * @param interactedSubcardRank the rank for interacted media item for recommendation card, -1
+ * for tapping on card but not on any media item, 0 for first media item, 1 for second, etc.
+ * @param interactedSubcardCardinality how many media items were shown to the user when there
+ * is user interaction
+ * @param rank the rank for media card in the media carousel, starting from 0
+ *
+ */
fun logSmartspaceCardReported(
eventId: Int,
instanceId: Int,
+ uid: Int,
isRecommendationCard: Boolean,
surface: Int,
+ interactedSubcardRank: Int = 0,
+ interactedSubcardCardinality: Int = 0,
rank: Int = mediaCarouselScrollHandler.visibleMediaIndex
) {
// Only log media resume card when Smartspace data is available
if (!isRecommendationCard &&
- !mediaManager.smartspaceMediaData.isActive &&
- MediaPlayerData.smartspaceMediaData == null) {
+ !mediaManager.smartspaceMediaData.isActive &&
+ MediaPlayerData.smartspaceMediaData == null) {
return
}
@@ -720,13 +760,20 @@
SysUiStatsLog.write(SysUiStatsLog.SMARTSPACE_CARD_REPORTED,
eventId,
instanceId,
- if (isRecommendationCard)
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_MEDIA_RECOMMENDATIONS
- else
- SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__HEADPHONE_RESUME_MEDIA,
+ // Deprecated, replaced with AiAi feature type so we don't need to create logging
+ // card type for each new feature.
+ SysUiStatsLog.SMART_SPACE_CARD_REPORTED__CARD_TYPE__UNKNOWN_CARD,
surface,
rank,
- mediaContent.getChildCount())
+ mediaContent.getChildCount(),
+ if (isRecommendationCard)
+ 15 // MEDIA_RECOMMENDATION
+ else
+ 31, // MEDIA_RESUME
+ uid,
+ interactedSubcardRank,
+ interactedSubcardCardinality
+ )
/* ktlint-disable max-line-length */
}
@@ -738,18 +785,20 @@
if (!recommendation.isEmpty()) {
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
recommendation.get(0).mInstanceId,
+ recommendation.get(0).mUid,
true,
recommendation.get(0).surfaceForSmartspaceLogging,
- /* rank */-1)
+ rank = -1)
} else {
val visibleMediaIndex = mediaCarouselScrollHandler.visibleMediaIndex
if (MediaPlayerData.players().size > visibleMediaIndex) {
val player = MediaPlayerData.players().elementAt(visibleMediaIndex)
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
player.mInstanceId,
- false,
+ player.mUid,
+ false,
player.surfaceForSmartspaceLogging,
- /* rank */-1)
+ rank = -1)
}
}
mediaManager.onSwipeToDismiss()
@@ -768,7 +817,7 @@
@VisibleForTesting
internal object MediaPlayerData {
private val EMPTY = MediaData(-1, false, 0, null, null, null, null, null,
- emptyList(), emptyList(), "INVALID", null, null, null, true, null)
+ emptyList(), emptyList(), "INVALID", null, null, null, true, null)
// Whether should prioritize Smartspace card.
internal var shouldPrioritizeSs: Boolean = false
private set
@@ -776,18 +825,18 @@
private set
data class MediaSortKey(
- // Whether the item represents a Smartspace media recommendation.
+ // Whether the item represents a Smartspace media recommendation.
val isSsMediaRec: Boolean,
val data: MediaData,
val updateTime: Long = 0
)
private val comparator =
- compareByDescending<MediaSortKey> { it.data.isPlaying }
- .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
- .thenByDescending { it.data.isLocalSession }
- .thenByDescending { !it.data.resumption }
- .thenByDescending { it.updateTime }
+ compareByDescending<MediaSortKey> { it.data.isPlaying }
+ .thenByDescending { if (shouldPrioritizeSs) it.isSsMediaRec else !it.isSsMediaRec }
+ .thenByDescending { it.data.isLocalSession }
+ .thenByDescending { !it.data.resumption }
+ .thenByDescending { it.updateTime }
private val mediaPlayers = TreeMap<MediaSortKey, MediaControlPanel>(comparator)
private val mediaData: MutableMap<String, MediaSortKey> = mutableMapOf()
@@ -888,4 +937,4 @@
}
return false
}
-}
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
index 15a7083..c125612 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaControlPanel.java
@@ -33,6 +33,7 @@
import android.media.session.MediaController;
import android.media.session.MediaSession;
import android.media.session.PlaybackState;
+import android.os.Process;
import android.text.Layout;
import android.util.Log;
import android.view.View;
@@ -111,6 +112,9 @@
private int mAlbumArtSize;
// Instance id for logging purpose.
protected int mInstanceId = -1;
+ // Uid for the media app.
+ protected int mUid = Process.INVALID_UID;
+ private int mSmartspaceMediaItemsCount;
private MediaCarouselController mMediaCarouselController;
private final MediaOutputDialogFactory mMediaOutputDialogFactory;
@@ -266,7 +270,13 @@
}
mKey = key;
MediaSession.Token token = data.getToken();
- mInstanceId = SmallHash.hash(data.getPackageName());
+ PackageManager packageManager = mContext.getPackageManager();
+ try {
+ mUid = packageManager.getApplicationInfo(data.getPackageName(), 0 /* flags */).uid;
+ } catch (PackageManager.NameNotFoundException e) {
+ Log.e(TAG, "Unable to look up package name", e);
+ }
+ mInstanceId = SmallHash.hash(mUid);
mBackgroundColor = data.getBackgroundColor();
if (mToken == null || !mToken.equals(token)) {
@@ -360,27 +370,16 @@
final MediaDeviceData device = data.getDevice();
final int seamlessId = mPlayerViewHolder.getSeamless().getId();
- final int seamlessFallbackId = mPlayerViewHolder.getSeamlessFallback().getId();
- final boolean showFallback = device != null && !device.getEnabled();
- final int seamlessFallbackVisibility = showFallback ? View.VISIBLE : View.GONE;
- mPlayerViewHolder.getSeamlessFallback().setVisibility(seamlessFallbackVisibility);
- expandedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
- collapsedSet.setVisibility(seamlessFallbackId, seamlessFallbackVisibility);
- final int seamlessVisibility = showFallback ? View.GONE : View.VISIBLE;
- mPlayerViewHolder.getSeamless().setVisibility(seamlessVisibility);
- expandedSet.setVisibility(seamlessId, seamlessVisibility);
- collapsedSet.setVisibility(seamlessId, seamlessVisibility);
- final float seamlessAlpha = data.getResumption() ? DISABLED_ALPHA : 1.0f;
+ // Disable clicking on output switcher for invalid devices and resumption controls
+ final boolean seamlessDisabled = (device != null && !device.getEnabled())
+ || data.getResumption();
+ final float seamlessAlpha = seamlessDisabled ? DISABLED_ALPHA : 1.0f;
expandedSet.setAlpha(seamlessId, seamlessAlpha);
collapsedSet.setAlpha(seamlessId, seamlessAlpha);
- // Disable clicking on output switcher for resumption controls.
- mPlayerViewHolder.getSeamless().setEnabled(!data.getResumption());
+ mPlayerViewHolder.getSeamless().setEnabled(!seamlessDisabled);
String deviceString = null;
- if (showFallback) {
- iconView.setImageDrawable(null);
- } else if (device != null) {
+ if (device != null && device.getEnabled()) {
Drawable icon = device.getIcon();
- iconView.setVisibility(View.VISIBLE);
if (icon instanceof AdaptiveIcon) {
AdaptiveIcon aIcon = (AdaptiveIcon) icon;
aIcon.setBackgroundColor(mBackgroundColor);
@@ -391,10 +390,9 @@
deviceString = device.getName();
} else {
// Reset to default
- Log.w(TAG, "device is null. Not binding output chip.");
- iconView.setVisibility(View.GONE);
- deviceString = mContext.getString(
- com.android.internal.R.string.ext_media_seamless_action);
+ Log.w(TAG, "Device is null or not enabled: " + device + ", not binding output chip.");
+ iconView.setImageResource(R.drawable.ic_media_home_devices);
+ deviceString = mContext.getString(R.string.media_seamless_other_device);
}
deviceName.setText(deviceString);
seamlessView.setContentDescription(deviceString);
@@ -531,10 +529,11 @@
}
// Set up recommendation card's header.
- ApplicationInfo applicationInfo = null;
+ ApplicationInfo applicationInfo;
try {
applicationInfo = mContext.getPackageManager()
.getApplicationInfo(data.getPackageName(), 0 /* flags */);
+ mUid = applicationInfo.uid;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Fail to get media recommendation's app info", e);
return;
@@ -553,7 +552,8 @@
headerTitleText.setText(appLabel);
}
// Set up media rec card's tap action if applicable.
- setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction());
+ setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
+ /* interactedSubcardRank */ -1);
// Set up media rec card's accessibility label.
recommendationCard.setContentDescription(
mContext.getString(R.string.controls_media_smartspace_rec_description, appLabel));
@@ -567,7 +567,8 @@
ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
int mediaRecommendationNum = Math.min(mediaRecommendationList.size(),
MEDIA_RECOMMENDATION_MAX_NUM);
- for (int itemIndex = 0, uiComponentIndex = 0;
+ int uiComponentIndex = 0;
+ for (int itemIndex = 0;
itemIndex < mediaRecommendationNum && uiComponentIndex < mediaRecommendationNum;
itemIndex++) {
SmartspaceAction recommendation = mediaRecommendationList.get(itemIndex);
@@ -582,7 +583,8 @@
// Set up the media item's click listener if applicable.
ViewGroup mediaCoverContainer = mediaCoverContainers.get(uiComponentIndex);
- setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation);
+ setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation,
+ uiComponentIndex);
// Set up the accessibility label for the media item.
String artistName = recommendation.getExtras()
@@ -614,10 +616,10 @@
mediaCoverItemsResIds.get(uiComponentIndex), true);
setVisibleAndAlpha(expandedSet,
mediaCoverContainersResIds.get(uiComponentIndex), true);
-
uiComponentIndex++;
}
+ mSmartspaceMediaItemsCount = uiComponentIndex;
// Set up long press to show guts setting panel.
mRecommendationViewHolder.getDismiss().setOnClickListener(v -> {
logSmartspaceCardReported(761, // SMARTSPACE_CARD_DISMISS
@@ -750,7 +752,8 @@
private void setSmartspaceRecItemOnClickListener(
@NonNull View view,
- @NonNull SmartspaceAction action) {
+ @NonNull SmartspaceAction action,
+ int interactedSubcardRank) {
if (view == null || action == null || action.getIntent() == null
|| action.getIntent().getExtras() == null) {
Log.e(TAG, "No tap action can be set up");
@@ -758,9 +761,10 @@
}
view.setOnClickListener(v -> {
- // When media recommendation card is shown, it will always be the top card.
logSmartspaceCardReported(760, // SMARTSPACE_CARD_CLICK
- /* isRecommendationCard */ true);
+ /* isRecommendationCard */ true,
+ interactedSubcardRank,
+ getSmartspaceSubCardCardinality());
if (shouldSmartspaceRecItemOpenInForeground(action)) {
// Request to unlock the device if the activity needs to be opened in foreground.
@@ -818,9 +822,28 @@
}
private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard) {
+ logSmartspaceCardReported(eventId, isRecommendationCard,
+ /* interactedSubcardRank */ 0,
+ /* interactedSubcardCardinality */ 0);
+ }
+
+ private void logSmartspaceCardReported(int eventId, boolean isRecommendationCard,
+ int interactedSubcardRank, int interactedSubcardCardinality) {
mMediaCarouselController.logSmartspaceCardReported(eventId,
mInstanceId,
+ mUid,
isRecommendationCard,
- getSurfaceForSmartspaceLogging());
+ getSurfaceForSmartspaceLogging(),
+ interactedSubcardRank,
+ interactedSubcardCardinality);
}
-}
+
+ private int getSmartspaceSubCardCardinality() {
+ if (!mMediaCarouselController.getMediaCarouselScrollHandler().getQsExpanded()
+ && mSmartspaceMediaItemsCount > 3) {
+ return 3;
+ }
+
+ return mSmartspaceMediaItemsCount;
+ }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
index 791f59d..35603b6 100644
--- a/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/PlayerViewHolder.kt
@@ -43,7 +43,6 @@
val seamless = itemView.requireViewById<ViewGroup>(R.id.media_seamless)
val seamlessIcon = itemView.requireViewById<ImageView>(R.id.media_seamless_image)
val seamlessText = itemView.requireViewById<TextView>(R.id.media_seamless_text)
- val seamlessFallback = itemView.requireViewById<ImageView>(R.id.media_seamless_fallback)
// Seek bar
val seekBar = itemView.requireViewById<SeekBar>(R.id.media_progress_bar)
@@ -124,7 +123,6 @@
R.id.header_title,
R.id.header_artist,
R.id.media_seamless,
- R.id.media_seamless_fallback,
R.id.notification_media_progress_time,
R.id.media_progress_bar,
R.id.action0,
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 4a67e94..7de0a12 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -422,6 +422,12 @@
new Handler(Looper.getMainLooper())) {
@Override
public void onChange(boolean selfChange, Uri uri) {
+ // TODO(b/198002034): Content observers currently can still be called back after being
+ // unregistered, and in this case we can ignore the change if the nav bar has been
+ // destroyed already
+ if (mNavigationBarView == null) {
+ return;
+ }
updateAssistantEntrypoints();
}
};
@@ -648,7 +654,7 @@
if (mIsOnDefaultDisplay) {
final RotationButtonController rotationButtonController =
mNavigationBarView.getRotationButtonController();
- rotationButtonController.addRotationCallback(mRotationWatcher);
+ rotationButtonController.setRotationCallback(mRotationWatcher);
// Reset user rotation pref to match that of the WindowManager if starting in locked
// mode. This will automatically happen when switching from auto-rotate to locked mode.
@@ -687,6 +693,9 @@
@Override
public void onViewDetachedFromWindow(View v) {
+ final RotationButtonController rotationButtonController =
+ mNavigationBarView.getRotationButtonController();
+ rotationButtonController.setRotationCallback(null);
mNavigationBarView.getBarTransitions().destroy();
mNavigationBarView.getLightTransitionsController().destroy(mContext);
mOverviewProxyService.removeCallback(mOverviewProxyListener);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarView.java
index 93388f9..2de4026 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;
@@ -281,7 +279,7 @@
new RotationButtonUpdatesCallback() {
@Override
public void onVisibilityChanged(boolean visible) {
- if (visible) {
+ if (visible && mAutoHideController != null) {
// If the button will actually become visible and the navbar is about
// to hide, tell the statusbar to keep it around for longer
mAutoHideController.touchAutoHide();
@@ -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/RotationButtonController.java b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
index 196625b..0f5c03a 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/RotationButtonController.java
@@ -183,7 +183,7 @@
TaskStackChangeListeners.getInstance().unregisterTaskStackListener(mTaskStackListener);
}
- void addRotationCallback(Consumer<Integer> watcher) {
+ void setRotationCallback(Consumer<Integer> watcher) {
mRotWatcherListener = watcher;
}
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/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index 2bf4bf4..bf1a98f 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -106,7 +106,7 @@
static final String DEBUG_MISSING_GESTURE_TAG = "NoBackGesture";
private static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
- SystemProperties.getBoolean("persist.debug.per_window_input_rotation", true);
+ SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
private ISystemGestureExclusionListener mGestureExclusionListener =
new ISystemGestureExclusionListener.Stub() {
@@ -384,7 +384,7 @@
private void onNavigationSettingsChanged() {
boolean wasBackAllowed = isHandlingGestures();
updateCurrentUserResources();
- if (wasBackAllowed != isHandlingGestures()) {
+ if (mStateChangeCallback != null && wasBackAllowed != isHandlingGestures()) {
mStateChangeCallback.run();
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
index a85800b..359f3a4 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QuickStatusBarHeader.java
@@ -140,6 +140,10 @@
mBatteryRemainingIcon = findViewById(R.id.batteryRemainingIcon);
updateResources();
+ Configuration config = mContext.getResources().getConfiguration();
+ setDatePrivacyContainersWidth(config.orientation == Configuration.ORIENTATION_LANDSCAPE);
+ setSecurityHeaderContainerVisibility(
+ config.orientation == Configuration.ORIENTATION_LANDSCAPE);
// QS will always show the estimate, and BatteryMeterView handles the case where
// it's unavailable or charging
@@ -189,6 +193,8 @@
super.onConfigurationChanged(newConfig);
updateResources();
setDatePrivacyContainersWidth(newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
+ setSecurityHeaderContainerVisibility(
+ newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE);
}
@Override
@@ -209,6 +215,10 @@
mPrivacyContainer.setLayoutParams(lp);
}
+ private void setSecurityHeaderContainerVisibility(boolean landscape) {
+ mSecurityHeaderView.setVisibility(landscape ? VISIBLE : GONE);
+ }
+
private void updateBatteryMode() {
if (mConfigShowBatteryEstimate && !mHasCenterCutout) {
mBatteryRemainingIcon.setPercentShowMode(BatteryMeterView.MODE_ESTIMATE);
@@ -316,6 +326,7 @@
public void onAnimationAtStart() {
super.onAnimationAtStart();
mClockDateView.setFreezeSwitching(false);
+ mClockDateView.setVisibility(View.VISIBLE);
setSeparatorVisibility(mShowClockIconsSeparator);
// In QQS we never ignore RSSI.
mIconContainer.removeIgnoredSlots(mRssiIgnoredSlots);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
index 2e771d6..b1cd03c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tileimpl/QSIconViewImpl.java
@@ -116,6 +116,9 @@
: icon.getInvisibleDrawable(mContext) : null;
int padding = icon != null ? icon.getPadding() : 0;
if (d != null) {
+ if (d.getConstantState() != null) {
+ d = d.getConstantState().newDrawable();
+ }
d.setAutoMirrored(false);
d.setLayoutDirection(getLayoutDirection());
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
index d0a4b62..cc9e748 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/InternetTile.java
@@ -122,8 +122,9 @@
@Override
protected void handleClick(@Nullable View view) {
- boolean canConfigMobileData = mAccessPointController.canConfigMobileData();
- mHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+ mHandler.post(() -> mInternetDialogFactory.create(true,
+ mAccessPointController.canConfigMobileData(),
+ mAccessPointController.canConfigWifi()));
}
@Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
index 91c81bc..99eb5b6 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetAdapter.java
@@ -16,16 +16,11 @@
package com.android.systemui.qs.tiles.dialog;
-import static com.android.wifitrackerlib.WifiEntry.SECURITY_NONE;
-import static com.android.wifitrackerlib.WifiEntry.SECURITY_OWE;
-
import android.content.Context;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.text.Html;
import android.text.TextUtils;
-import android.util.Log;
-import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -34,8 +29,10 @@
import android.widget.TextView;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.recyclerview.widget.RecyclerView;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.settingslib.Utils;
import com.android.settingslib.wifi.WifiUtils;
import com.android.systemui.R;
@@ -43,7 +40,6 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicReference;
-import java.util.stream.Collectors;
/**
* Adapter for showing Wi-Fi networks.
@@ -54,9 +50,10 @@
private static final String ACTION_WIFI_DIALOG = "com.android.settings.WIFI_DIALOG";
private static final String EXTRA_CHOSEN_WIFI_ENTRY_KEY = "key_chosen_wifientry_key";
private static final String EXTRA_CONNECT_FOR_CALLER = "connect_for_caller";
- private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final InternetDialogController mInternetDialogController;
+ private List<WifiEntry> mWifiEntries;
+ private int mWifiEntriesCount;
protected View mHolderView;
protected Context mContext;
@@ -76,54 +73,31 @@
@Override
public void onBindViewHolder(@NonNull InternetViewHolder viewHolder, int position) {
- List<WifiEntry> wifiList = getWifiEntryList();
- if (wifiList != null && wifiList.size() != 0) {
- int count = getItemCount();
- if (wifiList.size() > count) {
- wifiList = getWifiEntryList().subList(0, count - 1);
- }
-
- if (position < wifiList.size()) {
- viewHolder.onBind(wifiList.get(position));
- }
- } else if (DEBUG) {
- Log.d(TAG, "onBindViewHolder, Wi-Fi entry list = null");
+ if (mWifiEntries == null || position >= mWifiEntriesCount) {
+ return;
}
- }
-
- private List<WifiEntry> getWifiEntryList() {
- if (mInternetDialogController.getWifiEntryList() == null) {
- return null;
- }
-
- return mInternetDialogController.getWifiEntryList().stream()
- .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
- || !wifiEntry.hasInternetAccess()))
- .limit(getItemCount())
- .collect(Collectors.toList());
+ viewHolder.onBind(mWifiEntries.get(position));
}
/**
- * The total number of networks (mobile network and entries of Wi-Fi) should be four in
- * {@link InternetDialog}.
+ * Updates the Wi-Fi networks.
*
- * Airplane mode is ON (mobile network is gone):
- * Return four Wi-Fi's entries if no internet Wi-Fi.
- * Return three Wi-Fi's entries if one internet Wi-Fi.
- * Airplane mode is OFF (mobile network is visible):
- * Return three Wi-Fi's entries if no internet Wi-Fi.
- * Return two Wi-Fi's entries if one internet Wi-Fi.
+ * @param wifiEntries the updated Wi-Fi entries.
+ * @param wifiEntriesCount the total number of Wi-Fi entries.
+ */
+ public void setWifiEntries(@Nullable List<WifiEntry> wifiEntries, int wifiEntriesCount) {
+ mWifiEntries = wifiEntries;
+ mWifiEntriesCount = wifiEntriesCount;
+ }
+
+ /**
+ * Gets the total number of Wi-Fi networks.
*
- * @return The total number of networks.
+ * @return The total number of Wi-Fi entries.
*/
@Override
public int getItemCount() {
- final boolean hasInternetWifi = mInternetDialogController.getInternetWifiEntry() != null;
- if (mInternetDialogController.isAirplaneModeEnabled()) {
- return hasInternetWifi ? 3 : 4;
- } else {
- return hasInternetWifi ? 2 : 3;
- }
+ return mWifiEntriesCount;
}
/**
@@ -137,10 +111,11 @@
final ImageView mWifiIcon;
final TextView mWifiTitleText;
final TextView mWifiSummaryText;
- final ImageView mWifiLockedIcon;
+ final ImageView mWifiEndIcon;
final Context mContext;
final InternetDialogController mInternetDialogController;
+ @VisibleForTesting
protected WifiUtils.InternetIconInjector mWifiIconInjector;
InternetViewHolder(View view, InternetDialogController internetDialogController) {
@@ -153,28 +128,25 @@
mWifiIcon = view.requireViewById(R.id.wifi_icon);
mWifiTitleText = view.requireViewById(R.id.wifi_title);
mWifiSummaryText = view.requireViewById(R.id.wifi_summary);
- mWifiLockedIcon = view.requireViewById(R.id.wifi_locked_icon);
+ mWifiEndIcon = view.requireViewById(R.id.wifi_end_icon);
mWifiIconInjector = mInternetDialogController.getWifiIconInjector();
}
- void onBind(WifiEntry wifiEntry) {
- int security = wifiEntry.getSecurity();
- try {
- mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
- if (isOpenNetwork(security)) {
- mWifiLockedIcon.setVisibility(View.GONE);
- } else {
- mWifiLockedIcon.setVisibility(View.VISIBLE);
- mWifiLockedIcon.setImageDrawable(
- mContext.getDrawable(R.drawable.ic_friction_lock_closed));
- }
- } catch (Throwable throwable) {
- throwable.printStackTrace();
- }
-
+ void onBind(@NonNull WifiEntry wifiEntry) {
+ mWifiIcon.setImageDrawable(getWifiDrawable(wifiEntry));
setWifiNetworkLayout(wifiEntry.getTitle(),
Html.fromHtml(wifiEntry.getSummary(false), Html.FROM_HTML_MODE_LEGACY));
+ final int connectedState = wifiEntry.getConnectedState();
+ final int security = wifiEntry.getSecurity();
+ updateEndIcon(connectedState, security);
+
+ if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
+ mWifiListLayout.setOnClickListener(
+ v -> mInternetDialogController.launchWifiNetworkDetailsSetting(
+ wifiEntry.getKey()));
+ return;
+ }
mWifiListLayout.setOnClickListener(v -> {
if (wifiEntry.shouldEditBeforeConnect()) {
final Intent intent = new Intent(ACTION_WIFI_DIALOG);
@@ -188,28 +160,20 @@
});
}
- /** Return true if this is an open network AccessPoint. */
- boolean isOpenNetwork(int security) {
- return security == SECURITY_NONE
- || security == SECURITY_OWE;
- }
-
void setWifiNetworkLayout(CharSequence title, CharSequence summary) {
- mWifiNetworkLayout.setVisibility(View.VISIBLE);
mWifiTitleText.setText(title);
if (TextUtils.isEmpty(summary)) {
- mWifiTitleText.setGravity(Gravity.CENTER);
mWifiSummaryText.setVisibility(View.GONE);
return;
- } else {
- mWifiTitleText.setGravity(Gravity.BOTTOM);
- mWifiSummaryText.setGravity(Gravity.TOP);
- mWifiSummaryText.setVisibility(View.VISIBLE);
}
+ mWifiSummaryText.setVisibility(View.VISIBLE);
mWifiSummaryText.setText(summary);
}
- Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) throws Throwable {
+ Drawable getWifiDrawable(@NonNull WifiEntry wifiEntry) {
+ if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+ return null;
+ }
final Drawable drawable = mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(),
wifiEntry.getLevel());
if (drawable == null) {
@@ -221,5 +185,20 @@
shared.set(drawable);
return shared.get();
}
+
+ void updateEndIcon(int connectedState, int security) {
+ Drawable drawable = null;
+ if (connectedState != WifiEntry.CONNECTED_STATE_DISCONNECTED) {
+ drawable = mContext.getDrawable(R.drawable.ic_settings_24dp);
+ } else if (security != WifiEntry.SECURITY_NONE && security != WifiEntry.SECURITY_OWE) {
+ drawable = mContext.getDrawable(R.drawable.ic_friction_lock_closed);
+ }
+ if (drawable == null) {
+ mWifiEndIcon.setVisibility(View.GONE);
+ return;
+ }
+ mWifiEndIcon.setVisibility(View.VISIBLE);
+ mWifiEndIcon.setImageDrawable(drawable);
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
index e1e0ba7..b1db8a9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialog.java
@@ -21,13 +21,11 @@
import android.app.AlertDialog;
import android.content.Context;
-import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable;
import android.net.Network;
import android.net.NetworkCapabilities;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Handler;
@@ -51,11 +49,12 @@
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
-import android.widget.Space;
import android.widget.Switch;
import android.widget.TextView;
+import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
@@ -92,7 +91,7 @@
@VisibleForTesting
protected View mDialogView;
@VisibleForTesting
- protected WifiEntry mConnectedWifiEntry;
+ protected boolean mCanConfigWifi;
private InternetDialogFactory mInternetDialogFactory;
private SubscriptionManager mSubscriptionManager;
@@ -105,12 +104,14 @@
private TextView mInternetDialogSubTitle;
private View mDivider;
private ProgressBar mProgressBar;
+ private LinearLayout mInternetDialogLayout;
private LinearLayout mInternetListLayout;
private LinearLayout mConnectedWifListLayout;
private LinearLayout mConnectedWifList;
private LinearLayout mMobileNetworkLayout;
private LinearLayout mMobileNetworkList;
private LinearLayout mTurnWifiOnLayout;
+ private TextView mWifiToggleTitleText;
private LinearLayout mSeeAllLayout;
private RecyclerView mWifiRecyclerView;
private ImageView mConnectedWifiIcon;
@@ -125,10 +126,14 @@
private Button mDoneButton;
private Drawable mBackgroundOn;
private int mListMaxHeight;
- private int mListMaxWidth;
+ private int mLayoutWidth;
private int mDefaultDataSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
private boolean mCanConfigMobileData;
+ // Wi-Fi entries
+ protected WifiEntry mConnectedWifiEntry;
+ protected int mWifiEntriesCount;
+
// Wi-Fi scanning progress bar
protected boolean mIsProgressBarVisible;
protected boolean mIsSearchingHidden;
@@ -142,16 +147,17 @@
private final ViewTreeObserver.OnGlobalLayoutListener mInternetListLayoutListener = () -> {
// Set max height for list
- if (mInternetListLayout.getHeight() > mListMaxHeight) {
- ViewGroup.LayoutParams params = mInternetListLayout.getLayoutParams();
+ if (mInternetDialogLayout.getHeight() > mListMaxHeight) {
+ ViewGroup.LayoutParams params = mInternetDialogLayout.getLayoutParams();
params.height = mListMaxHeight;
- mInternetListLayout.setLayoutParams(params);
+ mInternetDialogLayout.setLayoutParams(params);
}
};
public InternetDialog(Context context, InternetDialogFactory internetDialogFactory,
InternetDialogController internetDialogController, boolean canConfigMobileData,
- boolean aboveStatusBar, UiEventLogger uiEventLogger, @Main Handler handler) {
+ boolean canConfigWifi, boolean aboveStatusBar, UiEventLogger uiEventLogger,
+ @Main Handler handler) {
super(context, R.style.Theme_SystemUI_Dialog_Internet);
if (DEBUG) {
Log.d(TAG, "Init InternetDialog");
@@ -165,6 +171,7 @@
mTelephonyManager = mInternetDialogController.getTelephonyManager();
mWifiManager = mInternetDialogController.getWifiManager();
mCanConfigMobileData = canConfigMobileData;
+ mCanConfigWifi = canConfigWifi;
mLayoutManager = new LinearLayoutManager(mContext) {
@Override
@@ -174,7 +181,7 @@
};
mListMaxHeight = context.getResources().getDimensionPixelSize(
R.dimen.internet_dialog_list_max_height);
- mListMaxWidth = context.getResources().getDimensionPixelSize(
+ mLayoutWidth = context.getResources().getDimensionPixelSize(
R.dimen.internet_dialog_list_max_width);
mUiEventLogger = uiEventLogger;
mAdapter = new InternetAdapter(mInternetDialogController);
@@ -202,11 +209,14 @@
layoutParams.setFitInsetsIgnoringVisibility(true);
window.setAttributes(layoutParams);
window.setContentView(mDialogView);
- window.setLayout(mListMaxWidth, ViewGroup.LayoutParams.WRAP_CONTENT);
+ //Only fix the width for large screen or tablet.
+ window.setLayout(mContext.getResources().getDimensionPixelSize(
+ R.dimen.internet_dialog_list_max_width), ViewGroup.LayoutParams.WRAP_CONTENT);
window.setWindowAnimations(R.style.Animation_InternetDialog);
window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
window.addFlags(FLAG_LAYOUT_NO_LIMITS);
+ mInternetDialogLayout = mDialogView.requireViewById(R.id.internet_connectivity_dialog);
mInternetDialogTitle = mDialogView.requireViewById(R.id.internet_dialog_title);
mInternetDialogSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
mDivider = mDialogView.requireViewById(R.id.divider);
@@ -215,6 +225,7 @@
mMobileNetworkLayout = mDialogView.requireViewById(R.id.mobile_network_layout);
mMobileNetworkList = mDialogView.requireViewById(R.id.mobile_network_list);
mTurnWifiOnLayout = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mWifiToggleTitleText = mDialogView.requireViewById(R.id.wifi_toggle_title);
mConnectedWifListLayout = mDialogView.requireViewById(R.id.wifi_connected_layout);
mConnectedWifList = mDialogView.requireViewById(R.id.wifi_connected_list);
mConnectedWifiIcon = mDialogView.requireViewById(R.id.wifi_connected_icon);
@@ -230,7 +241,7 @@
mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_toggle);
mWiFiToggle = mDialogView.requireViewById(R.id.wifi_toggle);
mBackgroundOn = mContext.getDrawable(R.drawable.settingslib_switch_bar_bg_on);
- mInternetListLayout.getViewTreeObserver().addOnGlobalLayoutListener(
+ mInternetDialogLayout.getViewTreeObserver().addOnGlobalLayoutListener(
mInternetListLayoutListener);
mInternetDialogTitle.setText(getDialogTitleText());
mInternetDialogTitle.setGravity(Gravity.START | Gravity.CENTER_VERTICAL);
@@ -247,7 +258,19 @@
if (DEBUG) {
Log.d(TAG, "onStart");
}
- mInternetDialogController.onStart(this);
+ mInternetDialogController.onStart(this, mCanConfigWifi);
+ if (!mCanConfigWifi) {
+ hideWifiViews();
+ }
+ }
+
+ @VisibleForTesting
+ void hideWifiViews() {
+ setProgressBarVisible(false);
+ mTurnWifiOnLayout.setVisibility(View.GONE);
+ mConnectedWifListLayout.setVisibility(View.GONE);
+ mWifiRecyclerView.setVisibility(View.GONE);
+ mSeeAllLayout.setVisibility(View.GONE);
}
@Override
@@ -286,23 +309,22 @@
} else {
mInternetDialogSubTitle.setText(getSubtitleText());
}
- showProgressBar();
setMobileDataLayout(mInternetDialogController.activeNetworkIsCellular());
+ if (!mCanConfigWifi) {
+ return;
+ }
+
+ showProgressBar();
final boolean isDeviceLocked = mInternetDialogController.isDeviceLocked();
final boolean isWifiEnabled = mWifiManager.isWifiEnabled();
updateWifiToggle(isWifiEnabled, isDeviceLocked);
updateConnectedWifi(isWifiEnabled, isDeviceLocked);
- List<WifiEntry> wifiEntryList = mInternetDialogController.getWifiEntryList();
- final int wifiListVisibility =
- (isDeviceLocked || wifiEntryList == null || wifiEntryList.size() <= 0)
- ? View.GONE : View.VISIBLE;
- mWifiRecyclerView.setVisibility(wifiListVisibility);
- if (wifiListVisibility == View.VISIBLE) {
- mAdapter.notifyDataSetChanged();
- }
- mSeeAllLayout.setVisibility(wifiListVisibility);
+ final int visibility = (isDeviceLocked || !isWifiEnabled || mWifiEntriesCount <= 0)
+ ? View.GONE : View.VISIBLE;
+ mWifiRecyclerView.setVisibility(visibility);
+ mSeeAllLayout.setVisibility(visibility);
}
private void setOnClickListener() {
@@ -368,6 +390,12 @@
private void updateWifiToggle(boolean isWifiEnabled, boolean isDeviceLocked) {
mWiFiToggle.setChecked(isWifiEnabled);
+ if (isDeviceLocked && mInternetDialogController.isNightMode()) {
+ int titleColor = mConnectedWifiEntry != null ? mContext.getColor(
+ R.color.connected_network_primary_color) : Utils.getColorAttrDefaultColor(
+ mContext, android.R.attr.textColorPrimary);
+ mWifiToggleTitleText.setTextColor(titleColor);
+ }
mTurnWifiOnLayout.setBackground(
(isDeviceLocked && mConnectedWifiEntry != null) ? mBackgroundOn : null);
}
@@ -379,8 +407,8 @@
return;
}
mConnectedWifListLayout.setVisibility(View.VISIBLE);
- mConnectedWifiTitleText.setText(mInternetDialogController.getInternetWifiTitle());
- mConnectedWifiSummaryText.setText(mInternetDialogController.getInternetWifiSummary());
+ mConnectedWifiTitleText.setText(mConnectedWifiEntry.getTitle());
+ mConnectedWifiSummaryText.setText(mConnectedWifiEntry.getSummary(false));
mConnectedWifiIcon.setImageDrawable(
mInternetDialogController.getInternetWifiDrawable(mConnectedWifiEntry));
if (mInternetDialogController.isNightMode()) {
@@ -395,7 +423,10 @@
}
void onClickConnectedWifi() {
- mInternetDialogController.launchWifiNetworkDetailsSetting();
+ if (mConnectedWifiEntry == null) {
+ return;
+ }
+ mInternetDialogController.launchWifiNetworkDetailsSetting(mConnectedWifiEntry.getKey());
}
void onClickSeeMoreButton() {
@@ -430,8 +461,7 @@
return;
}
setProgressBarVisible(true);
- List<ScanResult> wifiScanResults = mWifiManager.getScanResults();
- if (wifiScanResults != null && wifiScanResults.size() > 0) {
+ if (mConnectedWifiEntry != null || mWifiEntriesCount > 0) {
mHandler.postDelayed(mHideProgressBarRunnable, PROGRESS_DELAY_MS);
} else if (!mIsSearchingHidden) {
mHandler.postDelayed(mHideSearchingRunnable, PROGRESS_DELAY_MS);
@@ -459,8 +489,7 @@
}
private void showTurnOffMobileDialog() {
- CharSequence carrierName =
- mSubscriptionManager.getDefaultDataSubscriptionInfo().getCarrierName();
+ CharSequence carrierName = getMobileNetworkTitle();
boolean isInService = mInternetDialogController.isVoiceStateInService();
if (TextUtils.isEmpty(carrierName) || !isInService) {
carrierName = mContext.getString(R.string.mobile_data_disable_message_default_carrier);
@@ -516,8 +545,8 @@
}
@Override
+ @WorkerThread
public void onDataConnectionStateChanged(int state, int networkType) {
- mAdapter.notifyDataSetChanged();
mHandler.post(() -> updateDialog());
}
@@ -532,10 +561,16 @@
}
@Override
- public void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry) {
+ @WorkerThread
+ public void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+ @Nullable WifiEntry connectedEntry) {
mConnectedWifiEntry = connectedEntry;
- mAdapter.notifyDataSetChanged();
- mHandler.post(() -> updateDialog());
+ mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+ mAdapter.setWifiEntries(wifiEntries, mWifiEntriesCount);
+ mHandler.post(() -> {
+ mAdapter.notifyDataSetChanged();
+ updateDialog();
+ });
}
@Override
@@ -548,24 +583,6 @@
}
}
- @Override
- public void onWifiStateReceived(Context context, Intent intent) {
- if (intent == null) {
- return;
- }
-
- String action = intent.getAction();
- if (action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- mInternetDialogController.scanWifiAccessPoints();
- showProgressBar();
- return;
- }
-
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
- mHandler.post(() -> updateDialog());
- }
- }
-
public enum InternetDialogEvent implements UiEventLogger.UiEventEnum {
@UiEvent(doc = "The Internet dialog became visible on the screen.")
INTERNET_DIALOG_SHOW(843);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
index ed32730..70f52ad 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogController.java
@@ -32,7 +32,6 @@
import android.net.Network;
import android.net.NetworkCapabilities;
import android.net.NetworkRequest;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.provider.Settings;
@@ -53,6 +52,7 @@
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
import com.android.internal.logging.UiEventLogger;
import com.android.keyguard.KeyguardUpdateMonitor;
@@ -108,6 +108,8 @@
R.string.all_network_unavailable;
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+ static final int MAX_WIFI_ENTRY_COUNT = 4;
+
private WifiManager mWifiManager;
private Context mContext;
private SubscriptionManager mSubscriptionManager;
@@ -122,7 +124,8 @@
private AccessPointController mAccessPointController;
private IntentFilter mConnectionStateFilter;
private InternetDialogCallback mCallback;
- private List<WifiEntry> mWifiEntry;
+ private WifiEntry mConnectedEntry;
+ private int mWifiEntriesCount;
private UiEventLogger mUiEventLogger;
private BroadcastDispatcher mBroadcastDispatcher;
private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@@ -132,16 +135,15 @@
@VisibleForTesting
protected ActivityStarter mActivityStarter;
@VisibleForTesting
- protected WifiEntry mConnectedEntry;
- @VisibleForTesting
protected SubscriptionManager.OnSubscriptionsChangedListener mOnSubscriptionsChangedListener;
@VisibleForTesting
protected InternetTelephonyCallback mInternetTelephonyCallback;
@VisibleForTesting
protected WifiUtils.InternetIconInjector mWifiIconInjector;
-
@VisibleForTesting
- KeyguardStateController mKeyguardStateController;
+ protected boolean mCanConfigWifi;
+ @VisibleForTesting
+ protected KeyguardStateController mKeyguardStateController;
private final KeyguardUpdateMonitorCallback mKeyguardUpdateCallback =
new KeyguardUpdateMonitorCallback() {
@@ -183,8 +185,6 @@
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mKeyguardStateController = keyguardStateController;
mConnectionStateFilter = new IntentFilter();
- mConnectionStateFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
- mConnectionStateFilter.addAction(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION);
mConnectionStateFilter.addAction(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED);
mUiEventLogger = uiEventLogger;
mActivityStarter = starter;
@@ -193,7 +193,7 @@
mWifiIconInjector = new WifiUtils.InternetIconInjector(mContext);
}
- void onStart(@NonNull InternetDialogCallback callback) {
+ void onStart(@NonNull InternetDialogCallback callback, boolean canConfigWifi) {
if (DEBUG) {
Log.d(TAG, "onStart");
}
@@ -217,6 +217,7 @@
mConnectivityManager.registerNetworkCallback(new NetworkRequest.Builder()
.addCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
.build(), new DataConnectivityListener(), mHandler);
+ mCanConfigWifi = canConfigWifi;
scanWifiAccessPoints();
}
@@ -247,8 +248,7 @@
return new Intent(ACTION_NETWORK_PROVIDER_SETTINGS).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
- protected Intent getWifiDetailsSettingsIntent() {
- String key = mConnectedEntry == null ? null : mConnectedEntry.getKey();
+ protected Intent getWifiDetailsSettingsIntent(String key) {
if (TextUtils.isEmpty(key)) {
if (DEBUG) {
Log.d(TAG, "connected entry's key is empty");
@@ -270,7 +270,7 @@
return null;
}
- if (!mWifiManager.isWifiEnabled()) {
+ if (mCanConfigWifi && !mWifiManager.isWifiEnabled()) {
// When the airplane mode is off and Wi-Fi is disabled.
// Sub-Title: Wi-Fi is off
if (DEBUG) {
@@ -288,12 +288,11 @@
return mContext.getText(SUBTITLE_TEXT_UNLOCK_TO_VIEW_NETWORKS);
}
- final List<ScanResult> wifiList = mWifiManager.getScanResults();
- if (wifiList != null && wifiList.size() != 0) {
- return mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT);
+ if (mConnectedEntry != null || mWifiEntriesCount > 0) {
+ return mCanConfigWifi ? mContext.getText(SUBTITLE_TEXT_TAP_A_NETWORK_TO_CONNECT) : null;
}
- if (isProgressBarVisible) {
+ if (mCanConfigWifi && isProgressBarVisible) {
// When the Wi-Fi scan result callback is received
// Sub-Title: Searching for networks...
return mContext.getText(SUBTITLE_TEXT_SEARCHING_FOR_NETWORKS);
@@ -317,7 +316,7 @@
return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
}
- if (!isMobileDataEnabled()) {
+ if (mCanConfigWifi && !isMobileDataEnabled()) {
if (DEBUG) {
Log.d(TAG, "Mobile data off");
}
@@ -331,10 +330,16 @@
return mContext.getText(SUBTITLE_TEXT_ALL_CARRIER_NETWORK_UNAVAILABLE);
}
- return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+ if (mCanConfigWifi) {
+ return mContext.getText(SUBTITLE_TEXT_NON_CARRIER_NETWORK_UNAVAILABLE);
+ }
+ return null;
}
Drawable getInternetWifiDrawable(@NonNull WifiEntry wifiEntry) {
+ if (wifiEntry.getLevel() == WifiEntry.WIFI_LEVEL_UNREACHABLE) {
+ return null;
+ }
final Drawable drawable =
mWifiIconInjector.getIcon(wifiEntry.shouldShowXLevelIcon(), wifiEntry.getLevel());
if (drawable == null) {
@@ -388,7 +393,8 @@
level += 1;
numLevels += 1;
}
- return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON, false);
+ return getSignalStrengthIcon(mContext, level, numLevels, NO_CELL_DATA_TYPE_ICON,
+ !isMobileDataEnabled());
}
Drawable getSignalStrengthIcon(Context context, int level, int numLevels,
@@ -549,33 +555,13 @@
return summary;
}
- String getInternetWifiTitle() {
- if (getInternetWifiEntry() == null) {
- if (DEBUG) {
- Log.d(TAG, "connected entry is null");
- }
- return "";
- }
- return getInternetWifiEntry().getTitle();
- }
-
- String getInternetWifiSummary() {
- if (getInternetWifiEntry() == null) {
- if (DEBUG) {
- Log.d(TAG, "connected entry is null");
- }
- return "";
- }
- return getInternetWifiEntry().getSummary(false);
- }
-
void launchNetworkSetting() {
mCallback.dismissDialog();
mActivityStarter.postStartActivityDismissingKeyguard(getSettingsIntent(), 0);
}
- void launchWifiNetworkDetailsSetting() {
- Intent intent = getWifiDetailsSettingsIntent();
+ void launchWifiNetworkDetailsSetting(String key) {
+ Intent intent = getWifiDetailsSettingsIntent(key);
if (intent != null) {
mCallback.dismissDialog();
mActivityStarter.postStartActivityDismissingKeyguard(intent, 0);
@@ -590,18 +576,6 @@
}
}
- List<WifiEntry> getWifiEntryList() {
- return mWifiEntry;
- }
-
- WifiEntry getInternetWifiEntry() {
- if (mConnectedEntry == null || !mConnectedEntry.isDefaultNetwork()
- || !mConnectedEntry.hasInternetAccess()) {
- return null;
- }
- return mConnectedEntry;
- }
-
WifiManager getWifiManager() {
return mWifiManager;
}
@@ -767,7 +741,7 @@
final Intent intent = new Intent("com.android.settings.WIFI_DIALOG")
.putExtra(EXTRA_CHOSEN_WIFI_ENTRY_KEY, mWifiEntry.getKey());
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- mActivityStarter.startActivity(intent, true);
+ mActivityStarter.startActivity(intent, false /* dismissShade */);
} else if (status == CONNECT_STATUS_FAILURE_UNKNOWN) {
Toast.makeText(mContext, R.string.wifi_failed_connect_message,
Toast.LENGTH_SHORT).show();
@@ -779,20 +753,33 @@
}
}
- void scanWifiAccessPoints() {
- mAccessPointController.scanForAccessPoints();
+ private void scanWifiAccessPoints() {
+ if (mCanConfigWifi) {
+ mAccessPointController.scanForAccessPoints();
+ }
}
@Override
+ @WorkerThread
public void onAccessPointsChanged(List<WifiEntry> accessPoints) {
- if (accessPoints == null) {
+ if (!mCanConfigWifi) {
+ return;
+ }
+
+ if (accessPoints == null || accessPoints.size() == 0) {
+ mConnectedEntry = null;
+ mWifiEntriesCount = 0;
+ if (mCallback != null) {
+ mCallback.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+ }
return;
}
boolean hasConnectedWifi = false;
- mWifiEntry = accessPoints;
- for (WifiEntry wifiEntry : accessPoints) {
- if (wifiEntry.getConnectedState() == WifiEntry.CONNECTED_STATE_CONNECTED) {
+ final int accessPointSize = accessPoints.size();
+ for (int i = 0; i < accessPointSize; i++) {
+ WifiEntry wifiEntry = accessPoints.get(i);
+ if (wifiEntry.isDefaultNetwork() && wifiEntry.hasInternetAccess()) {
mConnectedEntry = wifiEntry;
hasConnectedWifi = true;
break;
@@ -802,7 +789,23 @@
mConnectedEntry = null;
}
- mCallback.onAccessPointsChanged(mWifiEntry, getInternetWifiEntry());
+ int count = MAX_WIFI_ENTRY_COUNT;
+ if (hasCarrier()) {
+ count -= 1;
+ }
+ if (hasConnectedWifi) {
+ count -= 1;
+ }
+ final List<WifiEntry> wifiEntries = accessPoints.stream()
+ .filter(wifiEntry -> (!wifiEntry.isDefaultNetwork()
+ || !wifiEntry.hasInternetAccess()))
+ .limit(count)
+ .collect(Collectors.toList());
+ mWifiEntriesCount = wifiEntries == null ? 0 : wifiEntries.size();
+
+ if (mCallback != null) {
+ mCallback.onAccessPointsChanged(wifiEntries, mConnectedEntry);
+ }
}
@Override
@@ -855,8 +858,17 @@
private class DataConnectivityListener extends ConnectivityManager.NetworkCallback {
@Override
+ @WorkerThread
public void onCapabilitiesChanged(@NonNull Network network,
@NonNull NetworkCapabilities networkCapabilities) {
+ if (mCanConfigWifi) {
+ for (int transport : networkCapabilities.getTransportTypes()) {
+ if (transport == NetworkCapabilities.TRANSPORT_WIFI) {
+ scanWifiAccessPoints();
+ break;
+ }
+ }
+ }
final Network activeNetwork = mConnectivityManager.getActiveNetwork();
if (activeNetwork != null && activeNetwork.equals(network)) {
// update UI
@@ -869,11 +881,6 @@
@Override
public void onReceive(Context context, Intent intent) {
final String action = intent.getAction();
- if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)
- || action.equals(WifiManager.SCAN_RESULTS_AVAILABLE_ACTION)) {
- mCallback.onWifiStateReceived(context, intent);
- }
-
if (action.equals(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)) {
if (DEBUG) {
Log.d(TAG, "ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED");
@@ -929,8 +936,7 @@
void dismissDialog();
- void onAccessPointsChanged(List<WifiEntry> wifiEntryList, WifiEntry connectedEntry);
-
- void onWifiStateReceived(Context context, Intent intent);
+ void onAccessPointsChanged(@Nullable List<WifiEntry> wifiEntries,
+ @Nullable WifiEntry connectedEntry);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
index e82e89ef1..11c6980 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/dialog/InternetDialogFactory.kt
@@ -31,17 +31,17 @@
*/
@SysUISingleton
class InternetDialogFactory @Inject constructor(
- @Main private val handler: Handler,
- private val internetDialogController: InternetDialogController,
- private val context: Context,
- private val uiEventLogger: UiEventLogger
+ @Main private val handler: Handler,
+ private val internetDialogController: InternetDialogController,
+ private val context: Context,
+ private val uiEventLogger: UiEventLogger
) {
companion object {
var internetDialog: InternetDialog? = null
}
/** Creates a [InternetDialog]. */
- fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean) {
+ fun create(aboveStatusBar: Boolean, canConfigMobileData: Boolean, canConfigWifi: Boolean) {
if (internetDialog != null) {
if (DEBUG) {
Log.d(TAG, "InternetDialog is showing, do not create it twice.")
@@ -49,7 +49,7 @@
return
} else {
internetDialog = InternetDialog(context, this, internetDialogController,
- canConfigMobileData, aboveStatusBar, uiEventLogger, handler)
+ canConfigMobileData, canConfigWifi, aboveStatusBar, uiEventLogger, handler)
internetDialog?.show()
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index a5fc5ab..4584b6d 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;
@@ -546,7 +547,7 @@
com.android.internal.R.string.config_recentsComponentName));
mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
.setPackage(mRecentsComponentName.getPackageName());
- mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources());
+ mWindowCornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(mContext);
mSupportsRoundedCornersOnWindows = ScreenDecorationsUtils
.supportsRoundedCornersOnWindows(mContext.getResources());
mSysUiState = sysUiState;
@@ -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/screenshot/ScreenshotController.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
index cab2168..8def475 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotController.java
@@ -33,6 +33,7 @@
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.annotation.MainThread;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
@@ -261,6 +262,7 @@
private Bitmap mScreenBitmap;
private SaveImageInBackgroundTask mSaveInBgTask;
private boolean mScreenshotTakenInPortrait;
+ private boolean mBlockAttach;
private Animator mScreenshotAnimation;
private RequestCallback mCurrentRequestCallback;
@@ -559,8 +561,8 @@
mScreenshotView.reset();
}
- mScreenshotView.updateOrientation(mWindowManager.getCurrentWindowMetrics()
- .getWindowInsets().getDisplayCutout());
+ mScreenshotView.updateOrientation(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets());
mScreenBitmap = screenshot;
@@ -594,9 +596,8 @@
// Delay scroll capture eval a bit to allow the underlying activity
// to set up in the new orientation.
mScreenshotHandler.postDelayed(this::requestScrollCapture, 150);
- mScreenshotView.updateDisplayCutoutMargins(
- mWindowManager.getCurrentWindowMetrics().getWindowInsets()
- .getDisplayCutout());
+ mScreenshotView.updateInsets(
+ mWindowManager.getCurrentWindowMetrics().getWindowInsets());
// screenshot animation calculations won't be valid anymore, so just end
if (mScreenshotAnimation != null && mScreenshotAnimation.isRunning()) {
mScreenshotAnimation.end();
@@ -732,6 +733,7 @@
new ViewTreeObserver.OnWindowAttachListener() {
@Override
public void onWindowAttached() {
+ mBlockAttach = false;
decorView.getViewTreeObserver().removeOnWindowAttachListener(this);
action.run();
}
@@ -748,14 +750,16 @@
mWindow.setContentView(contentView);
}
+ @MainThread
private void attachWindow() {
View decorView = mWindow.getDecorView();
- if (decorView.isAttachedToWindow()) {
+ if (decorView.isAttachedToWindow() || mBlockAttach) {
return;
}
if (DEBUG_WINDOW) {
Log.d(TAG, "attachWindow");
}
+ mBlockAttach = true;
mWindowManager.addView(decorView, mWindowLayoutParams);
decorView.requestApplyInsets();
}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
index e5e690bcb..dfb39e3 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotView.java
@@ -118,8 +118,8 @@
private static final long SCREENSHOT_TO_CORNER_SCALE_DURATION_MS = 234;
private static final long SCREENSHOT_ACTIONS_EXPANSION_DURATION_MS = 400;
private static final long SCREENSHOT_ACTIONS_ALPHA_DURATION_MS = 100;
- private static final long SCREENSHOT_DISMISS_Y_DURATION_MS = 350;
- private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 183;
+ private static final long SCREENSHOT_DISMISS_X_DURATION_MS = 350;
+ private static final long SCREENSHOT_DISMISS_ALPHA_DURATION_MS = 350;
private static final long SCREENSHOT_DISMISS_ALPHA_OFFSET_MS = 50; // delay before starting fade
private static final float SCREENSHOT_ACTIONS_START_SCALE_X = .7f;
private static final float ROUNDED_CORNER_RADIUS = .25f;
@@ -416,21 +416,30 @@
mScreenshotPreview.setImageDrawable(createScreenDrawable(mResources, bitmap, screenInsets));
}
- void updateDisplayCutoutMargins(DisplayCutout cutout) {
+ void updateInsets(WindowInsets insets) {
int orientation = mContext.getResources().getConfiguration().orientation;
mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
FrameLayout.LayoutParams p =
(FrameLayout.LayoutParams) mScreenshotStatic.getLayoutParams();
+ DisplayCutout cutout = insets.getDisplayCutout();
+ Insets navBarInsets = insets.getInsets(WindowInsets.Type.navigationBars());
if (cutout == null) {
- p.setMargins(0, 0, 0, 0);
+ p.setMargins(0, 0, 0, navBarInsets.bottom);
} else {
Insets waterfall = cutout.getWaterfallInsets();
if (mOrientationPortrait) {
- p.setMargins(waterfall.left, Math.max(cutout.getSafeInsetTop(), waterfall.top),
- waterfall.right, Math.max(cutout.getSafeInsetBottom(), waterfall.bottom));
+ p.setMargins(
+ waterfall.left,
+ Math.max(cutout.getSafeInsetTop(), waterfall.top),
+ waterfall.right,
+ Math.max(cutout.getSafeInsetBottom(),
+ Math.max(navBarInsets.bottom, waterfall.bottom)));
} else {
- p.setMargins(Math.max(cutout.getSafeInsetLeft(), waterfall.left), waterfall.top,
- Math.max(cutout.getSafeInsetRight(), waterfall.right), waterfall.bottom);
+ p.setMargins(
+ Math.max(cutout.getSafeInsetLeft(), waterfall.left),
+ waterfall.top,
+ Math.max(cutout.getSafeInsetRight(), waterfall.right),
+ Math.max(navBarInsets.bottom, waterfall.bottom));
}
}
mStaticLeftMargin = p.leftMargin;
@@ -438,10 +447,10 @@
mScreenshotStatic.requestLayout();
}
- void updateOrientation(DisplayCutout cutout) {
+ void updateOrientation(WindowInsets insets) {
int orientation = mContext.getResources().getConfiguration().orientation;
mOrientationPortrait = (orientation == ORIENTATION_PORTRAIT);
- updateDisplayCutoutMargins(cutout);
+ updateInsets(insets);
int screenshotFixedSize =
mContext.getResources().getDimensionPixelSize(R.dimen.global_screenshot_x_scale);
ViewGroup.LayoutParams params = mScreenshotPreview.getLayoutParams();
@@ -980,7 +989,6 @@
mScrollingScrim.setVisibility(View.GONE);
mScrollablePreview.setVisibility(View.GONE);
mScreenshotStatic.setTranslationX(0);
- mScreenshotPreview.setTranslationY(0);
mScreenshotPreview.setContentDescription(
mContext.getResources().getString(R.string.screenshot_preview_description));
mScreenshotPreview.setOnClickListener(null);
@@ -996,9 +1004,6 @@
mSmartChips.clear();
mQuickShareChip = null;
setAlpha(1);
- mDismissButton.setTranslationY(0);
- mActionsContainer.setTranslationY(0);
- mActionsContainerBackground.setTranslationY(0);
mScreenshotSelectorView.stop();
}
@@ -1026,22 +1031,19 @@
setAlpha(1 - animation.getAnimatedFraction());
});
- ValueAnimator yAnim = ValueAnimator.ofFloat(0, 1);
- yAnim.setInterpolator(mAccelerateInterpolator);
- yAnim.setDuration(SCREENSHOT_DISMISS_Y_DURATION_MS);
- float screenshotStartY = mScreenshotPreview.getTranslationY();
- float dismissStartY = mDismissButton.getTranslationY();
- yAnim.addUpdateListener(animation -> {
- float yDelta = MathUtils.lerp(0, mDismissDeltaY, animation.getAnimatedFraction());
- mScreenshotPreview.setTranslationY(screenshotStartY + yDelta);
- mScreenshotPreviewBorder.setTranslationY(screenshotStartY + yDelta);
- mDismissButton.setTranslationY(dismissStartY + yDelta);
- mActionsContainer.setTranslationY(yDelta);
- mActionsContainerBackground.setTranslationY(yDelta);
+ ValueAnimator xAnim = ValueAnimator.ofFloat(0, 1);
+ xAnim.setInterpolator(mAccelerateInterpolator);
+ xAnim.setDuration(SCREENSHOT_DISMISS_X_DURATION_MS);
+ float deltaX = mDirectionLTR
+ ? -1 * (mScreenshotPreviewBorder.getX() + mScreenshotPreviewBorder.getWidth())
+ : (mDisplayMetrics.widthPixels - mScreenshotPreviewBorder.getX());
+ xAnim.addUpdateListener(animation -> {
+ float currXDelta = MathUtils.lerp(0, deltaX, animation.getAnimatedFraction());
+ mScreenshotStatic.setTranslationX(currXDelta);
});
AnimatorSet animSet = new AnimatorSet();
- animSet.play(yAnim).with(alphaAnim);
+ animSet.play(xAnim).with(alphaAnim);
return animSet;
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index 90158c32..aba1a24 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -291,8 +291,8 @@
default void showAuthenticationDialog(PromptInfo promptInfo,
IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed,
- boolean requireConfirmation, int userId, String opPackageName,
- long operationId, @BiometricMultiSensorMode int multiSensorConfig) {
+ boolean requireConfirmation, int userId, long operationId, String opPackageName,
+ long requestId, @BiometricMultiSensorMode int multiSensorConfig) {
}
/** @see IStatusBar#onBiometricAuthenticated() */
@@ -845,7 +845,7 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId,
+ int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) {
synchronized (mLock) {
SomeArgs args = SomeArgs.obtain();
@@ -857,6 +857,7 @@
args.argi1 = userId;
args.arg6 = opPackageName;
args.arg7 = operationId;
+ args.arg8 = requestId;
args.argi2 = multiSensorConfig;
mHandler.obtainMessage(MSG_BIOMETRIC_SHOW, args)
.sendToTarget();
@@ -1315,8 +1316,9 @@
(boolean) someArgs.arg4 /* credentialAllowed */,
(boolean) someArgs.arg5 /* requireConfirmation */,
someArgs.argi1 /* userId */,
- (String) someArgs.arg6 /* opPackageName */,
(long) someArgs.arg7 /* operationId */,
+ (String) someArgs.arg6 /* opPackageName */,
+ (long) someArgs.arg8 /* requestId */,
someArgs.argi2 /* multiSensorConfig */);
}
someArgs.recycle();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 1431c9e..eb5f82c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -811,13 +811,8 @@
mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
}
} else if (mKeyguardUpdateMonitor.isScreenOn()) {
- if (mKeyguardUpdateMonitor.isUdfpsAvailable()) {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock_press),
- false /* isError */, true /* hideOnScreenOff */);
- } else {
- showTransientIndication(mContext.getString(R.string.keyguard_unlock),
- false /* isError */, true /* hideOnScreenOff */);
- }
+ showTransientIndication(mContext.getString(R.string.keyguard_unlock),
+ false /* isError */, true /* hideOnScreenOff */);
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index b833427..e845804 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -181,7 +181,8 @@
if (shouldApplyShadeBlur()) shadeExpansion else 0f, false))
var combinedBlur = (expansionRadius * INTERACTION_BLUR_FRACTION +
animationRadius * ANIMATION_BLUR_FRACTION)
- val qsExpandedRatio = qsPanelExpansion * shadeExpansion
+ val qsExpandedRatio = Interpolators.getNotificationScrimAlpha(qsPanelExpansion,
+ false /* notification */) * shadeExpansion
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
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/KeyguardStatusBarViewController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
index fefa994..893aa6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewController.java
@@ -16,6 +16,7 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_IN;
import static com.android.systemui.statusbar.events.SystemStatusAnimationSchedulerKt.ANIMATING_OUT;
@@ -23,19 +24,30 @@
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.res.Resources;
+import android.hardware.biometrics.BiometricSourceType;
+import android.util.MathUtils;
import android.view.View;
import androidx.annotation.NonNull;
import com.android.keyguard.CarrierTextController;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.animation.Interpolators;
import com.android.systemui.battery.BatteryMeterViewController;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.events.SystemStatusAnimationCallback;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
+import com.android.systemui.statusbar.notification.AnimatableProperty;
+import com.android.systemui.statusbar.notification.PropertyAnimator;
+import com.android.systemui.statusbar.notification.stack.AnimationProperties;
import com.android.systemui.statusbar.notification.stack.StackStateAnimator;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoController;
import com.android.systemui.util.ViewController;
@@ -49,6 +61,21 @@
/** View Controller for {@link com.android.systemui.statusbar.phone.KeyguardStatusBarView}. */
public class KeyguardStatusBarViewController extends ViewController<KeyguardStatusBarView> {
+ private static final AnimationProperties KEYGUARD_HUN_PROPERTIES =
+ new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
+
+ private float mKeyguardHeadsUpShowingAmount = 0.0f;
+ private final AnimatableProperty mHeadsUpShowingAmountAnimation = AnimatableProperty.from(
+ "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
+ (view, aFloat) -> {
+ mKeyguardHeadsUpShowingAmount = aFloat;
+ updateViewState();
+ },
+ view -> mKeyguardHeadsUpShowingAmount,
+ R.id.keyguard_hun_animator_tag,
+ R.id.keyguard_hun_animator_end_tag,
+ R.id.keyguard_hun_animator_start_tag);
+
private final CarrierTextController mCarrierTextController;
private final ConfigurationController mConfigurationController;
private final SystemStatusAnimationScheduler mAnimationScheduler;
@@ -57,7 +84,13 @@
private final StatusBarIconController mStatusBarIconController;
private final StatusBarIconController.TintedIconManager.Factory mTintedIconManagerFactory;
private final BatteryMeterViewController mBatteryMeterViewController;
- private final ViewStateProvider mViewStateProvider;
+ private final NotificationPanelViewController.NotificationPanelViewStateProvider
+ mNotificationPanelViewStateProvider;
+ private final KeyguardStateController mKeyguardStateController;
+ private final KeyguardBypassController mKeyguardBypassController;
+ private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ private final BiometricUnlockController mBiometricUnlockController;
+ private final SysuiStatusBarStateController mStatusBarStateController;
private final ConfigurationController.ConfigurationListener mConfigurationListener =
new ConfigurationController.ConfigurationListener() {
@@ -115,12 +148,73 @@
updateViewState();
};
+ private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
+ new KeyguardUpdateMonitorCallback() {
+ @Override
+ public void onBiometricAuthenticated(
+ int userId,
+ BiometricSourceType biometricSourceType,
+ boolean isStrongBiometric) {
+ if (mFirstBypassAttempt
+ && mKeyguardUpdateMonitor.isUnlockingWithBiometricAllowed(
+ isStrongBiometric)) {
+ mDelayShowingKeyguardStatusBar = true;
+ }
+ }
+
+ @Override
+ public void onBiometricRunningStateChanged(
+ boolean running,
+ BiometricSourceType biometricSourceType) {
+ boolean keyguardOrShadeLocked =
+ mStatusBarState == KEYGUARD
+ || mStatusBarState == StatusBarState.SHADE_LOCKED;
+ if (!running
+ && mFirstBypassAttempt
+ && keyguardOrShadeLocked
+ && !mDozing
+ && !mDelayShowingKeyguardStatusBar
+ && !mBiometricUnlockController.isBiometricUnlock()) {
+ mFirstBypassAttempt = false;
+ animateKeyguardStatusBarIn();
+ }
+ }
+
+ @Override
+ public void onFinishedGoingToSleep(int why) {
+ mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+ mDelayShowingKeyguardStatusBar = false;
+ }
+ };
+
+ private final StatusBarStateController.StateListener mStatusBarStateListener =
+ new StatusBarStateController.StateListener() {
+ @Override
+ public void onStateChanged(int newState) {
+ mStatusBarState = newState;
+ }
+ };
+
private final List<String> mBlockedIcons;
+ private final int mNotificationsHeaderCollideDistance;
private boolean mBatteryListening;
private StatusBarIconController.TintedIconManager mTintedIconManager;
private float mKeyguardStatusBarAnimateAlpha = 1f;
+ /**
+ * If face auth with bypass is running for the first time after you turn on the screen.
+ * (From aod or screen off)
+ */
+ private boolean mFirstBypassAttempt;
+ /**
+ * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
+ * the keyguard is dismissed to show the status bar.
+ */
+ private boolean mDelayShowingKeyguardStatusBar;
+ private int mStatusBarState;
+ private boolean mDozing;
+ private boolean mShowingKeyguardHeadsUp;
@Inject
public KeyguardStatusBarViewController(
@@ -133,7 +227,13 @@
StatusBarIconController statusBarIconController,
StatusBarIconController.TintedIconManager.Factory tintedIconManagerFactory,
BatteryMeterViewController batteryMeterViewController,
- ViewStateProvider viewStateProvider) {
+ NotificationPanelViewController.NotificationPanelViewStateProvider
+ notificationPanelViewStateProvider,
+ KeyguardStateController keyguardStateController,
+ KeyguardBypassController bypassController,
+ KeyguardUpdateMonitor keyguardUpdateMonitor,
+ BiometricUnlockController biometricUnlockController,
+ SysuiStatusBarStateController statusBarStateController) {
super(view);
mCarrierTextController = carrierTextController;
mConfigurationController = configurationController;
@@ -143,13 +243,33 @@
mStatusBarIconController = statusBarIconController;
mTintedIconManagerFactory = tintedIconManagerFactory;
mBatteryMeterViewController = batteryMeterViewController;
- mViewStateProvider = viewStateProvider;
+ mNotificationPanelViewStateProvider = notificationPanelViewStateProvider;
+ mKeyguardStateController = keyguardStateController;
+ mKeyguardBypassController = bypassController;
+ mKeyguardUpdateMonitor = keyguardUpdateMonitor;
+ mBiometricUnlockController = biometricUnlockController;
+ mStatusBarStateController = statusBarStateController;
+
+ mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
+ mKeyguardStateController.addCallback(
+ new KeyguardStateController.Callback() {
+ @Override
+ public void onKeyguardFadingAwayChanged() {
+ if (!mKeyguardStateController.isKeyguardFadingAway()) {
+ mFirstBypassAttempt = false;
+ mDelayShowingKeyguardStatusBar = false;
+ }
+ }
+ }
+ );
Resources r = getResources();
mBlockedIcons = Collections.unmodifiableList(Arrays.asList(
r.getString(com.android.internal.R.string.status_bar_volume),
r.getString(com.android.internal.R.string.status_bar_alarm_clock),
r.getString(com.android.internal.R.string.status_bar_call_strength)));
+ mNotificationsHeaderCollideDistance = r.getDimensionPixelSize(
+ R.dimen.header_notifications_collide_distance);
}
@Override
@@ -164,6 +284,8 @@
mConfigurationController.addCallback(mConfigurationListener);
mAnimationScheduler.addCallback(mAnimationCallback);
mUserInfoController.addCallback(mOnUserInfoChangedListener);
+ mStatusBarStateController.addCallback(mStatusBarStateListener);
+ mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
if (mTintedIconManager == null) {
mTintedIconManager =
mTintedIconManagerFactory.create(mView.findViewById(R.id.statusIcons));
@@ -178,6 +300,8 @@
mConfigurationController.removeCallback(mConfigurationListener);
mAnimationScheduler.removeCallback(mAnimationCallback);
mUserInfoController.removeCallback(mOnUserInfoChangedListener);
+ mStatusBarStateController.removeCallback(mStatusBarStateListener);
+ mKeyguardUpdateMonitor.removeCallback(mKeyguardUpdateMonitorCallback);
if (mTintedIconManager != null) {
mStatusBarIconController.removeIconGroup(mTintedIconManager);
}
@@ -221,6 +345,11 @@
mView.setTopClipping(notificationPanelTop - mView.getTop());
}
+ /** Sets the dozing state. */
+ public void setDozing(boolean dozing) {
+ mDozing = dozing;
+ }
+
/** Animate the keyguard status bar in. */
public void animateKeyguardStatusBarIn() {
mView.setVisibility(View.VISIBLE);
@@ -251,17 +380,28 @@
}
/**
- * Updates the {@link KeyguardStatusBarView} state based on what the {@link ViewStateProvider}
- * provides.
+ * Updates the {@link KeyguardStatusBarView} state based on what the
+ * {@link NotificationPanelViewController.NotificationPanelViewStateProvider} and other
+ * controllers provide.
*/
public void updateViewState() {
- ViewState newViewState = mViewStateProvider.provideViewState();
- if (!newViewState.mShouldUpdate) {
+ if (!isKeyguardShowing()) {
return;
}
- updateViewState(
- newViewState.mAlpha * mKeyguardStatusBarAnimateAlpha,
- newViewState.mVisibility);
+
+ float alphaQsExpansion = 1 - Math.min(
+ 1, mNotificationPanelViewStateProvider.getQsExpansionFraction() * 2);
+ float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
+ * mKeyguardStatusBarAnimateAlpha
+ * (1.0f - mKeyguardHeadsUpShowingAmount);
+
+ boolean hideForBypass =
+ mFirstBypassAttempt && mKeyguardUpdateMonitor.shouldListenForFace()
+ || mDelayShowingKeyguardStatusBar;
+ int newVisibility = newAlpha != 0f && !mDozing && !hideForBypass
+ ? View.VISIBLE : View.INVISIBLE;
+
+ updateViewState(newAlpha, newVisibility);
}
/**
@@ -272,6 +412,58 @@
mView.setVisibility(visibility);
}
+ /**
+ * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
+ * during swiping up.
+ */
+ private float getKeyguardContentsAlpha() {
+ float alpha;
+ if (isKeyguardShowing()) {
+ // When on Keyguard, we hide the header as soon as we expanded close enough to the
+ // header
+ alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ / (mView.getHeight() + mNotificationsHeaderCollideDistance);
+ } else {
+ // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
+ // soon as we start translating the stack.
+ alpha = mNotificationPanelViewStateProvider.getPanelViewExpandedHeight()
+ / mView.getHeight();
+ }
+ alpha = MathUtils.saturate(alpha);
+ alpha = (float) Math.pow(alpha, 0.75);
+ return alpha;
+ }
+
+ /**
+ * Update {@link KeyguardStatusBarView}'s visibility based on whether keyguard is showing and
+ * whether heads up is visible.
+ */
+ public void updateForHeadsUp() {
+ updateForHeadsUp(true);
+ }
+
+ void updateForHeadsUp(boolean animate) {
+ boolean showingKeyguardHeadsUp =
+ isKeyguardShowing() && mNotificationPanelViewStateProvider.shouldHeadsUpBeVisible();
+ if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
+ mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
+ if (isKeyguardShowing()) {
+ PropertyAnimator.setProperty(
+ mView,
+ mHeadsUpShowingAmountAnimation,
+ showingKeyguardHeadsUp ? 1.0f : 0.0f,
+ KEYGUARD_HUN_PROPERTIES,
+ animate);
+ } else {
+ PropertyAnimator.applyImmediately(mView, mHeadsUpShowingAmountAnimation, 0.0f);
+ }
+ }
+ }
+
+ private boolean isKeyguardShowing() {
+ return mStatusBarState == KEYGUARD;
+ }
+
/** */
public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
pw.println("KeyguardStatusBarView:");
@@ -279,22 +471,4 @@
mView.dump(fd, pw, args);
}
- /** An interface that provides the desired state of {@link KeyguardStatusBarView}. */
- public interface ViewStateProvider {
- /** Provides the state. */
- ViewState provideViewState();
- }
-
- /** A POJO for the desired state of {@link KeyguardStatusBarView}. */
- static class ViewState {
- final boolean mShouldUpdate;
- final float mAlpha;
- final int mVisibility;
-
- ViewState(boolean shouldUpdate, float alpha, int visibility) {
- this.mShouldUpdate = shouldUpdate;
- this.mAlpha = alpha;
- this.mVisibility = visibility;
- }
- }
}
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 5f2dab8..51d531b 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;
@@ -55,7 +57,6 @@
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.Drawable;
-import android.hardware.biometrics.BiometricSourceType;
import android.os.Bundle;
import android.os.Handler;
import android.os.PowerManager;
@@ -91,13 +92,13 @@
import com.android.keyguard.KeyguardStatusView;
import com.android.keyguard.KeyguardStatusViewController;
import com.android.keyguard.KeyguardUpdateMonitor;
-import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.keyguard.LockIconViewController;
import com.android.keyguard.dagger.KeyguardQsUserSwitchComponent;
import com.android.keyguard.dagger.KeyguardStatusBarViewComponent;
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;
@@ -113,6 +114,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;
@@ -178,7 +180,6 @@
import java.util.List;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
-import java.util.function.Function;
import javax.inject.Inject;
import javax.inject.Provider;
@@ -232,7 +233,6 @@
@VisibleForTesting final StatusBarStateListener mStatusBarStateListener =
new StatusBarStateListener();
- private final BiometricUnlockController mBiometricUnlockController;
private final NotificationPanelView mView;
private final VibratorHelper mVibratorHelper;
private final MetricsLogger mMetricsLogger;
@@ -260,53 +260,6 @@
private static final Rect M_DUMMY_DIRTY_RECT = new Rect(0, 0, 1, 1);
private static final Rect EMPTY_RECT = new Rect();
- private final AnimatableProperty KEYGUARD_HEADS_UP_SHOWING_AMOUNT = AnimatableProperty.from(
- "KEYGUARD_HEADS_UP_SHOWING_AMOUNT",
- (notificationPanelView, aFloat) -> setKeyguardHeadsUpShowingAmount(aFloat),
- (Function<NotificationPanelView, Float>) notificationPanelView ->
- getKeyguardHeadsUpShowingAmount(),
- R.id.keyguard_hun_animator_tag, R.id.keyguard_hun_animator_end_tag,
- R.id.keyguard_hun_animator_start_tag);
- private static final AnimationProperties
- KEYGUARD_HUN_PROPERTIES =
- new AnimationProperties().setDuration(StackStateAnimator.ANIMATION_DURATION_STANDARD);
- @VisibleForTesting
- final KeyguardUpdateMonitorCallback
- mKeyguardUpdateCallback =
- new KeyguardUpdateMonitorCallback() {
-
- @Override
- public void onBiometricAuthenticated(int userId,
- BiometricSourceType biometricSourceType,
- boolean isStrongBiometric) {
- if (mFirstBypassAttempt
- && mUpdateMonitor.isUnlockingWithBiometricAllowed(isStrongBiometric)) {
- mDelayShowingKeyguardStatusBar = true;
- }
- }
-
- @Override
- public void onBiometricRunningStateChanged(boolean running,
- BiometricSourceType biometricSourceType) {
- boolean
- keyguardOrShadeLocked =
- mBarState == KEYGUARD
- || mBarState == StatusBarState.SHADE_LOCKED;
- if (!running && mFirstBypassAttempt && keyguardOrShadeLocked && !mDozing
- && !mDelayShowingKeyguardStatusBar
- && !mBiometricUnlockController.isBiometricUnlock()) {
- mFirstBypassAttempt = false;
- mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
- }
- }
-
- @Override
- public void onFinishedGoingToSleep(int why) {
- mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
- mDelayShowingKeyguardStatusBar = false;
- }
- };
-
private final LayoutInflater mLayoutInflater;
private final PowerManager mPowerManager;
private final AccessibilityManager mAccessibilityManager;
@@ -395,7 +348,6 @@
private FlingAnimationUtils mFlingAnimationUtils;
private int mStatusBarMinHeight;
private int mStatusBarHeaderHeightKeyguard;
- private int mNotificationsHeaderCollideDistance;
private float mOverStretchAmount;
private float mDownX;
private float mDownY;
@@ -512,6 +464,8 @@
private final NotificationLockscreenUserManager mLockscreenUserManager;
private final UserManager mUserManager;
private final MediaDataManager mMediaDataManager;
+ private final SysUiState mSysUiState;
+
private NotificationShadeDepthController mDepthController;
private int mDisplayId;
@@ -527,8 +481,6 @@
private int mDarkIconSize;
private int mHeadsUpInset;
private boolean mHeadsUpPinnedMode;
- private float mKeyguardHeadsUpShowingAmount = 0.0f;
- private boolean mShowingKeyguardHeadsUp;
private boolean mAllowExpandForSmallExpansion;
private Runnable mExpandAfterLayoutRunnable;
@@ -587,17 +539,6 @@
*/
private boolean mIsPanelCollapseOnQQS;
- /**
- * If face auth with bypass is running for the first time after you turn on the screen.
- * (From aod or screen off)
- */
- private boolean mFirstBypassAttempt;
- /**
- * If auth happens successfully during {@code mFirstBypassAttempt}, and we should wait until
- * the keyguard is dismissed to show the status bar.
- */
- private boolean mDelayShowingKeyguardStatusBar;
-
private boolean mAnimatingQS;
/**
@@ -682,27 +623,6 @@
}
};
- private final KeyguardStatusBarViewController.ViewStateProvider mViewStateProvider =
- new KeyguardStatusBarViewController.ViewStateProvider() {
- @Override
- public KeyguardStatusBarViewController.ViewState provideViewState() {
- float alphaQsExpansion = 1 - Math.min(1, computeQsExpansionFraction() * 2);
- float newAlpha = Math.min(getKeyguardContentsAlpha(), alphaQsExpansion)
- * (1.0f - mKeyguardHeadsUpShowingAmount);
-
- boolean hideForBypass =
- mFirstBypassAttempt && mUpdateMonitor.shouldListenForFace()
- || mDelayShowingKeyguardStatusBar;
- int newVisibility = newAlpha != 0f && !mDozing && !hideForBypass
- ? View.VISIBLE : View.INVISIBLE;
-
- return new KeyguardStatusBarViewController.ViewState(
- /* shouldAnimate= */ mKeyguardShowing,
- newAlpha,
- newVisibility);
- }
- };
-
@Inject
public NotificationPanelViewController(NotificationPanelView view,
@Main Resources resources,
@@ -726,7 +646,6 @@
StatusBarTouchableRegionManager statusBarTouchableRegionManager,
ConversationNotificationManager conversationNotificationManager,
MediaHierarchyManager mediaHierarchyManager,
- BiometricUnlockController biometricUnlockController,
StatusBarKeyguardViewManager statusBarKeyguardViewManager,
NotificationStackScrollLayoutController notificationStackScrollLayoutController,
KeyguardStatusViewComponent.Factory keyguardStatusViewComponentFactory,
@@ -812,7 +731,6 @@
mDisplayId = displayId;
mPulseExpansionHandler = pulseExpansionHandler;
mDozeParameters = dozeParameters;
- mBiometricUnlockController = biometricUnlockController;
mScrimController = scrimController;
mScrimController.setClipsQsScrim(!mShouldUseSplitNotificationShade);
mUserManager = userManager;
@@ -820,6 +738,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();
@@ -828,21 +748,8 @@
mThemeResId = mView.getContext().getThemeResId();
mKeyguardBypassController = bypassController;
mUpdateMonitor = keyguardUpdateMonitor;
- mFirstBypassAttempt = mKeyguardBypassController.getBypassEnabled();
- KeyguardStateController.Callback
- keyguardMonitorCallback =
- new KeyguardStateController.Callback() {
- @Override
- public void onKeyguardFadingAwayChanged() {
- if (!mKeyguardStateController.isKeyguardFadingAway()) {
- mFirstBypassAttempt = false;
- mDelayShowingKeyguardStatusBar = false;
- }
- }
- };
mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
lockscreenShadeTransitionController.setNotificationPanelController(this);
- mKeyguardStateController.addCallback(keyguardMonitorCallback);
DynamicPrivacyControlListener
dynamicPrivacyControlListener =
new DynamicPrivacyControlListener();
@@ -906,7 +813,7 @@
mKeyguardStatusBarViewController =
mKeyguardStatusBarViewComponentFactory.build(
mKeyguardStatusBar,
- mViewStateProvider)
+ mNotificationPanelViewStateProvider)
.getKeyguardStatusBarViewController();
mKeyguardStatusBarViewController.init();
@@ -940,7 +847,7 @@
mWakeUpCoordinator.addListener(new NotificationWakeUpCoordinator.WakeUpListener() {
@Override
public void onFullyHiddenChanged(boolean isFullyHidden) {
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
}
@Override
@@ -977,8 +884,6 @@
mStatusBarHeaderHeightKeyguard = mResources.getDimensionPixelSize(
R.dimen.status_bar_header_height_keyguard);
mQsPeekHeight = mResources.getDimensionPixelSize(R.dimen.qs_peek_height);
- mNotificationsHeaderCollideDistance = mResources.getDimensionPixelSize(
- R.dimen.header_notifications_collide_distance);
mClockPositionAlgorithm.loadDimens(mResources);
mQsFalsingThreshold = mResources.getDimensionPixelSize(R.dimen.qs_falsing_threshold);
mPositionMinSideMargin = mResources.getDimensionPixelSize(
@@ -997,7 +902,8 @@
R.dimen.pulse_expansion_max_top_overshoot);
mScrimCornerRadius = mResources.getDimensionPixelSize(
R.dimen.notification_scrim_corner_radius);
- mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(mResources);
+ mScreenCornerRadius = (int) ScreenDecorationsUtils.getWindowCornerRadius(
+ mView.getContext());
mLockscreenNotificationQSPadding = mResources.getDimensionPixelSize(
R.dimen.notification_side_paddings);
}
@@ -1903,6 +1809,9 @@
private boolean handleQsTouch(MotionEvent event) {
+ if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(event.getX())) {
+ return false;
+ }
final int action = event.getActionMasked();
if (action == MotionEvent.ACTION_DOWN && getExpandedFraction() == 1f
&& mBarState != KEYGUARD && !mQsExpanded && isQsExpansionEnabled()) {
@@ -1944,8 +1853,12 @@
return false;
}
+ private boolean touchXOutsideOfQs(float touchX) {
+ return touchX < mQsFrame.getX() || touchX > mQsFrame.getX() + mQsFrame.getWidth();
+ }
+
private boolean isInQsArea(float x, float y) {
- if (x < mQsFrame.getX() || x > mQsFrame.getX() + mQsFrame.getWidth()) {
+ if (touchXOutsideOfQs(x)) {
return false;
}
// Let's reject anything at the very bottom around the home handle in gesture nav
@@ -2982,30 +2895,6 @@
return Math.min(0, translation);
}
- /**
- * @return the alpha to be used to fade out the contents on Keyguard (status bar, bottom area)
- * during swiping up
- */
- private float getKeyguardContentsAlpha() {
- float alpha;
- if (mBarState == KEYGUARD) {
-
- // When on Keyguard, we hide the header as soon as we expanded close enough to the
- // header
- alpha =
- getExpandedHeight() / (mKeyguardStatusBar.getHeight()
- + mNotificationsHeaderCollideDistance);
- } else {
-
- // In SHADE_LOCKED, the top card is already really close to the header. Hide it as
- // soon as we start translating the stack.
- alpha = getExpandedHeight() / mKeyguardStatusBar.getHeight();
- }
- alpha = MathUtils.saturate(alpha);
- alpha = (float) Math.pow(alpha, 0.75);
- return alpha;
- }
-
private void updateKeyguardBottomAreaAlpha() {
// There are two possible panel expansion behaviors:
// • User dragging up to unlock: we want to fade out as quick as possible
@@ -3301,31 +3190,6 @@
mPanelAlphaEndAction = r;
}
- private void updateKeyguardStatusBarForHeadsUp() {
- boolean
- showingKeyguardHeadsUp =
- mKeyguardShowing && mHeadsUpAppearanceController.shouldBeVisible();
- if (mShowingKeyguardHeadsUp != showingKeyguardHeadsUp) {
- mShowingKeyguardHeadsUp = showingKeyguardHeadsUp;
- if (mKeyguardShowing) {
- PropertyAnimator.setProperty(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT,
- showingKeyguardHeadsUp ? 1.0f : 0.0f, KEYGUARD_HUN_PROPERTIES,
- true /* animate */);
- } else {
- PropertyAnimator.applyImmediately(mView, KEYGUARD_HEADS_UP_SHOWING_AMOUNT, 0.0f);
- }
- }
- }
-
- private void setKeyguardHeadsUpShowingAmount(float amount) {
- mKeyguardHeadsUpShowingAmount = amount;
- mKeyguardStatusBarViewController.updateViewState();
- }
-
- private float getKeyguardHeadsUpShowingAmount() {
- return mKeyguardHeadsUpShowingAmount;
- }
-
public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
mHeadsUpAnimatingAway = headsUpAnimatingAway;
mNotificationStackScrollLayoutController.setHeadsUpAnimatingAway(headsUpAnimatingAway);
@@ -3628,6 +3492,7 @@
mDozing = dozing;
mNotificationStackScrollLayoutController.setDozing(mDozing, animate, wakeUpTouchLocation);
mKeyguardBottomArea.setDozing(mDozing, animate);
+ mKeyguardStatusBarViewController.setDozing(mDozing);
if (dozing) {
mBottomAreaShadeAlphaAnimator.cancel();
@@ -4026,6 +3891,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) {
@@ -4094,9 +3973,7 @@
@Override
public void flingTopOverscroll(float velocity, boolean open) {
// in split shade mode we want to expand/collapse QS only when touch happens within QS
- if (mShouldUseSplitNotificationShade
- && (mInitialTouchX < mQsFrame.getX()
- || mInitialTouchX > mQsFrame.getX() + mQsFrame.getWidth())) {
+ if (mShouldUseSplitNotificationShade && touchXOutsideOfQs(mInitialTouchX)) {
return;
}
mLastOverscroll = 0f;
@@ -4292,7 +4169,7 @@
updateGestureExclusionRect();
mHeadsUpPinnedMode = inPinnedMode;
updateHeadsUpVisibility();
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
}
@Override
@@ -4451,7 +4328,7 @@
}
}
}
- updateKeyguardStatusBarForHeadsUp();
+ mKeyguardStatusBarViewController.updateForHeadsUp();
if (keyguardShowing) {
updateDozingVisibilities(false /* animate */);
}
@@ -4477,6 +4354,43 @@
}
/**
+ * An interface that provides the current state of the notification panel and related views,
+ * which is needed to calculate {@link KeyguardStatusBarView}'s state in
+ * {@link KeyguardStatusBarViewController}.
+ */
+ public interface NotificationPanelViewStateProvider {
+ /** Returns the expanded height of the panel view. */
+ float getPanelViewExpandedHeight();
+ /** Returns the fraction of QS that's expanded. */
+ float getQsExpansionFraction();
+ /**
+ * Returns true if heads up should be visible.
+ *
+ * TODO(b/138786270): If HeadsUpAppearanceController was injectable, we could inject it into
+ * {@link KeyguardStatusBarViewController} and remove this method.
+ */
+ boolean shouldHeadsUpBeVisible();
+ }
+
+ private final NotificationPanelViewStateProvider mNotificationPanelViewStateProvider =
+ new NotificationPanelViewStateProvider() {
+ @Override
+ public float getPanelViewExpandedHeight() {
+ return getExpandedHeight();
+ }
+
+ @Override
+ public float getQsExpansionFraction() {
+ return computeQsExpansionFraction();
+ }
+
+ @Override
+ public boolean shouldHeadsUpBeVisible() {
+ return mHeadsUpAppearanceController.shouldBeVisible();
+ }
+ };
+
+ /**
* Reconfigures the shade to show the AOD UI (clock, smartspace, etc). This is called by the
* screen off animation controller in order to animate in AOD without "actually" fully switching
* to the KEYGUARD state, which is a heavy transition that causes jank as 10+ files react to the
@@ -4508,7 +4422,6 @@
.addTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.addCallback(mStatusBarStateListener);
mConfigurationController.addCallback(mConfigurationListener);
- mUpdateMonitor.registerCallback(mKeyguardUpdateCallback);
// Theme might have changed between inflating this view and attaching it to the
// window, so
// force a call to onThemeChanged
@@ -4525,7 +4438,6 @@
.removeTagListener(QS.TAG, mFragmentListener);
mStatusBarStateController.removeCallback(mStatusBarStateListener);
mConfigurationController.removeCallback(mConfigurationListener);
- mUpdateMonitor.removeCallback(mKeyguardUpdateCallback);
mFalsingManager.removeTapListener(mFalsingTapListener);
}
}
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/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 87d4543..4213902 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -556,6 +556,8 @@
if (isNaN(expansionFraction)) {
return;
}
+ expansionFraction = Interpolators
+ .getNotificationScrimAlpha(expansionFraction, false /* notification */);
boolean qsBottomVisible = qsPanelBottomY > 0;
if (mQsExpansion != expansionFraction || mQsBottomVisible != qsBottomVisible) {
mQsExpansion = expansionFraction;
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 32b5cb2..59c307c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -1089,6 +1089,11 @@
}
}
}, OverlayPlugin.class, true /* Allow multiple plugins */);
+
+ mStartingSurfaceOptional.ifPresent(startingSurface -> startingSurface.setSysuiProxy(
+ (requestTopUi, componentTag) -> mMainExecutor.execute(() ->
+ mNotificationShadeWindowController.setRequestTopUi(
+ requestTopUi, componentTag))));
}
// ================================================================================
@@ -1824,6 +1829,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/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
index 6b52dca..f8120a8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/UnlockedScreenOffAnimationController.kt
@@ -5,20 +5,23 @@
import android.animation.ValueAnimator
import android.content.Context
import android.content.res.Configuration
+import android.database.ContentObserver
import android.os.Handler
+import android.provider.Settings
+import com.android.systemui.statusbar.StatusBarState
import android.view.View
import com.android.systemui.animation.Interpolators
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.KeyguardViewMediator
import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.statusbar.LightRevealScrim
-import com.android.systemui.statusbar.StatusBarState
import com.android.systemui.statusbar.StatusBarStateControllerImpl
import com.android.systemui.statusbar.notification.AnimatableProperty
import com.android.systemui.statusbar.notification.PropertyAnimator
import com.android.systemui.statusbar.notification.stack.AnimationProperties
import com.android.systemui.statusbar.notification.stack.StackStateAnimator
import com.android.systemui.statusbar.policy.KeyguardStateController
+import com.android.systemui.util.settings.GlobalSettings
import javax.inject.Inject
/**
@@ -46,13 +49,16 @@
private val statusBarStateControllerImpl: StatusBarStateControllerImpl,
private val keyguardViewMediatorLazy: dagger.Lazy<KeyguardViewMediator>,
private val keyguardStateController: KeyguardStateController,
- private val dozeParameters: dagger.Lazy<DozeParameters>
+ private val dozeParameters: dagger.Lazy<DozeParameters>,
+ private val globalSettings: GlobalSettings
) : WakefulnessLifecycle.Observer {
private val handler = Handler()
private lateinit var statusBar: StatusBar
private lateinit var lightRevealScrim: LightRevealScrim
+ private var animatorDurationScale = 1f
+ private var shouldAnimateInKeyguard = false
private var lightRevealAnimationPlaying = false
private var aodUiAnimationPlaying = false
@@ -79,6 +85,12 @@
})
}
+ val animatorDurationScaleObserver = object : ContentObserver(null) {
+ override fun onChange(selfChange: Boolean) {
+ updateAnimatorDurationScale()
+ }
+ }
+
fun initialize(
statusBar: StatusBar,
lightRevealScrim: LightRevealScrim
@@ -86,14 +98,25 @@
this.lightRevealScrim = lightRevealScrim
this.statusBar = statusBar
+ updateAnimatorDurationScale()
+ globalSettings.registerContentObserver(
+ Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE),
+ /* notify for descendants */ false,
+ animatorDurationScaleObserver)
wakefulnessLifecycle.addObserver(this)
}
+ fun updateAnimatorDurationScale() {
+ animatorDurationScale =
+ globalSettings.getFloat(Settings.Global.ANIMATOR_DURATION_SCALE, 1f)
+ }
+
/**
* Animates in the provided keyguard view, ending in the same position that it will be in on
* AOD.
*/
fun animateInKeyguard(keyguardView: View, after: Runnable) {
+ shouldAnimateInKeyguard = false
keyguardView.alpha = 0f
keyguardView.visibility = View.VISIBLE
@@ -138,6 +161,7 @@
// Waking up, so reset this flag.
decidedToAnimateGoingToSleep = null
+ shouldAnimateInKeyguard = false
lightRevealAnimator.cancel()
handler.removeCallbacksAndMessages(null)
}
@@ -146,7 +170,6 @@
// Set this to false in onFinishedWakingUp rather than onStartedWakingUp so that other
// observers (such as StatusBar) can ask us whether we were playing the screen off animation
// and reset accordingly.
- lightRevealAnimationPlaying = false
aodUiAnimationPlaying = false
// If we can't control the screen off animation, we shouldn't mess with the StatusBar's
@@ -167,15 +190,15 @@
if (dozeParameters.get().shouldControlUnlockedScreenOff()) {
decidedToAnimateGoingToSleep = true
+ shouldAnimateInKeyguard = true
lightRevealAnimationPlaying = true
lightRevealAnimator.start()
-
handler.postDelayed({
aodUiAnimationPlaying = true
// Show AOD. That'll cause the KeyguardVisibilityHelper to call #animateInKeyguard.
statusBar.notificationPanelViewController.showAodUi()
- }, ANIMATE_IN_KEYGUARD_DELAY)
+ }, (ANIMATE_IN_KEYGUARD_DELAY * animatorDurationScale).toLong())
} else {
decidedToAnimateGoingToSleep = false
}
@@ -228,6 +251,10 @@
return lightRevealAnimationPlaying || aodUiAnimationPlaying
}
+ fun shouldAnimateInKeyguard(): Boolean {
+ return shouldAnimateInKeyguard
+ }
+
/**
* Whether the light reveal animation is playing. The second part of the screen off animation,
* where AOD animates in, might still be playing if this returns false.
@@ -235,4 +262,4 @@
fun isScreenOffLightRevealAnimationPlaying(): Boolean {
return lightRevealAnimationPlaying
}
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
index 20b66f0..cd8894c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardUserSwitcherListView.java
@@ -103,7 +103,7 @@
}
}
- if (animate) {
+ if (animate && userItemViews.length > 1) {
// AnimationUtils will immediately hide/show the first item in the array. Since the
// first view is the current user, we want to manage its visibility separately.
// Set first item to null so AnimationUtils ignores it.
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index c3f8853..156def5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -71,6 +71,7 @@
import com.android.systemui.dagger.qualifiers.Main;
import com.android.systemui.demomode.DemoMode;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.qs.tiles.dialog.InternetDialogFactory;
import com.android.systemui.qs.tiles.dialog.InternetDialogUtil;
@@ -129,6 +130,7 @@
private Config mConfig;
private final CarrierConfigTracker mCarrierConfigTracker;
private final FeatureFlags mFeatureFlags;
+ private final DumpManager mDumpManager;
private TelephonyCallback.ActiveDataSubscriptionIdListener mPhoneStateListener;
private int mActiveMobileDataSubscription = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
@@ -225,7 +227,8 @@
CarrierConfigTracker carrierConfigTracker,
FeatureFlags featureFlags,
@Main Handler handler,
- InternetDialogFactory internetDialogFactory) {
+ InternetDialogFactory internetDialogFactory,
+ DumpManager dumpManager) {
this(context, connectivityManager,
telephonyManager,
telephonyListenerManager,
@@ -243,7 +246,8 @@
broadcastDispatcher,
demoModeController,
carrierConfigTracker,
- featureFlags);
+ featureFlags,
+ dumpManager);
mReceiverHandler.post(mRegisterListeners);
mMainHandler = handler;
mInternetDialogFactory = internetDialogFactory;
@@ -265,7 +269,8 @@
BroadcastDispatcher broadcastDispatcher,
DemoModeController demoModeController,
CarrierConfigTracker carrierConfigTracker,
- FeatureFlags featureFlags
+ FeatureFlags featureFlags,
+ DumpManager dumpManager
) {
mContext = context;
mTelephonyListenerManager = telephonyListenerManager;
@@ -284,6 +289,7 @@
mDemoModeController = demoModeController;
mCarrierConfigTracker = carrierConfigTracker;
mFeatureFlags = featureFlags;
+ mDumpManager = dumpManager;
// telephony
mPhone = telephonyManager;
@@ -434,6 +440,8 @@
mDemoModeController.addCallback(this);
mProviderModelBehavior = mFeatureFlags.isCombinedStatusBarSignalIconsEnabled();
mProviderModelSetting = mFeatureFlags.isProviderModelSettingEnabled();
+
+ mDumpManager.registerDumpable(TAG, this);
}
private final Runnable mClearForceValidated = () -> {
@@ -793,8 +801,8 @@
mReceiverHandler.post(this::handleConfigurationChanged);
break;
case Settings.Panel.ACTION_INTERNET_CONNECTIVITY:
- boolean canConfigMobileData = mAccessPoints.canConfigMobileData();
- mMainHandler.post(() -> mInternetDialogFactory.create(true, canConfigMobileData));
+ mMainHandler.post(() -> mInternetDialogFactory.create(true,
+ mAccessPoints.canConfigMobileData(), mAccessPoints.canConfigWifi()));
break;
default:
int subId = intent.getIntExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
index c3b4fbe..fe0b970 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayApplier.java
@@ -132,14 +132,18 @@
/* Target package for each overlay category. */
private final Map<String, String> mCategoryToTargetPackage = new ArrayMap<>();
private final OverlayManager mOverlayManager;
- private final Executor mExecutor;
+ private final Executor mBgExecutor;
+ private final Executor mMainExecutor;
private final String mLauncherPackage;
private final String mThemePickerPackage;
- public ThemeOverlayApplier(OverlayManager overlayManager, Executor executor,
+ public ThemeOverlayApplier(OverlayManager overlayManager,
+ Executor bgExecutor,
+ Executor mainExecutor,
String launcherPackage, String themePickerPackage, DumpManager dumpManager) {
mOverlayManager = overlayManager;
- mExecutor = executor;
+ mBgExecutor = bgExecutor;
+ mMainExecutor = mainExecutor;
mLauncherPackage = launcherPackage;
mThemePickerPackage = themePickerPackage;
mTargetPackageToCategories.put(ANDROID_PACKAGE, Sets.newHashSet(
@@ -170,12 +174,13 @@
* Apply the set of overlay packages to the set of {@code UserHandle}s provided. Overlays that
* affect sysui will also be applied to the system user.
*/
- void applyCurrentUserOverlays(
+ public void applyCurrentUserOverlays(
Map<String, OverlayIdentifier> categoryToPackage,
FabricatedOverlay[] pendingCreation,
int currentUser,
- Set<UserHandle> managedProfiles) {
- mExecutor.execute(() -> {
+ Set<UserHandle> managedProfiles,
+ Runnable onOverlaysApplied) {
+ mBgExecutor.execute(() -> {
// Disable all overlays that have not been specified in the user setting.
final Set<String> overlayCategoriesToDisable = new HashSet<>(THEME_CATEGORIES);
@@ -221,6 +226,7 @@
try {
mOverlayManager.commit(transaction.build());
+ mMainExecutor.execute(onOverlaysApplied);
} catch (SecurityException | IllegalStateException e) {
Log.e(TAG, "setEnabled failed", e);
}
diff --git a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
index a53d528..0130cb2 100644
--- a/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/theme/ThemeOverlayController.java
@@ -521,16 +521,16 @@
.map(key -> key + " -> " + categoryToPackage.get(key)).collect(
Collectors.joining(", ")));
}
+ Runnable overlaysAppliedRunnable = () -> onOverlaysApplied();
if (mNeedsOverlayCreation) {
mNeedsOverlayCreation = false;
mThemeManager.applyCurrentUserOverlays(categoryToPackage, new FabricatedOverlay[] {
mSecondaryOverlay, mNeutralOverlay
- }, currentUser, managedProfiles);
+ }, currentUser, managedProfiles, overlaysAppliedRunnable);
} else {
mThemeManager.applyCurrentUserOverlays(categoryToPackage, null, currentUser,
- managedProfiles);
+ managedProfiles, overlaysAppliedRunnable);
}
- onOverlaysApplied();
}
protected void onOverlaysApplied() {
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
index 9283403..3c3cc64 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/UnfoldLightRevealOverlayAnimation.kt
@@ -58,6 +58,10 @@
}
override fun onTransitionStarted() {
+ // When unfolding the view is added earlier, add view for folding case
+ if (scrimView == null) {
+ addOverlayView()
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
index c178b29..f420a85 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShellBaseModule.java
@@ -377,11 +377,13 @@
SyncTransactionQueue syncQueue, Context context,
RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
@ShellMainThread ShellExecutor mainExecutor,
- DisplayImeController displayImeController, Transitions transitions,
+ DisplayImeController displayImeController,
+ DisplayInsetsController displayInsetsController, Transitions transitions,
TransactionPool transactionPool) {
if (ActivityTaskManager.supportsSplitScreenMultiWindow(context)) {
return Optional.of(new SplitScreenController(shellTaskOrganizer, syncQueue, context,
- rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController, transitions,
+ rootTaskDisplayAreaOrganizer, mainExecutor, displayImeController,
+ displayInsetsController, transitions,
transactionPool));
} else {
return Optional.empty();
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
index 0276323..2efd369 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerTest.java
@@ -165,7 +165,8 @@
mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
/* leftAligned= */false, /* animate= */false);
- verify(mSecurityViewFlipper).setTranslationX(SCREEN_WIDTH / 2.0f);
+ verify(mSecurityViewFlipper).setTranslationX(
+ mKeyguardSecurityContainer.getWidth() - mSecurityViewFlipper.getWidth());
mKeyguardSecurityContainer.setOneHandedModeLeftAligned(
/* leftAligned= */true, /* animate= */false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index ed5cbe2..4c7f959e 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -17,6 +17,7 @@
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.DisplayCutout.BOUNDS_POSITION_BOTTOM;
import static android.view.DisplayCutout.BOUNDS_POSITION_LEFT;
+import static android.view.DisplayCutout.BOUNDS_POSITION_LENGTH;
import static android.view.DisplayCutout.BOUNDS_POSITION_RIGHT;
import static android.view.DisplayCutout.BOUNDS_POSITION_TOP;
import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_IS_ROUNDED_CORNERS_OVERLAY;
@@ -43,6 +44,7 @@
import static org.mockito.Mockito.when;
import android.content.res.Configuration;
+import android.content.res.TypedArray;
import android.graphics.Insets;
import android.graphics.Point;
import android.graphics.Rect;
@@ -52,6 +54,7 @@
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
import android.testing.TestableLooper.RunWithLooper;
+import android.util.RotationUtils;
import android.view.Display;
import android.view.DisplayCutout;
import android.view.View;
@@ -60,7 +63,6 @@
import androidx.test.filters.SmallTest;
-import com.android.systemui.R.dimen;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.settings.UserTracker;
import com.android.systemui.statusbar.events.PrivacyDotViewController;
@@ -100,6 +102,8 @@
private UserTracker mUserTracker;
@Mock
private PrivacyDotViewController mDotViewController;
+ @Mock
+ private TypedArray mMockTypedArray;
@Before
public void setup() {
@@ -121,6 +125,7 @@
.getDisplay(DEFAULT_DISPLAY);
when(mDisplayManager.getDisplay(anyInt())).thenReturn(display);
mContext.addMockSystemService(DisplayManager.class, mDisplayManager);
+ when(mMockTypedArray.length()).thenReturn(0);
mScreenDecorations = spy(new ScreenDecorations(mContext, mExecutor, mSecureSettings,
mBroadcastDispatcher, mTunerService, mUserTracker, mDotViewController,
@@ -148,18 +153,9 @@
@Test
public void testNoRounding_NoCutout() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
@@ -173,14 +169,9 @@
@Test
public void testRounding_NoCutout() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 20 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
@@ -203,19 +194,10 @@
@Test
public void testRoundingRadius_NoCutout() {
- final int testRadius = 1;
final Point testRadiusPoint = new Point(1, 1);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, testRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, testRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, testRadius);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
-
+ setupResources(1 /* radius */, 1 /* radiusTop */, 1 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
@@ -230,16 +212,8 @@
public void testRoundingTopBottomRadius_OnTopBottomOverlay() {
final int testTopRadius = 1;
final int testBottomRadius = 5;
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, testTopRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, testTopRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, testBottomRadius);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */,
+ false /* multipleRadius */, false /* fillCutout */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
@@ -267,58 +241,49 @@
public void testRoundingTopBottomRadius_OnLeftRightOverlay() {
final int testTopRadius = 1;
final int testBottomRadius = 5;
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, testTopRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, testTopRadius);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, testBottomRadius);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(testTopRadius, testTopRadius, testBottomRadius, 0 /* roundedPadding */,
+ false /* multipleRadius */, false /* fillCutout */);
// left cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- new Rect(0, 200, 1, 210),
- ZERO_RECT,
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
+ final Point topRadius = new Point(testTopRadius, testTopRadius);
+ final Point bottomRadius = new Point(testBottomRadius, testBottomRadius);
View leftRoundedCorner =
mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].findViewById(R.id.left);
+ boolean isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.left);
+ verify(mScreenDecorations, atLeastOnce())
+ .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius);
+
View rightRoundedCorner =
mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT].findViewById(R.id.right);
+ isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_LEFT, R.id.right);
verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius));
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+ .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius);
+
leftRoundedCorner =
mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].findViewById(R.id.left);
+ isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.left);
+ verify(mScreenDecorations, atLeastOnce())
+ .setSize(leftRoundedCorner, isTop ? topRadius : bottomRadius);
+
rightRoundedCorner =
mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT].findViewById(R.id.right);
+ isTop = mScreenDecorations.isTopRoundedCorner(BOUNDS_POSITION_RIGHT, R.id.right);
verify(mScreenDecorations, atLeastOnce())
- .setSize(leftRoundedCorner, new Point(testTopRadius, testTopRadius));
- verify(mScreenDecorations, atLeastOnce())
- .setSize(rightRoundedCorner, new Point(testBottomRadius, testBottomRadius));
+ .setSize(rightRoundedCorner, isTop ? topRadius : bottomRadius);
}
@Test
public void testRoundingMultipleRadius_NoCutout() {
final VectorDrawable d = (VectorDrawable) mContext.getDrawable(R.drawable.rounded);
final Point multipleRadiusSize = new Point(d.getIntrinsicWidth(), d.getIntrinsicHeight());
-
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 9999);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 9999);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, true);
+ setupResources(9999 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 9999 /* roundedPadding */, true /* multipleRadius */,
+ false /* fillCutout */);
// no cutout
doReturn(null).when(mScreenDecorations).getCutout();
@@ -345,27 +310,14 @@
@Test
public void testNoRounding_CutoutShortEdge() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// top cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- ZERO_RECT,
- new Rect(9, 0, 10, 1),
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Top window is created for top cutout.
@@ -381,27 +333,14 @@
@Test
public void testNoRounding_CutoutLongEdge() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// left cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- new Rect(0, 200, 1, 210),
- ZERO_RECT,
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
// Left window is created for left cutout.
@@ -417,29 +356,20 @@
@Test
public void testRounding_CutoutShortEdge() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 20 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// top cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- ZERO_RECT,
- new Rect(9, 0, 10, 1),
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- // Top window is created for rouned corner and top cutout.
+ // Top window is created for rounded corner and top cutout.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any());
- // Bottom window is created for rouned corner.
+ // Bottom window is created for rounded corner.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any());
// Left window should be null.
@@ -450,29 +380,20 @@
@Test
public void testRounding_CutoutLongEdge() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 20 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// left cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- new Rect(0, 200, 1, 210),
- ZERO_RECT,
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- // Left window is created for rouned corner and left cutout.
+ // Left window is created for rounded corner and left cutout.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]), any());
- // Right window is created for rouned corner.
+ // Right window is created for rounded corner.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_RIGHT]), any());
// Top window should be null.
@@ -483,29 +404,20 @@
@Test
public void testRounding_CutoutShortAndLongEdge() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 20 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// top and left cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- new Rect(0, 200, 1, 210),
- new Rect(9, 0, 10, 1),
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {new Rect(0, 50, 1, 60), new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
- // Top window is created for rouned corner and top cutout.
+ // Top window is created for rounded corner and top cutout.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_TOP]), any());
- // Bottom window is created for rouned corner.
+ // Bottom window is created for rounded corner.
verify(mWindowManager, times(1))
.addView(eq(mScreenDecorations.mOverlays[BOUNDS_POSITION_BOTTOM]), any());
// Left window is created for left cutout.
@@ -517,27 +429,14 @@
@Test
public void testNoRounding_SwitchFrom_ShortEdgeCutout_To_LongCutout() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ true /* fillCutout */);
// Set to short edge cutout(top).
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- ZERO_RECT,
- new Rect(9, 0, 10, 1),
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
verify(mWindowManager, times(1))
@@ -547,14 +446,9 @@
assertNull(mScreenDecorations.mOverlays[BOUNDS_POSITION_LEFT]);
// Switch to long edge cutout(left).
- // left cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- new Rect(0, 200, 1, 210),
- ZERO_RECT,
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] newBounds = {new Rect(0, 50, 1, 60), null, null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(1, 0, 0, 0), newBounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.onConfigurationChanged(new Configuration());
verify(mWindowManager, times(1))
@@ -566,33 +460,21 @@
@Test
public void testDelayedCutout() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(dimen.rounded_corner_content_padding, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
// top cutout
- doReturn(new DisplayCutout(
- Insets.of(0, 10, 0, 0),
- ZERO_RECT,
- new Rect(9, 0, 10, 1),
- ZERO_RECT,
- ZERO_RECT,
- Insets.NONE)).when(mScreenDecorations).getCutout();
+ final Rect[] bounds = {null, new Rect(9, 0, 10, 1), null, null};
+ doReturn(getDisplayCutoutForRotation(Insets.of(0, 1, 0, 0), bounds))
+ .when(mScreenDecorations).getCutout();
mScreenDecorations.start();
assertNull(mScreenDecorations.mOverlays);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, true);
+ when(mContext.getResources().getBoolean(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout))
+ .thenReturn(true);
mScreenDecorations.onConfigurationChanged(new Configuration());
// Only top windows should be added.
@@ -612,34 +494,24 @@
@Test
public void testUpdateRoundedCorners() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(20 /* radius */, 0 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
mScreenDecorations.start();
assertEquals(mScreenDecorations.mRoundedDefault, new Point(20, 20));
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 5);
+ when(mContext.getResources().getDimensionPixelSize(
+ com.android.internal.R.dimen.rounded_corner_radius)).thenReturn(5);
mScreenDecorations.onConfigurationChanged(null);
assertEquals(mScreenDecorations.mRoundedDefault, new Point(5, 5));
}
@Test
public void testOnlyRoundedCornerRadiusTop() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 10);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 0);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 10 /* radiusTop */, 0 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
mScreenDecorations.start();
assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
@@ -649,16 +521,9 @@
@Test
public void testOnlyRoundedCornerRadiusBottom() {
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_top, 0);
- mContext.getOrCreateTestableResources().addOverride(
- com.android.internal.R.dimen.rounded_corner_radius_bottom, 20);
- mContext.getOrCreateTestableResources()
- .addOverride(R.bool.config_roundedCornerMultipleRadius, false);
+ setupResources(0 /* radius */, 0 /* radiusTop */, 20 /* radiusBottom */,
+ 0 /* roundedPadding */, false /* multipleRadius */,
+ false /* fillCutout */);
mScreenDecorations.start();
assertEquals(new Point(0, 0), mScreenDecorations.mRoundedDefault);
@@ -721,4 +586,59 @@
verify(mTunerService, times(1)).removeTunable(any());
assertThat(mScreenDecorations.mIsRegistered, is(false));
}
+
+ private void setupResources(int radius, int radiusTop, int radiusBottom, int roundedPadding,
+ boolean multipleRadius, boolean fillCutout) {
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_displayUniqueIdArray,
+ new String[]{});
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_roundedCornerRadiusArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_roundedCornerTopRadiusArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.array.config_roundedCornerBottomRadiusArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_roundedCornerDrawableArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_roundedCornerTopDrawableArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_roundedCornerBottomDrawableArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.array.config_roundedCornerMultipleRadiusArray,
+ mMockTypedArray);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius, radius);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_top, radiusTop);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.dimen.rounded_corner_radius_bottom, radiusBottom);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.dimen.rounded_corner_content_padding, roundedPadding);
+ mContext.getOrCreateTestableResources().addOverride(
+ R.bool.config_roundedCornerMultipleRadius, multipleRadius);
+ mContext.getOrCreateTestableResources().addOverride(
+ com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, fillCutout);
+ }
+
+ private DisplayCutout getDisplayCutoutForRotation(Insets safeInsets, Rect[] cutoutBounds) {
+ final int rotation = mContext.getDisplay().getRotation();
+ final Insets insets = RotationUtils.rotateInsets(safeInsets, rotation);
+ final Rect[] sorted = new Rect[BOUNDS_POSITION_LENGTH];
+ for (int i = 0; i < BOUNDS_POSITION_LENGTH; i++) {
+ final int rotatedPos = ScreenDecorations.getBoundPositionFromRotation(i, rotation);
+ if (cutoutBounds[i] != null) {
+ RotationUtils.rotateBounds(cutoutBounds[i], new Rect(0, 0, 100, 200), rotation);
+ }
+ sorted[rotatedPos] = cutoutBounds[i];
+ }
+ return new DisplayCutout(insets, sorted[BOUNDS_POSITION_LEFT], sorted[BOUNDS_POSITION_TOP],
+ sorted[BOUNDS_POSITION_RIGHT], sorted[BOUNDS_POSITION_BOTTOM]);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 7794136..3291a7c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -171,6 +171,29 @@
}
@Test
+ public void enableWindowMagnification_LargeScreen_windowSizeIsConstrained() {
+ final int screenSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.magnification_max_frame_size) * 10;
+ mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+ //We need to initialize new one because the window size is determined when initialization.
+ final WindowMagnificationController controller = new WindowMagnificationController(mContext,
+ mHandler, mSfVsyncFrameProvider,
+ mMirrorWindowControl, mTransaction, mWindowMagnifierCallback, mSysUiState);
+
+ mInstrumentation.runOnMainSync(() -> {
+ controller.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+
+ final int halfScreenSize = screenSize / 2;
+ WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
+ // The frame size should be the half of smaller value of window height/width unless it
+ //exceed the max frame size.
+ assertTrue(params.width < halfScreenSize);
+ assertTrue(params.height < halfScreenSize);
+ }
+
+ @Test
public void deleteWindowMagnification_destroyControl() {
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -252,7 +275,9 @@
@Test
public void onOrientationChanged_enabled_updateDisplayRotationAndCenterStayAtSamePosition() {
final Display display = Mockito.spy(mContext.getDisplay());
- when(display.getRotation()).thenReturn(Surface.ROTATION_90);
+ final int currentRotation = display.getRotation();
+ final int newRotation = (currentRotation + 1) % 4;
+ when(display.getRotation()).thenReturn(newRotation);
when(mContext.getDisplay()).thenReturn(display);
mInstrumentation.runOnMainSync(() -> {
mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
@@ -261,7 +286,7 @@
final PointF expectedCenter = new PointF(mWindowMagnificationController.getCenterY(),
mWindowMagnificationController.getCenterX());
final Rect windowBounds = new Rect(mWindowManager.getCurrentWindowMetrics().getBounds());
- // Rotate the window 90 degrees.
+ // Rotate the window clockwise 90 degree.
windowBounds.set(windowBounds.top, windowBounds.left, windowBounds.bottom,
windowBounds.right);
mWindowManager.setWindowBounds(windowBounds);
@@ -270,7 +295,7 @@
mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_ORIENTATION);
});
- assertEquals(Surface.ROTATION_90, mWindowMagnificationController.mRotation);
+ assertEquals(newRotation, mWindowMagnificationController.mRotation);
final PointF actualCenter = new PointF(mWindowMagnificationController.getCenterX(),
mWindowMagnificationController.getCenterY());
assertEquals(expectedCenter, actualCenter);
@@ -316,6 +341,27 @@
mWindowMagnificationController.getCenterY() / testWindowBounds.height(),
0);
}
+ @Test
+ public void screenSizeIsChangedToLarge_enabled_windowSizeIsConstrained() {
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.enableWindowMagnification(Float.NaN, Float.NaN,
+ Float.NaN);
+ });
+ final int screenSize = mContext.getResources().getDimensionPixelSize(
+ R.dimen.magnification_max_frame_size) * 10;
+ mWindowManager.setWindowBounds(new Rect(0, 0, screenSize, screenSize));
+
+ mInstrumentation.runOnMainSync(() -> {
+ mWindowMagnificationController.onConfigurationChanged(ActivityInfo.CONFIG_SCREEN_SIZE);
+ });
+
+ final int halfScreenSize = screenSize / 2;
+ WindowManager.LayoutParams params = mWindowManager.getLayoutParamsFromAttachedView();
+ // The frame size should be the half of smaller value of window height/width unless it
+ //exceed the max frame size.
+ assertTrue(params.width < halfScreenSize);
+ assertTrue(params.height < halfScreenSize);
+ }
@Test
public void onDensityChanged_enabled_updateDimensionsAndResetWindowMagnification() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
index f91c029..b6d1e42 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricFaceToFingerprintViewTest.java
@@ -47,6 +47,7 @@
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -165,6 +166,7 @@
}
@Test
+ @Ignore("flaky, b/189031816")
public void testModeUpdated_onSoftError_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onAuthenticationFailed(TYPE_FACE, "no face");
@@ -181,6 +183,7 @@
}
@Test
+ @Ignore("flaky, b/189031816")
public void testModeUpdated_onHardError_whenSwitchToFingerprint() {
mFaceToFpView.onDialogAnimatedIn();
mFaceToFpView.onError(TYPE_FACE, "oh no!");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index bd518ff..f8e38e4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -45,6 +45,7 @@
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
+import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
@@ -199,6 +200,7 @@
}
@Test
+ @Ignore("flaky, b/189031816")
public void testError_sendsActionError() {
initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
final String testError = "testError";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index 39d5314..8dd5d6c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -565,8 +565,9 @@
credentialAllowed,
true /* requireConfirmation */,
0 /* userId */,
- "testPackage",
0 /* operationId */,
+ "testPackage",
+ 1 /* requestId */,
BIOMETRIC_MULTI_SENSOR_FACE_THEN_FINGERPRINT);
}
@@ -612,7 +613,7 @@
@Override
protected AuthDialog buildDialog(PromptInfo promptInfo,
boolean requireConfirmation, int userId, int[] sensorIds, boolean credentialAllowed,
- String opPackageName, boolean skipIntro, long operationId,
+ String opPackageName, boolean skipIntro, long operationId, long requestId,
@BiometricManager.BiometricMultiSensorMode int multiSensorConfig) {
mLastBiometricPromptInfo = promptInfo;
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index ae009bc..f5c6f98 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -16,6 +16,8 @@
package com.android.systemui.biometrics;
+import static android.media.AudioAttributes.USAGE_ASSISTANCE_ACCESSIBILITY;
+
import static junit.framework.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.any;
@@ -563,5 +565,10 @@
eq(mUdfpsController.EFFECT_CLICK),
eq("udfps-onStart"),
eq(UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES));
+
+ // THEN make sure vibration attributes has so that it always will play the haptic,
+ // even in battery saver mode
+ assertEquals(USAGE_ASSISTANCE_ACCESSIBILITY,
+ UdfpsController.VIBRATION_SONIFICATION_ATTRIBUTES.getUsage());
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
index decec63..2c08fe6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsKeyguardViewControllerTest.java
@@ -369,6 +369,25 @@
verify(mView).setUnpausedAlpha(0);
}
+ @Test
+ public void testShowUdfpsBouncer() {
+ // GIVEN view is attached and status bar expansion is 0
+ mController.onViewAttached();
+ captureExpansionListeners();
+ captureKeyguardStateControllerCallback();
+ captureAltAuthInterceptor();
+ updateStatusBarExpansion(0, true);
+ reset(mView);
+ when(mView.getContext()).thenReturn(mResourceContext);
+ when(mResourceContext.getString(anyInt())).thenReturn("test string");
+
+ // WHEN status bar expansion is 0 but udfps bouncer is requested
+ mAltAuthInterceptor.showAlternateAuthBouncer();
+
+ // THEN alpha is 0
+ verify(mView).setUnpausedAlpha(255);
+ }
+
private void sendStatusBarStateChanged(int statusBarState) {
mStatusBarStateListener.onStateChanged(statusBarState);
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
index b129fdd..42629f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaControlPanelTest.kt
@@ -37,6 +37,7 @@
import androidx.constraintlayout.widget.ConstraintSet
import androidx.lifecycle.LiveData
import androidx.test.filters.SmallTest
+import com.android.systemui.R
import com.android.systemui.SysuiTestCase
import com.android.systemui.media.dialog.MediaOutputDialogFactory
import com.android.systemui.plugins.ActivityStarter
@@ -101,7 +102,6 @@
private lateinit var seamless: ViewGroup
private lateinit var seamlessIcon: ImageView
private lateinit var seamlessText: TextView
- private lateinit var seamlessFallback: ImageView
private lateinit var seekBar: SeekBar
private lateinit var elapsedTimeView: TextView
private lateinit var totalTimeView: TextView
@@ -154,8 +154,6 @@
whenever(holder.seamlessIcon).thenReturn(seamlessIcon)
seamlessText = TextView(context)
whenever(holder.seamlessText).thenReturn(seamlessText)
- seamlessFallback = ImageView(context)
- whenever(holder.seamlessFallback).thenReturn(seamlessFallback)
seekBar = SeekBar(context)
whenever(holder.seekBar).thenReturn(seekBar)
elapsedTimeView = TextView(context)
@@ -239,21 +237,19 @@
@Test
fun bindDisabledDevice() {
seamless.id = 1
- seamlessFallback.id = 2
+ val fallbackString = context.getString(R.string.media_seamless_other_device)
player.attachPlayer(holder)
val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
emptyList(), PACKAGE, session.getSessionToken(), null, disabledDevice, true, null)
player.bindPlayer(state, PACKAGE)
- verify(expandedSet).setVisibility(seamless.id, View.GONE)
- verify(expandedSet).setVisibility(seamlessFallback.id, View.VISIBLE)
- verify(collapsedSet).setVisibility(seamless.id, View.GONE)
- verify(collapsedSet).setVisibility(seamlessFallback.id, View.VISIBLE)
+ assertThat(seamless.isEnabled()).isFalse()
+ assertThat(seamlessText.getText()).isEqualTo(fallbackString)
+ assertThat(seamless.contentDescription).isEqualTo(fallbackString)
}
@Test
fun bindNullDevice() {
- val fallbackString = context.getResources().getString(
- com.android.internal.R.string.ext_media_seamless_action)
+ val fallbackString = context.getResources().getString(R.string.media_seamless_other_device)
player.attachPlayer(holder)
val state = MediaData(USER_ID, true, BG_COLOR, APP, null, ARTIST, TITLE, null, emptyList(),
emptyList(), PACKAGE, session.getSessionToken(), null, null, true, null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
index 63ebe92..23e5168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tileimpl/QSIconViewImplTest.java
@@ -18,6 +18,7 @@
import static org.junit.Assert.assertFalse;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.argThat;
+import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
@@ -74,6 +75,24 @@
}
@Test
+ public void testMutateIconDrawable() {
+ SlashImageView iv = mock(SlashImageView.class);
+ Drawable originalDrawable = mock(Drawable.class);
+ Drawable otherDrawable = mock(Drawable.class);
+ State s = new State();
+ s.icon = mock(Icon.class);
+ when(s.icon.getInvisibleDrawable(eq(mContext))).thenReturn(originalDrawable);
+ when(s.icon.getDrawable(eq(mContext))).thenReturn(originalDrawable);
+ when(iv.isShown()).thenReturn(true);
+ when(originalDrawable.getConstantState()).thenReturn(fakeConstantState(otherDrawable));
+
+
+ mIconView.updateIcon(iv, s, /* allowAnimations= */true);
+
+ verify(iv).setState(any(), eq(otherDrawable));
+ }
+
+ @Test
public void testNoFirstFade() {
ImageView iv = mock(ImageView.class);
State s = new State();
@@ -104,4 +123,18 @@
public void testIconNotSet_toString() {
assertFalse(mIconView.toString().contains("lastIcon"));
}
+
+ private static Drawable.ConstantState fakeConstantState(Drawable otherDrawable) {
+ return new Drawable.ConstantState() {
+ @Override
+ public Drawable newDrawable() {
+ return otherDrawable;
+ }
+
+ @Override
+ public int getChangingConfigurations() {
+ return 1;
+ }
+ };
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
index 2b9082d..77946cf 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetAdapterTest.java
@@ -2,28 +2,37 @@
import static com.google.common.truth.Truth.assertThat;
+import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
+import android.graphics.drawable.Drawable;
import android.testing.AndroidTestingRunner;
+import android.testing.TestableResources;
import android.view.View;
import android.widget.LinearLayout;
import androidx.test.filters.SmallTest;
import com.android.settingslib.wifi.WifiUtils;
+import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.wifitrackerlib.WifiEntry;
import org.junit.Before;
+import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
-import org.mockito.MockitoAnnotations;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
import java.util.Arrays;
+import java.util.List;
@SmallTest
@RunWith(AndroidTestingRunner.class)
@@ -31,22 +40,34 @@
private static final String WIFI_TITLE = "Wi-Fi Title";
private static final String WIFI_SUMMARY = "Wi-Fi Summary";
+ private static final int GEAR_ICON_RES_ID = R.drawable.ic_settings_24dp;
+ private static final int LOCK_ICON_RES_ID = R.drawable.ic_friction_lock_closed;
+
+ @Rule
+ public MockitoRule mRule = MockitoJUnit.rule();
@Mock
private WifiEntry mInternetWifiEntry;
@Mock
+ private List<WifiEntry> mWifiEntries;
+ @Mock
private WifiEntry mWifiEntry;
@Mock
private InternetDialogController mInternetDialogController;
@Mock
private WifiUtils.InternetIconInjector mWifiIconInjector;
+ @Mock
+ private Drawable mGearIcon;
+ @Mock
+ private Drawable mLockIcon;
+ private TestableResources mTestableResources;
private InternetAdapter mInternetAdapter;
private InternetAdapter.InternetViewHolder mViewHolder;
@Before
public void setUp() {
- MockitoAnnotations.initMocks(this);
+ mTestableResources = mContext.getOrCreateTestableResources();
when(mInternetWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
@@ -56,43 +77,17 @@
mInternetAdapter = new InternetAdapter(mInternetDialogController);
mViewHolder = mInternetAdapter.onCreateViewHolder(new LinearLayout(mContext), 0);
- when(mInternetDialogController.getInternetWifiEntry()).thenReturn(mInternetWifiEntry);
- when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
+ mInternetAdapter.setWifiEntries(Arrays.asList(mWifiEntry), 1 /* wifiEntriesCount */);
mViewHolder.mWifiIconInjector = mWifiIconInjector;
}
@Test
- public void getItemCount_withApmOnWifiOnNoInternetWifi_returnFour() {
- // The preconditions WiFi ON is already in setUp()
- when(mInternetDialogController.getInternetWifiEntry()).thenReturn(null);
- when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
+ public void getItemCount_returnWifiEntriesCount() {
+ for (int i = 0; i < InternetDialogController.MAX_WIFI_ENTRY_COUNT; i++) {
+ mInternetAdapter.setWifiEntries(mWifiEntries, i /* wifiEntriesCount */);
- assertThat(mInternetAdapter.getItemCount()).isEqualTo(4);
- }
-
- @Test
- public void getItemCount_withApmOnWifiOnHasInternetWifi_returnThree() {
- // The preconditions WiFi ON and Internet WiFi are already in setUp()
- when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
-
- assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
- }
-
- @Test
- public void getItemCount_withApmOffWifiOnNoInternetWifi_returnThree() {
- // The preconditions WiFi ON is already in setUp()
- when(mInternetDialogController.getInternetWifiEntry()).thenReturn(null);
- when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
- assertThat(mInternetAdapter.getItemCount()).isEqualTo(3);
- }
-
- @Test
- public void getItemCount_withApmOffWifiOnHasInternetWifi_returnTwo() {
- // The preconditions WiFi ON and Internet WiFi are already in setUp()
- when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
-
- assertThat(mInternetAdapter.getItemCount()).isEqualTo(2);
+ assertThat(mInternetAdapter.getItemCount()).isEqualTo(i);
+ }
}
@Test
@@ -103,7 +98,7 @@
assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -114,11 +109,21 @@
assertThat(mViewHolder.mWifiTitleText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiSummaryText.getVisibility()).isEqualTo(View.VISIBLE);
assertThat(mViewHolder.mWifiIcon.getVisibility()).isEqualTo(View.VISIBLE);
- assertThat(mViewHolder.mWifiLockedIcon.getVisibility()).isEqualTo(View.VISIBLE);
+ assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
- public void onBindViewHolder_bindDefaultWifiNetwork_getIconWithInternet() {
+ public void onBindViewHolder_wifiLevelUnreachable_shouldNotGetWifiIcon() {
+ reset(mWifiIconInjector);
+ when(mWifiEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
+
+ mInternetAdapter.onBindViewHolder(mViewHolder, 0);
+
+ verify(mWifiIconInjector, never()).getIcon(anyBoolean(), anyInt());
+ }
+
+ @Test
+ public void onBindViewHolder_shouldNotShowXLevelIcon_getIconWithInternet() {
when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(false);
mInternetAdapter.onBindViewHolder(mViewHolder, 0);
@@ -127,11 +132,36 @@
}
@Test
- public void onBindViewHolder_bindNoDefaultWifiNetwork_getIconWithNoInternet() {
+ public void onBindViewHolder_shouldShowXLevelIcon_getIconWithNoInternet() {
when(mWifiEntry.shouldShowXLevelIcon()).thenReturn(true);
mInternetAdapter.onBindViewHolder(mViewHolder, 0);
verify(mWifiIconInjector).getIcon(eq(true) /* noInternet */, anyInt());
}
+
+ @Test
+ public void viewHolderUpdateEndIcon_wifiConnected_updateGearIcon() {
+ mTestableResources.addOverride(GEAR_ICON_RES_ID, mGearIcon);
+
+ mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_CONNECTED, WifiEntry.SECURITY_PSK);
+
+ assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mGearIcon);
+ }
+
+ @Test
+ public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityPsk_updateLockIcon() {
+ mTestableResources.addOverride(LOCK_ICON_RES_ID, mLockIcon);
+
+ mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_PSK);
+
+ assertThat(mViewHolder.mWifiEndIcon.getDrawable()).isEqualTo(mLockIcon);
+ }
+
+ @Test
+ public void viewHolderUpdateEndIcon_wifiDisconnectedAndSecurityNone_hideIcon() {
+ mViewHolder.updateEndIcon(WifiEntry.CONNECTED_STATE_DISCONNECTED, WifiEntry.SECURITY_NONE);
+
+ assertThat(mViewHolder.mWifiEndIcon.getVisibility()).isEqualTo(View.GONE);
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
index 830fe5a..baddacc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogControllerTest.java
@@ -10,6 +10,7 @@
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -17,7 +18,6 @@
import android.content.Intent;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.ServiceState;
@@ -84,14 +84,26 @@
@Mock
private WifiEntry mConnectedEntry;
@Mock
+ private WifiEntry mWifiEntry1;
+ @Mock
+ private WifiEntry mWifiEntry2;
+ @Mock
+ private WifiEntry mWifiEntry3;
+ @Mock
+ private WifiEntry mWifiEntry4;
+ @Mock
private ServiceState mServiceState;
@Mock
private BroadcastDispatcher mBroadcastDispatcher;
@Mock
private WifiUtils.InternetIconInjector mWifiIconInjector;
+ @Mock
+ InternetDialogController.InternetDialogCallback mInternetDialogCallback;
private MockInternetDialogController mInternetDialogController;
private FakeExecutor mExecutor = new FakeExecutor(new FakeSystemClock());
+ private List<WifiEntry> mAccessPoints = new ArrayList<>();
+ private List<WifiEntry> mWifiEntries = new ArrayList<>();
@Before
public void setUp() {
@@ -100,6 +112,13 @@
when(mKeyguardStateController.isUnlocked()).thenReturn(true);
when(mConnectedEntry.isDefaultNetwork()).thenReturn(true);
when(mConnectedEntry.hasInternetAccess()).thenReturn(true);
+ when(mWifiEntry1.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+ when(mWifiEntry2.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+ when(mWifiEntry3.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+ when(mWifiEntry4.getConnectedState()).thenReturn(WifiEntry.CONNECTED_STATE_DISCONNECTED);
+ mAccessPoints.add(mConnectedEntry);
+ mAccessPoints.add(mWifiEntry1);
+ when(mSubscriptionManager.getActiveSubscriptionIdList()).thenReturn(new int[]{SUB_ID});
mInternetDialogController = new MockInternetDialogController(mContext,
mock(UiEventLogger.class), mock(ActivityStarter.class), mAccessPointController,
@@ -108,10 +127,9 @@
mock(KeyguardUpdateMonitor.class), mGlobalSettings, mKeyguardStateController);
mSubscriptionManager.addOnSubscriptionsChangedListener(mExecutor,
mInternetDialogController.mOnSubscriptionsChangedListener);
- mInternetDialogController.onStart(
- mock(InternetDialogController.InternetDialogCallback.class));
+ mInternetDialogController.onStart(mInternetDialogCallback, true);
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
mInternetDialogController.mActivityStarter = mActivityStarter;
- mInternetDialogController.mConnectedEntry = mConnectedEntry;
mInternetDialogController.mWifiIconInjector = mWifiIconInjector;
}
@@ -143,32 +161,46 @@
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(false);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("wifi_is_off")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("wifi_is_off"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("wifi_is_off"));
}
@Test
public void getSubtitleText_withNoWifiEntry_returnSearchWifi() {
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = mock(ArrayList.class);
- doReturn(0).when(wifiScanResults).size();
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
+ mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(true),
- getResourcesString("wifi_empty_list_wifi_on")));
+ assertThat(mInternetDialogController.getSubtitleText(true))
+ .isEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(true))
+ .isNotEqualTo(getResourcesString("wifi_empty_list_wifi_on"));
}
@Test
public void getSubtitleText_withWifiEntry_returnTapToConnect() {
+ // The preconditions WiFi Entries is already in setUp()
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = mock(ArrayList.class);
- doReturn(1).when(wifiScanResults).size();
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("tap_a_network_to_connect")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("tap_a_network_to_connect"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("tap_a_network_to_connect"));
}
@Test
@@ -185,11 +217,7 @@
public void getSubtitleText_withNoService_returnNoNetworksAvailable() {
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = new ArrayList<>();
- doReturn(wifiScanResults).when(mWifiManager).getScanResults();
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- when(mSubscriptionManager.getActiveSubscriptionIdList())
- .thenReturn(new int[] {SUB_ID});
+ mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
doReturn(ServiceState.STATE_OUT_OF_SERVICE).when(mServiceState).getState();
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
@@ -203,103 +231,35 @@
public void getSubtitleText_withMobileDataDisabled_returnNoOtherAvailable() {
mInternetDialogController.setAirplaneModeEnabled(false);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = new ArrayList<>();
- doReturn(wifiScanResults).when(mWifiManager).getScanResults();
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
- when(mSubscriptionManager.getActiveSubscriptionIdList())
- .thenReturn(new int[] {SUB_ID});
+ mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
doReturn(ServiceState.STATE_IN_SERVICE).when(mServiceState).getState();
doReturn(mServiceState).when(mTelephonyManager).getServiceState();
when(mTelephonyManager.isDataEnabled()).thenReturn(false);
- assertTrue(TextUtils.equals(mInternetDialogController.getSubtitleText(false),
- getResourcesString("non_carrier_network_unavailable")));
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isEqualTo(getResourcesString("non_carrier_network_unavailable"));
+
+ // if the Wi-Fi disallow config, then don't return Wi-Fi related string.
+ mInternetDialogController.mCanConfigWifi = false;
+
+ assertThat(mInternetDialogController.getSubtitleText(false))
+ .isNotEqualTo(getResourcesString("non_carrier_network_unavailable"));
}
@Test
- public void getInternetWifiEntry_connectedEntryIsNull_returnNull() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
+ public void getWifiDetailsSettingsIntent_withNoKey_returnNull() {
+ assertThat(mInternetDialogController.getWifiDetailsSettingsIntent(null)).isNull();
}
@Test
- public void getInternetWifiEntry_connectedWifiIsNotDefaultNetwork_returnNull() {
- when(mConnectedEntry.isDefaultNetwork()).thenReturn(false);
-
- assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
+ public void getWifiDetailsSettingsIntent_withKey_returnIntent() {
+ assertThat(mInternetDialogController.getWifiDetailsSettingsIntent("test_key")).isNotNull();
}
@Test
- public void getInternetWifiEntry_connectedWifiHasNotInternetAccess_returnNull() {
- when(mConnectedEntry.hasInternetAccess()).thenReturn(false);
-
- assertThat(mInternetDialogController.getInternetWifiEntry()).isNull();
- }
-
- @Test
- public void getInternetWifiEntry_connectedEntryIsInternetWifi_returnConnectedEntry() {
- // The preconditions have been set in setUp().
- // - The connected Wi-Fi entry have both default network and internet access conditions.
-
- assertThat(mInternetDialogController.getInternetWifiEntry()).isEqualTo(mConnectedEntry);
- }
-
- @Test
- public void getInternetWifiTitle_withNoConnectedWifiEntry_returnEmpty() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getInternetWifiTitle()).isEmpty();
- }
-
- @Test
- public void getInternetWifiTitle_withInternetWifi_returnTitle() {
- // The preconditions have been set in setUp().
- // - The connected Wi-Fi entry have both default network and internet access conditions.
- when(mConnectedEntry.getTitle()).thenReturn(CONNECTED_TITLE);
-
- assertThat(mInternetDialogController.getInternetWifiTitle()).isEqualTo(CONNECTED_TITLE);
- }
-
- @Test
- public void getInternetWifiSummary_withNoConnectedWifiEntry_returnEmpty() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getInternetWifiSummary()).isEmpty();
- }
-
- @Test
- public void getInternetWifiSummary_withInternetWifi_returnSummary() {
- when(mConnectedEntry.getSummary(false)).thenReturn(CONNECTED_SUMMARY);
-
- assertThat(mInternetDialogController.getInternetWifiSummary()).isEqualTo(CONNECTED_SUMMARY);
- }
-
- @Test
- public void getWifiDetailsSettingsIntent_withNoConnectedEntry_returnNull() {
- mInternetDialogController.mConnectedEntry = null;
-
- assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
- }
-
- @Test
- public void getWifiDetailsSettingsIntent_withNoConnectedEntryKey_returnNull() {
- when(mConnectedEntry.getKey()).thenReturn(null);
-
- assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNull();
- }
-
- @Test
- public void getWifiDetailsSettingsIntent_withConnectedEntryKey_returnIntent() {
- when(mConnectedEntry.getKey()).thenReturn("test_key");
-
- assertThat(mInternetDialogController.getWifiDetailsSettingsIntent()).isNotNull();
- }
-
- @Test
- public void getWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() {
+ public void getInternetWifiDrawable_withConnectedEntry_returnIntentIconWithCorrectColor() {
final Drawable drawable = mock(Drawable.class);
when(mWifiIconInjector.getIcon(anyBoolean(), anyInt())).thenReturn(drawable);
@@ -310,20 +270,25 @@
}
@Test
- public void launchWifiNetworkDetailsSetting_withNoConnectedEntry_doNothing() {
- mInternetDialogController.mConnectedEntry = null;
+ public void getInternetWifiDrawable_withWifiLevelUnreachable_returnNull() {
+ when(mConnectedEntry.getLevel()).thenReturn(WifiEntry.WIFI_LEVEL_UNREACHABLE);
- mInternetDialogController.launchWifiNetworkDetailsSetting();
+ Drawable drawable = mInternetDialogController.getInternetWifiDrawable(mConnectedEntry);
+
+ assertThat(drawable).isNull();
+ }
+
+ @Test
+ public void launchWifiNetworkDetailsSetting_withNoWifiEntryKey_doNothing() {
+ mInternetDialogController.launchWifiNetworkDetailsSetting(null /* key */);
verify(mActivityStarter, never())
.postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
}
@Test
- public void launchWifiNetworkDetailsSetting_withConnectedEntryKey_startActivity() {
- when(mConnectedEntry.getKey()).thenReturn("test_key");
-
- mInternetDialogController.launchWifiNetworkDetailsSetting();
+ public void launchWifiNetworkDetailsSetting_withWifiEntryKey_startActivity() {
+ mInternetDialogController.launchWifiNetworkDetailsSetting("wifi_entry_key");
verify(mActivityStarter).postStartActivityDismissingKeyguard(any(Intent.class), anyInt());
}
@@ -342,6 +307,143 @@
assertThat(mInternetDialogController.isDeviceLocked()).isTrue();
}
+ @Test
+ public void onAccessPointsChanged_canNotConfigWifi_doNothing() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.mCanConfigWifi = false;
+
+ mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+ verify(mInternetDialogCallback, never()).onAccessPointsChanged(any(), any());
+ }
+
+ @Test
+ public void onAccessPointsChanged_nullAccessPoints_callbackBothNull() {
+ reset(mInternetDialogCallback);
+
+ mInternetDialogController.onAccessPointsChanged(null /* accessPoints */);
+
+ verify(mInternetDialogCallback)
+ .onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry */);
+ }
+
+ @Test
+ public void onAccessPointsChanged_oneConnectedEntry_callbackConnectedEntryOnly() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mConnectedEntry);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+ }
+
+ @Test
+ public void onAccessPointsChanged_noConnectedEntryAndOneOther_callbackWifiEntriesOnly() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mWifiEntry1);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ verify(mInternetDialogCallback)
+ .onAccessPointsChanged(mWifiEntries, null /* connectedEntry */);
+ }
+
+ @Test
+ public void onAccessPointsChanged_oneConnectedEntryAndOneOther_callbackCorrectly() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mConnectedEntry);
+ mAccessPoints.add(mWifiEntry1);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+ }
+
+ @Test
+ public void onAccessPointsChanged_oneConnectedEntryAndTwoOthers_callbackCorrectly() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mConnectedEntry);
+ mAccessPoints.add(mWifiEntry1);
+ mAccessPoints.add(mWifiEntry2);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ mWifiEntries.add(mWifiEntry2);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+ }
+
+ @Test
+ public void onAccessPointsChanged_oneConnectedEntryAndThreeOthers_callbackCutMore() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mConnectedEntry);
+ mAccessPoints.add(mWifiEntry1);
+ mAccessPoints.add(mWifiEntry2);
+ mAccessPoints.add(mWifiEntry3);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ mWifiEntries.add(mWifiEntry2);
+ mWifiEntries.add(mWifiEntry3);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+ // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(false);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.remove(mWifiEntry3);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+ }
+
+ @Test
+ public void onAccessPointsChanged_oneConnectedEntryAndFourOthers_callbackCutMore() {
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(true);
+ mAccessPoints.clear();
+ mAccessPoints.add(mConnectedEntry);
+ mAccessPoints.add(mWifiEntry1);
+ mAccessPoints.add(mWifiEntry2);
+ mAccessPoints.add(mWifiEntry3);
+ mAccessPoints.add(mWifiEntry4);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.clear();
+ mWifiEntries.add(mWifiEntry1);
+ mWifiEntries.add(mWifiEntry2);
+ mWifiEntries.add(mWifiEntry3);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+
+ // Turn off airplane mode to has carrier network, then Wi-Fi entries will cut last one.
+ reset(mInternetDialogCallback);
+ mInternetDialogController.setAirplaneModeEnabled(false);
+
+ mInternetDialogController.onAccessPointsChanged(mAccessPoints);
+
+ mWifiEntries.remove(mWifiEntry3);
+ verify(mInternetDialogCallback).onAccessPointsChanged(mWifiEntries, mConnectedEntry);
+ }
+
private String getResourcesString(String name) {
return mContext.getResources().getString(getResourcesId(name));
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
index 5a018f4..fa9c053 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/tiles/dialog/InternetDialogTest.java
@@ -12,7 +12,6 @@
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
-import android.net.wifi.ScanResult;
import android.net.wifi.WifiManager;
import android.os.Handler;
import android.telephony.TelephonyManager;
@@ -20,7 +19,6 @@
import android.testing.TestableLooper;
import android.view.View;
import android.widget.LinearLayout;
-import android.widget.TextView;
import androidx.recyclerview.widget.RecyclerView;
import androidx.test.filters.SmallTest;
@@ -39,8 +37,6 @@
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
-import java.util.ArrayList;
-import java.util.Arrays;
import java.util.List;
@SmallTest
@@ -62,13 +58,16 @@
@Mock
private WifiEntry mInternetWifiEntry;
@Mock
- private WifiEntry mWifiEntry;
+ private List<WifiEntry> mWifiEntries;
@Mock
private InternetAdapter mInternetAdapter;
@Mock
private InternetDialogController mInternetDialogController;
private InternetDialog mInternetDialog;
+ private View mDialogView;
+ private View mSubTitle;
+ private LinearLayout mMobileDataToggle;
private LinearLayout mWifiToggle;
private LinearLayout mConnectedWifi;
private RecyclerView mWifiList;
@@ -83,26 +82,26 @@
when(mInternetWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
when(mInternetWifiEntry.isDefaultNetwork()).thenReturn(true);
when(mInternetWifiEntry.hasInternetAccess()).thenReturn(true);
- when(mWifiEntry.getTitle()).thenReturn(WIFI_TITLE);
- when(mWifiEntry.getSummary(false)).thenReturn(WIFI_SUMMARY);
+ when(mWifiEntries.size()).thenReturn(1);
when(mInternetDialogController.getMobileNetworkTitle()).thenReturn(MOBILE_NETWORK_TITLE);
when(mInternetDialogController.getMobileNetworkSummary())
.thenReturn(MOBILE_NETWORK_SUMMARY);
when(mInternetDialogController.getWifiManager()).thenReturn(mWifiManager);
- when(mInternetDialogController.getInternetWifiEntry()).thenReturn(mInternetWifiEntry);
- when(mInternetDialogController.getWifiEntryList()).thenReturn(Arrays.asList(mWifiEntry));
mInternetDialog = new InternetDialog(mContext, mock(InternetDialogFactory.class),
- mInternetDialogController, true, true, mock(UiEventLogger.class), mHandler);
+ mInternetDialogController, true, true, true, mock(UiEventLogger.class), mHandler);
mInternetDialog.mAdapter = mInternetAdapter;
- mInternetDialog.mConnectedWifiEntry = mInternetWifiEntry;
+ mInternetDialog.onAccessPointsChanged(mWifiEntries, mInternetWifiEntry);
mInternetDialog.show();
- mWifiToggle = mInternetDialog.mDialogView.requireViewById(R.id.turn_on_wifi_layout);
- mConnectedWifi = mInternetDialog.mDialogView.requireViewById(R.id.wifi_connected_layout);
- mWifiList = mInternetDialog.mDialogView.requireViewById(R.id.wifi_list_layout);
- mSeeAll = mInternetDialog.mDialogView.requireViewById(R.id.see_all_layout);
+ mDialogView = mInternetDialog.mDialogView;
+ mSubTitle = mDialogView.requireViewById(R.id.internet_dialog_subtitle);
+ mMobileDataToggle = mDialogView.requireViewById(R.id.mobile_network_layout);
+ mWifiToggle = mDialogView.requireViewById(R.id.turn_on_wifi_layout);
+ mConnectedWifi = mDialogView.requireViewById(R.id.wifi_connected_layout);
+ mWifiList = mDialogView.requireViewById(R.id.wifi_list_layout);
+ mSeeAll = mDialogView.requireViewById(R.id.see_all_layout);
}
@After
@@ -111,33 +110,41 @@
}
@Test
+ public void hideWifiViews_WifiViewsGone() {
+ mInternetDialog.hideWifiViews();
+
+ assertThat(mInternetDialog.mIsProgressBarVisible).isFalse();
+ assertThat(mWifiToggle.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mConnectedWifi.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mWifiList.getVisibility()).isEqualTo(View.GONE);
+ assertThat(mSeeAll.getVisibility()).isEqualTo(View.GONE);
+ }
+
+ @Test
public void updateDialog_withApmOn_internetDialogSubTitleGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- mInternetDialog.updateDialog();
- final TextView view = mInternetDialog.mDialogView.requireViewById(
- R.id.internet_dialog_subtitle);
- assertThat(view.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.GONE);
}
@Test
public void updateDialog_withApmOff_internetDialogSubTitleVisible() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(false);
- mInternetDialog.updateDialog();
- final TextView view = mInternetDialog.mDialogView.requireViewById(
- R.id.internet_dialog_subtitle);
- assertThat(view.getVisibility()).isEqualTo(View.VISIBLE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mSubTitle.getVisibility()).isEqualTo(View.VISIBLE);
}
@Test
public void updateDialog_withApmOn_mobileDataLayoutGone() {
when(mInternetDialogController.isAirplaneModeEnabled()).thenReturn(true);
- mInternetDialog.updateDialog();
- final LinearLayout linearLayout = mInternetDialog.mDialogView.requireViewById(
- R.id.mobile_network_layout);
- assertThat(linearLayout.getVisibility()).isEqualTo(View.GONE);
+ mInternetDialog.updateDialog();
+
+ assertThat(mMobileDataToggle.getVisibility()).isEqualTo(View.GONE);
}
@Test
@@ -152,7 +159,8 @@
@Test
public void updateDialog_wifiOnAndNoConnectedWifi_hideConnectedWifi() {
- mInternetDialog.mConnectedWifiEntry = null;
+ // The precondition WiFi ON is already in setUp()
+ mInternetDialog.onAccessPointsChanged(mWifiEntries, null /* connectedEntry*/);
doReturn(false).when(mInternetDialogController).activeNetworkIsCellular();
mInternetDialog.updateDialog();
@@ -162,7 +170,8 @@
@Test
public void updateDialog_wifiOnAndNoWifiList_hideWifiListAndSeeAll() {
- when(mInternetDialogController.getWifiEntryList()).thenReturn(null);
+ // The precondition WiFi ON is already in setUp()
+ mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, mInternetWifiEntry);
mInternetDialog.updateDialog();
@@ -245,9 +254,6 @@
public void showProgressBar_wifiEnabledWithWifiEntry_showProgressBarThenHide() {
Mockito.reset(mHandler);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = mock(ArrayList.class);
- when(wifiScanResults.size()).thenReturn(1);
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
mInternetDialog.showProgressBar();
@@ -264,12 +270,10 @@
}
@Test
- public void showProgressBar_wifiEnabledWithoutWifiScanResults_showProgressBarThenHideSearch() {
+ public void showProgressBar_wifiEnabledWithoutWifiEntries_showProgressBarThenHideSearch() {
Mockito.reset(mHandler);
when(mWifiManager.isWifiEnabled()).thenReturn(true);
- List<ScanResult> wifiScanResults = mock(ArrayList.class);
- when(wifiScanResults.size()).thenReturn(0);
- when(mWifiManager.getScanResults()).thenReturn(wifiScanResults);
+ mInternetDialog.onAccessPointsChanged(null /* wifiEntries */, null /* connectedEntry*/);
mInternetDialog.showProgressBar();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
index be7917a..2416132 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/CommandQueueTest.java
@@ -425,17 +425,18 @@
final boolean credentialAllowed = true;
final boolean requireConfirmation = true;
final int userId = 10;
- final String packageName = "test";
final long operationId = 1;
+ final String packageName = "test";
+ final long requestId = 10;
final int multiSensorConfig = BiometricManager.BIOMETRIC_MULTI_SENSOR_DEFAULT;
mCommandQueue.showAuthenticationDialog(promptInfo, receiver, sensorIds,
- credentialAllowed, requireConfirmation , userId, packageName, operationId,
+ credentialAllowed, requireConfirmation, userId, operationId, packageName, requestId,
multiSensorConfig);
waitForIdleSync();
verify(mCallbacks).showAuthenticationDialog(eq(promptInfo), eq(receiver), eq(sensorIds),
- eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(packageName),
- eq(operationId), eq(multiSensorConfig));
+ eq(credentialAllowed), eq(requireConfirmation), eq(userId), eq(operationId),
+ eq(packageName), eq(requestId), eq(multiSensorConfig));
}
@Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index a7b1446..7f72f19 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -25,6 +25,7 @@
import android.view.ViewRootImpl
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.Interpolators
import com.android.systemui.dump.DumpManager
import com.android.systemui.plugins.statusbar.StatusBarStateController
import com.android.systemui.statusbar.phone.BiometricUnlockController
@@ -178,10 +179,21 @@
@Test
fun setQsPanelExpansion_appliesBlur() {
+ statusBarState = StatusBarState.KEYGUARD
notificationShadeDepthController.qsPanelExpansion = 1f
- notificationShadeDepthController.onPanelExpansionChanged(0.5f, tracking = false)
+ notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
notificationShadeDepthController.updateBlurCallback.doFrame(0)
- verify(blurUtils).applyBlur(any(), anyInt(), eq(false))
+ verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
+ }
+
+ @Test
+ fun setQsPanelExpansion_easing() {
+ statusBarState = StatusBarState.KEYGUARD
+ notificationShadeDepthController.qsPanelExpansion = 0.25f
+ notificationShadeDepthController.onPanelExpansionChanged(1f, tracking = false)
+ notificationShadeDepthController.updateBlurCallback.doFrame(0)
+ verify(wallpaperManager).setWallpaperZoomOut(any(),
+ eq(Interpolators.getNotificationScrimAlpha(0.25f, false /* notifications */)))
}
@Test
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/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
index aa73152..faf968b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.java
@@ -17,10 +17,14 @@
package com.android.systemui.statusbar.phone;
+import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
+import static com.android.systemui.statusbar.StatusBarState.SHADE;
+
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
import android.testing.AndroidTestingRunner;
import android.testing.TestableLooper;
@@ -30,18 +34,24 @@
import androidx.test.filters.SmallTest;
import com.android.keyguard.CarrierTextController;
+import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.KeyguardUpdateMonitorCallback;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import com.android.systemui.battery.BatteryMeterViewController;
import com.android.systemui.flags.FeatureFlags;
+import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.SysuiStatusBarStateController;
import com.android.systemui.statusbar.events.SystemStatusAnimationScheduler;
import com.android.systemui.statusbar.policy.BatteryController;
import com.android.systemui.statusbar.policy.ConfigurationController;
+import com.android.systemui.statusbar.policy.KeyguardStateController;
import com.android.systemui.statusbar.policy.UserInfoController;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -66,13 +76,24 @@
@Mock
private BatteryMeterViewController mBatteryMeterViewController;
@Mock
- private KeyguardStatusBarViewController.ViewStateProvider mViewStateProvider;
+ private KeyguardStateController mKeyguardStateController;
+ @Mock
+ private KeyguardBypassController mKeyguardBypassController;
+ @Mock
+ private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
+ @Mock
+ private BiometricUnlockController mBiometricUnlockController;
+ @Mock
+ private SysuiStatusBarStateController mStatusBarStateController;
+ private TestNotificationPanelViewStateProvider mNotificationPanelViewStateProvider;
private KeyguardStatusBarView mKeyguardStatusBarView;
private KeyguardStatusBarViewController mController;
@Before
public void setup() throws Exception {
+ mNotificationPanelViewStateProvider = new TestNotificationPanelViewStateProvider();
+
MockitoAnnotations.initMocks(this);
allowTestableLooperAsMainThread();
@@ -92,7 +113,12 @@
mStatusBarIconController,
new StatusBarIconController.TintedIconManager.Factory(mFeatureFlags),
mBatteryMeterViewController,
- mViewStateProvider
+ mNotificationPanelViewStateProvider,
+ mKeyguardStateController,
+ mKeyguardBypassController,
+ mKeyguardUpdateMonitor,
+ mBiometricUnlockController,
+ mStatusBarStateController
);
}
@@ -180,4 +206,179 @@
assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(newAlpha);
assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(newVisibility);
}
+
+ @Test
+ public void updateViewState_notKeyguardState_nothingUpdated() {
+ mController.onViewAttached();
+ updateStateToNotKeyguard();
+
+ float oldAlpha = mKeyguardStatusBarView.getAlpha();
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getAlpha()).isEqualTo(oldAlpha);
+ }
+
+ @Test
+ public void updateViewState_bypassEnabledAndShouldListenForFace_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+
+ when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ onFinishedGoingToSleep();
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void updateViewState_bypassNotEnabled_viewShown() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(true);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(false);
+ onFinishedGoingToSleep();
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void updateViewState_shouldNotListenForFace_viewShown() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ when(mKeyguardUpdateMonitor.shouldListenForFace()).thenReturn(false);
+ when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
+ onFinishedGoingToSleep();
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ @Test
+ public void updateViewState_panelExpandedHeightZero_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ mNotificationPanelViewStateProvider.setPanelViewExpandedHeight(0);
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void updateViewState_qsExpansionOne_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ mNotificationPanelViewStateProvider.setQsExpansionFraction(1f);
+
+ mController.updateViewState();
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ // TODO(b/195442899): Add more tests for #updateViewState once CLs are finalized.
+
+ @Test
+ public void updateForHeadsUp_headsUpShouldBeVisible_viewHidden() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+ mKeyguardStatusBarView.setVisibility(View.VISIBLE);
+
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.INVISIBLE);
+ }
+
+ @Test
+ public void updateForHeadsUp_headsUpShouldNotBeVisible_viewShown() {
+ mController.onViewAttached();
+ updateStateToKeyguard();
+
+ // Start with the opposite state.
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(true);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ mNotificationPanelViewStateProvider.setShouldHeadsUpBeVisible(false);
+ mController.updateForHeadsUp(/* animate= */ false);
+
+ assertThat(mKeyguardStatusBarView.getVisibility()).isEqualTo(View.VISIBLE);
+ }
+
+ private void updateStateToNotKeyguard() {
+ updateStatusBarState(SHADE);
+ }
+
+ private void updateStateToKeyguard() {
+ updateStatusBarState(KEYGUARD);
+ }
+
+ private void updateStatusBarState(int state) {
+ ArgumentCaptor<StatusBarStateController.StateListener> statusBarStateListenerCaptor =
+ ArgumentCaptor.forClass(StatusBarStateController.StateListener.class);
+ verify(mStatusBarStateController).addCallback(statusBarStateListenerCaptor.capture());
+ StatusBarStateController.StateListener callback = statusBarStateListenerCaptor.getValue();
+
+ callback.onStateChanged(state);
+ }
+
+ /**
+ * Calls {@link com.android.keyguard.KeyguardUpdateMonitorCallback#onFinishedGoingToSleep(int)}
+ * to ensure values are updated properly.
+ */
+ private void onFinishedGoingToSleep() {
+ ArgumentCaptor<KeyguardUpdateMonitorCallback> keyguardUpdateCallbackCaptor =
+ ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback.class);
+ verify(mKeyguardUpdateMonitor).registerCallback(keyguardUpdateCallbackCaptor.capture());
+ KeyguardUpdateMonitorCallback callback = keyguardUpdateCallbackCaptor.getValue();
+
+ callback.onFinishedGoingToSleep(0);
+ }
+
+ private static class TestNotificationPanelViewStateProvider
+ implements NotificationPanelViewController.NotificationPanelViewStateProvider {
+
+ TestNotificationPanelViewStateProvider() {}
+
+ private float mPanelViewExpandedHeight = 100f;
+ private float mQsExpansionFraction = 0f;
+ private boolean mShouldHeadsUpBeVisible = false;
+
+ @Override
+ public float getPanelViewExpandedHeight() {
+ return mPanelViewExpandedHeight;
+ }
+
+ @Override
+ public float getQsExpansionFraction() {
+ return mQsExpansionFraction;
+ }
+
+ @Override
+ public boolean shouldHeadsUpBeVisible() {
+ return mShouldHeadsUpBeVisible;
+ }
+
+ public void setPanelViewExpandedHeight(float panelViewExpandedHeight) {
+ this.mPanelViewExpandedHeight = panelViewExpandedHeight;
+ }
+
+ public void setQsExpansionFraction(float qsExpansionFraction) {
+ this.mQsExpansionFraction = qsExpansionFraction;
+ }
+
+ public void setShouldHeadsUpBeVisible(boolean shouldHeadsUpBeVisible) {
+ this.mShouldHeadsUpBeVisible = shouldHeadsUpBeVisible;
+ }
+ }
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
index 1dc6fa2..bef10ce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/NotificationPanelViewTest.java
@@ -47,7 +47,6 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.ContentObserver;
-import android.hardware.biometrics.BiometricSourceType;
import android.os.Handler;
import android.os.Looper;
import android.os.PowerManager;
@@ -229,8 +228,6 @@
@Mock
private ConversationNotificationManager mConversationNotificationManager;
@Mock
- private BiometricUnlockController mBiometricUnlockController;
- @Mock
private StatusBarKeyguardViewManager mStatusBarKeyguardViewManager;
@Mock
private KeyguardStatusViewComponent.Factory mKeyguardStatusViewComponentFactory;
@@ -416,7 +413,7 @@
mMetricsLogger, mActivityManager, mConfigurationController,
() -> flingAnimationUtilsBuilder, mStatusBarTouchableRegionManager,
mConversationNotificationManager, mMediaHiearchyManager,
- mBiometricUnlockController, mStatusBarKeyguardViewManager,
+ mStatusBarKeyguardViewManager,
mNotificationStackScrollLayoutController,
mKeyguardStatusViewComponentFactory,
mKeyguardQsUserSwitchComponentFactory,
@@ -512,20 +509,6 @@
}
@Test
- public void testKeyguardStatusBarVisibility_hiddenForBypass() {
- when(mUpdateMonitor.shouldListenForFace()).thenReturn(true);
- mNotificationPanelViewController.mKeyguardUpdateCallback.onBiometricRunningStateChanged(
- true, BiometricSourceType.FACE);
- verify(mKeyguardStatusBar, never()).setVisibility(View.VISIBLE);
-
- when(mKeyguardBypassController.getBypassEnabled()).thenReturn(true);
- mNotificationPanelViewController.mKeyguardUpdateCallback.onFinishedGoingToSleep(0);
- mNotificationPanelViewController.mKeyguardUpdateCallback.onBiometricRunningStateChanged(
- true, BiometricSourceType.FACE);
- verify(mKeyguardStatusBar, never()).setVisibility(View.VISIBLE);
- }
-
- @Test
public void testA11y_initializeNode() {
AccessibilityNodeInfo nodeInfo = new AccessibilityNodeInfo();
mAccessibiltyDelegate.onInitializeAccessibilityNodeInfo(mView, nodeInfo);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index 9d316b1..5ebe900 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -712,7 +712,7 @@
public void qsExpansion_half_clippingQs() {
reset(mScrimBehind);
mScrimController.setClipsQsScrim(true);
- mScrimController.setQsPosition(0.5f, 999 /* value doesn't matter */);
+ mScrimController.setQsPosition(0.25f, 999 /* value doesn't matter */);
finishAnimationsImmediately();
assertScrimAlpha(Map.of(
@@ -1138,7 +1138,7 @@
@Test
public void testScrimsVisible_whenShadeVisibleOnLockscreen() {
mScrimController.transitionTo(ScrimState.KEYGUARD);
- mScrimController.setQsPosition(0.5f, 300);
+ mScrimController.setQsPosition(0.25f, 300);
assertScrimAlpha(Map.of(
mScrimBehind, SEMI_TRANSPARENT,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
index 21c4a17..c488ee9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerBaseTest.java
@@ -70,6 +70,7 @@
import com.android.systemui.SysuiTestCase;
import com.android.systemui.broadcast.BroadcastDispatcher;
import com.android.systemui.demomode.DemoModeController;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.flags.FeatureFlags;
import com.android.systemui.statusbar.policy.DeviceProvisionedController.DeviceProvisionedListener;
import com.android.systemui.statusbar.policy.NetworkController.IconState;
@@ -241,7 +242,9 @@
mMockBd,
mDemoModeController,
mCarrierConfigTracker,
- mFeatureFlags);
+ mFeatureFlags,
+ mock(DumpManager.class)
+ );
setupNetworkController();
// Trigger blank callbacks to always get the current state (some tests don't trigger
@@ -309,7 +312,8 @@
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
- mCarrierConfigTracker, mFeatureFlags);
+ mCarrierConfigTracker, mFeatureFlags,
+ mock(DumpManager.class));
setupNetworkController();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
index bc4c2b6..3433a14 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerDataTest.java
@@ -21,6 +21,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.CarrierConfigTracker;
import org.junit.Test;
@@ -113,7 +114,7 @@
mock(AccessPointControllerImpl.class),
mock(DataUsageController.class), mMockSubDefaults,
mock(DeviceProvisionedController.class), mMockBd, mDemoModeController,
- mock(CarrierConfigTracker.class), mFeatureFlags);
+ mock(CarrierConfigTracker.class), mFeatureFlags, mock(DumpManager.class));
setupNetworkController();
setupDefaultSignal();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
index 5090b0d..4ff1301 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/NetworkControllerSignalTest.java
@@ -41,6 +41,7 @@
import com.android.settingslib.mobile.TelephonyIcons;
import com.android.settingslib.net.DataUsageController;
import com.android.systemui.R;
+import com.android.systemui.dump.DumpManager;
import com.android.systemui.util.CarrierConfigTracker;
import org.junit.Test;
@@ -67,7 +68,8 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+ mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+ mock(DumpManager.class));
setupNetworkController();
verifyLastMobileDataIndicators(false, -1, 0);
@@ -87,7 +89,8 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+ mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+ mock(DumpManager.class));
mNetworkController.registerListeners();
// Wait for the main looper to execute the previous command
@@ -155,7 +158,8 @@
Looper.getMainLooper(), mFakeExecutor, mCallbackHandler,
mock(AccessPointControllerImpl.class), mock(DataUsageController.class),
mMockSubDefaults, mock(DeviceProvisionedController.class), mMockBd,
- mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags);
+ mDemoModeController, mock(CarrierConfigTracker.class), mFeatureFlags,
+ mock(DumpManager.class));
setupNetworkController();
// No Subscriptions.
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
index 9c47f19..e6dc4db 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayApplierTest.java
@@ -96,6 +96,8 @@
DumpManager mDumpManager;
@Mock
OverlayManagerTransaction.Builder mTransactionBuilder;
+ @Mock
+ Runnable mOnOverlaysApplied;
private ThemeOverlayApplier mManager;
private boolean mGetOverlayInfoEnabled = true;
@@ -103,7 +105,8 @@
@Before
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
- mManager = new ThemeOverlayApplier(mOverlayManager, MoreExecutors.directExecutor(),
+ mManager = new ThemeOverlayApplier(mOverlayManager,
+ MoreExecutors.directExecutor(), MoreExecutors.directExecutor(),
LAUNCHER_PACKAGE, THEMEPICKER_PACKAGE, mDumpManager) {
@Override
protected OverlayManagerTransaction.Builder getTransactionBuilder() {
@@ -173,7 +176,7 @@
@Test
public void allCategoriesSpecified_allEnabledExclusively() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
verify(mOverlayManager).commit(any());
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
@@ -185,7 +188,7 @@
@Test
public void allCategoriesSpecified_sysuiCategoriesAlsoAppliedToSysuiUser() {
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (Map.Entry<String, OverlayIdentifier> entry : ALL_CATEGORIES_MAP.entrySet()) {
if (SYSTEM_USER_CATEGORIES.contains(entry.getKey())) {
@@ -202,8 +205,9 @@
public void allCategoriesSpecified_enabledForAllUserHandles() {
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- userHandles);
+ userHandles, mOnOverlaysApplied);
+ verify(mOnOverlaysApplied).run();
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
eq(TEST_USER.getIdentifier()));
@@ -219,7 +223,7 @@
Set<UserHandle> userHandles = Sets.newHashSet(TEST_USER_HANDLES);
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, null, TEST_USER.getIdentifier(),
- userHandles);
+ userHandles, mOnOverlaysApplied);
for (OverlayIdentifier overlayPackage : ALL_CATEGORIES_MAP.values()) {
verify(mTransactionBuilder, never()).setEnabled(eq(overlayPackage), eq(true),
@@ -233,7 +237,7 @@
mock(FabricatedOverlay.class)
};
mManager.applyCurrentUserOverlays(ALL_CATEGORIES_MAP, pendingCreation,
- TEST_USER.getIdentifier(), TEST_USER_HANDLES);
+ TEST_USER.getIdentifier(), TEST_USER_HANDLES, mOnOverlaysApplied);
for (FabricatedOverlay overlay : pendingCreation) {
verify(mTransactionBuilder).registerFabricatedOverlay(eq(overlay));
@@ -247,7 +251,7 @@
categoryToPackage.remove(OVERLAY_CATEGORY_ICON_ANDROID);
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (OverlayIdentifier overlayPackage : categoryToPackage.values()) {
verify(mTransactionBuilder).setEnabled(eq(overlayPackage), eq(true),
@@ -264,7 +268,7 @@
@Test
public void zeroCategoriesSpecified_allDisabled() {
mManager.applyCurrentUserOverlays(Maps.newArrayMap(), null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
for (String category : THEME_CATEGORIES) {
verify(mTransactionBuilder).setEnabled(
@@ -279,7 +283,7 @@
categoryToPackage.put("blah.category", new OverlayIdentifier("com.example.blah.category"));
mManager.applyCurrentUserOverlays(categoryToPackage, null, TEST_USER.getIdentifier(),
- TEST_USER_HANDLES);
+ TEST_USER_HANDLES, mOnOverlaysApplied);
verify(mTransactionBuilder, never()).setEnabled(
eq(new OverlayIdentifier("com.example.blah.category")), eq(false),
diff --git a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
index f6a54936..cd911cc 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/theme/ThemeOverlayControllerTest.java
@@ -161,7 +161,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -183,7 +183,7 @@
mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.BLACK),
null, null), WallpaperManager.FLAG_SYSTEM);
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -204,7 +204,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
@@ -240,7 +240,7 @@
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -270,7 +270,7 @@
"android.theme.customization.color_both\":\"0")).isTrue();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -300,7 +300,7 @@
"android.theme.customization.color_both\":\"1")).isTrue();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -327,7 +327,7 @@
assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -354,7 +354,7 @@
assertThat(updatedSetting.getValue().contains("android.theme.customization.color_index"))
.isFalse();
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -382,7 +382,7 @@
eq(Settings.Secure.THEME_CUSTOMIZATION_OVERLAY_PACKAGES), updatedSetting.capture());
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -411,14 +411,14 @@
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
public void onProfileAdded_setsTheme() {
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -428,7 +428,7 @@
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -438,7 +438,7 @@
mBroadcastReceiver.getValue().onReceive(null,
new Intent(Intent.ACTION_MANAGED_PROFILE_ADDED));
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -450,7 +450,7 @@
Color.valueOf(Color.BLUE), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
// Regression test: null events should not reset the internal state and allow colors to be
// applied again.
@@ -458,11 +458,11 @@
mBroadcastReceiver.getValue().onReceive(null, new Intent(Intent.ACTION_WALLPAPER_CHANGED));
mColorsListener.getValue().onColorsChanged(null, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
- any());
+ any(), any());
mColorsListener.getValue().onColorsChanged(new WallpaperColors(Color.valueOf(Color.GREEN),
null, null), WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never()).applyCurrentUserOverlays(any(), any(), anyInt(),
- any());
+ any(), any());
}
@Test
@@ -499,7 +499,7 @@
verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
// Colors were applied during controller initialization.
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
clearInvocations(mThemeOverlayApplier);
}
@@ -533,7 +533,7 @@
verify(mDeviceProvisionedController).addCallback(mDeviceProvisionedListener.capture());
// Colors were applied during controller initialization.
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
clearInvocations(mThemeOverlayApplier);
WallpaperColors mainColors = new WallpaperColors(Color.valueOf(Color.RED),
@@ -542,12 +542,12 @@
// Defers event because we already have initial colors.
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
// Then event happens after setup phase is over.
when(mDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true);
mDeviceProvisionedListener.getValue().onUserSetupChanged();
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -568,11 +568,11 @@
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
mWakefulnessLifecycle.dispatchFinishedGoingToSleep();
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -592,10 +592,10 @@
Color.valueOf(Color.RED), null);
mColorsListener.getValue().onColorsChanged(mainColors, WallpaperManager.FLAG_SYSTEM);
verify(mThemeOverlayApplier, never())
- .applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
mWakefulnessLifecycleObserver.getValue().onFinishedGoingToSleep();
- verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any());
+ verify(mThemeOverlayApplier).applyCurrentUserOverlays(any(), any(), anyInt(), any(), any());
}
@Test
@@ -614,7 +614,7 @@
ArgumentCaptor.forClass(Map.class);
verify(mThemeOverlayApplier)
- .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any());
+ .applyCurrentUserOverlays(themeOverlays.capture(), any(), anyInt(), any(), any());
// Assert that we received the colors that we were expecting
assertThat(themeOverlays.getValue().get(OVERLAY_CATEGORY_SYSTEM_PALETTE))
diff --git a/services/core/java/com/android/server/BluetoothManagerService.java b/services/core/java/com/android/server/BluetoothManagerService.java
index b7c61a0d..dc7904d 100644
--- a/services/core/java/com/android/server/BluetoothManagerService.java
+++ b/services/core/java/com/android/server/BluetoothManagerService.java
@@ -2479,7 +2479,8 @@
try {
foregroundUser = ActivityManager.getCurrentUser();
valid = (callingUser == foregroundUser) || parentUser == foregroundUser
- || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid;
+ || callingAppId == Process.NFC_UID || callingAppId == mSystemUiUid
+ || callingAppId == Process.SHELL_UID;
if (DBG && !valid) {
Slog.d(TAG, "checkIfCallerIsForegroundUser: valid=" + valid + " callingUser="
+ callingUser + " parentUser=" + parentUser + " foregroundUser="
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index a6a8cf01..400b084 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -1833,6 +1833,11 @@
+ ", skipping since the account already exists");
return false;
}
+ if (accounts.accountsDb.findAllDeAccounts().size() > 100) {
+ Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
+ + ", skipping since more than 50 accounts on device exist");
+ return false;
+ }
long accountId = accounts.accountsDb.insertCeAccount(account, password);
if (accountId < 0) {
Log.w(TAG, "insertAccountIntoDatabase: " + account.toSafeString()
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index 5c9d385..2e3e635 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -94,8 +94,6 @@
sGlobalSettingToTypeMap.put(
Settings.Global.ANGLE_GL_DRIVER_SELECTION_VALUES, String.class);
sGlobalSettingToTypeMap.put(
- Settings.Global.ANGLE_ALLOWLIST, String.class);
- sGlobalSettingToTypeMap.put(
Settings.Global.ANGLE_EGL_FEATURES, String.class);
sGlobalSettingToTypeMap.put(
Settings.Global.SHOW_ANGLE_IN_USE_DIALOG_BOX, String.class);
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 5c19ceb..ff480d1 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -72,6 +72,7 @@
import static com.android.server.am.ProcessList.TAG_PROCESS_OBSERVERS;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_SWITCH;
+import android.annotation.IntDef;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityThread;
@@ -114,6 +115,8 @@
import com.android.server.wm.WindowProcessController;
import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
import java.lang.ref.WeakReference;
import java.util.ArrayDeque;
import java.util.ArrayList;
@@ -171,6 +174,27 @@
@EnabledSince(targetSdkVersion = android.os.Build.VERSION_CODES.S)
static final long USE_SHORT_FGS_USAGE_INTERACTION_TIME = 183972877L;
+ static final int CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY = 0;
+ static final int CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY = 1;
+ static final int CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME = 2;
+
+ @IntDef(prefix = { "CACHED_COMPAT_CHANGE_" }, value = {
+ CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY,
+ CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY,
+ CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+ })
+ @Retention(RetentionPolicy.SOURCE)
+ static @interface CachedCompatChangeId{}
+
+ /**
+ * Mapping from CACHED_COMPAT_CHANGE_* to the actual compat change id.
+ */
+ static final long[] CACHED_COMPAT_CHANGE_IDS_MAPPING = new long[] {
+ PROCESS_CAPABILITY_CHANGE_ID,
+ CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID,
+ USE_SHORT_FGS_USAGE_INTERACTION_TIME,
+ };
+
/**
* For some direct access we need to power manager.
*/
@@ -368,6 +392,12 @@
return mPlatformCompatCache;
}
+ boolean isChangeEnabled(@CachedCompatChangeId int cachedCompatChangeId, ApplicationInfo app,
+ boolean defaultValue) {
+ return getPlatformCompatCache().isChangeEnabled(
+ CACHED_COMPAT_CHANGE_IDS_MAPPING[cachedCompatChangeId], app, defaultValue);
+ }
+
OomAdjuster(ActivityManagerService service, ProcessList processList, ActiveUids activeUids) {
this(service, processList, activeUids, createAdjusterThread());
}
@@ -1929,12 +1959,8 @@
(fgsType & FOREGROUND_SERVICE_TYPE_LOCATION)
!= 0 ? PROCESS_CAPABILITY_FOREGROUND_LOCATION : 0;
- boolean enabled = false;
- try {
- enabled = getPlatformCompatCache().isChangeEnabled(
- CAMERA_MICROPHONE_CAPABILITY_CHANGE_ID, s.appInfo);
- } catch (RemoteException e) {
- }
+ final boolean enabled = state.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY);
if (enabled) {
capabilityFromFGS |=
(fgsType & FOREGROUND_SERVICE_TYPE_CAMERA)
@@ -2151,12 +2177,8 @@
// to client's state.
clientProcState = PROCESS_STATE_BOUND_TOP;
state.bumpAllowStartFgsState(PROCESS_STATE_BOUND_TOP);
- boolean enabled = false;
- try {
- enabled = getPlatformCompatCache().isChangeEnabled(
- PROCESS_CAPABILITY_CHANGE_ID, client.info);
- } catch (RemoteException e) {
- }
+ final boolean enabled = cstate.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY);
if (enabled) {
if (cr.hasFlag(Context.BIND_INCLUDE_CAPABILITIES)) {
// TOP process passes all capabilities to the service.
@@ -2800,8 +2822,8 @@
state.setProcStateChanged(true);
}
} else if (state.hasReportedInteraction()) {
- final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
- USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+ final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
final long interactionThreshold = fgsInteractionChangeEnabled
? mConstants.USAGE_STATS_INTERACTION_INTERVAL_POST_S
: mConstants.USAGE_STATS_INTERACTION_INTERVAL_PRE_S;
@@ -2811,8 +2833,8 @@
maybeUpdateUsageStatsLSP(app, nowElapsed);
}
} else {
- final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
- USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+ final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
final long interactionThreshold = fgsInteractionChangeEnabled
? mConstants.SERVICE_USAGE_INTERACTION_TIME_POST_S
: mConstants.SERVICE_USAGE_INTERACTION_TIME_PRE_S;
@@ -2901,8 +2923,8 @@
if (mService.mUsageStatsService == null) {
return;
}
- final boolean fgsInteractionChangeEnabled = getPlatformCompatCache().isChangeEnabled(
- USE_SHORT_FGS_USAGE_INTERACTION_TIME, app.info, false);
+ final boolean fgsInteractionChangeEnabled = state.getCachedCompatChange(
+ CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME);
boolean isInteraction;
// To avoid some abuse patterns, we are going to be careful about what we consider
// to be an app interaction. Being the top activity doesn't count while the display
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index dc6bcd8..d4474d6 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -21,6 +21,7 @@
import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
+import static com.android.server.am.OomAdjuster.CachedCompatChangeId;
import static com.android.server.am.ProcessRecord.TAG;
import android.annotation.ElapsedRealtimeLong;
@@ -377,6 +378,16 @@
@GuardedBy("mService")
private int mCachedIsReceivingBroadcast = VALUE_INVALID;
+ /**
+ * Cache the return value of PlatformCompat.isChangeEnabled().
+ */
+ @GuardedBy("mService")
+ private int[] mCachedCompatChanges = new int[] {
+ VALUE_INVALID, // CACHED_COMPAT_CHANGE_PROCESS_CAPABILITY
+ VALUE_INVALID, // CACHED_COMPAT_CHANGE_CAMERA_MICROPHONE_CAPABILITY
+ VALUE_INVALID, // CACHED_COMPAT_CHANGE_USE_SHORT_FGS_USAGE_INTERACTION_TIME
+ };
+
@GuardedBy("mService")
private int mCachedAdj = ProcessList.INVALID_ADJ;
@GuardedBy("mService")
@@ -1009,6 +1020,16 @@
}
@GuardedBy("mService")
+ boolean getCachedCompatChange(@CachedCompatChangeId int cachedCompatChangeId) {
+ if (mCachedCompatChanges[cachedCompatChangeId] == VALUE_INVALID) {
+ mCachedCompatChanges[cachedCompatChangeId] = mService.mOomAdjuster
+ .isChangeEnabled(cachedCompatChangeId, mApp.info, false /* default */)
+ ? VALUE_TRUE : VALUE_FALSE;
+ }
+ return mCachedCompatChanges[cachedCompatChangeId] == VALUE_TRUE;
+ }
+
+ @GuardedBy("mService")
void computeOomAdjFromActivitiesIfNecessary(OomAdjuster.ComputeOomAdjWindowCallback callback,
int adj, boolean foregroundActivities, boolean hasVisibleActivities, int procState,
int schedGroup, int appUid, int logUid, int processCurTop) {
@@ -1088,6 +1109,9 @@
mCurSchedGroup = mSetSchedGroup = ProcessList.SCHED_GROUP_BACKGROUND;
mCurProcState = mCurRawProcState = mSetProcState = mAllowStartFgsState =
PROCESS_STATE_NONEXISTENT;
+ for (int i = 0; i < mCachedCompatChanges.length; i++) {
+ mCachedCompatChanges[i] = VALUE_INVALID;
+ }
}
@GuardedBy("mService")
diff --git a/services/core/java/com/android/server/app/GameManagerService.java b/services/core/java/com/android/server/app/GameManagerService.java
index af8d7a6..3003c52 100644
--- a/services/core/java/com/android/server/app/GameManagerService.java
+++ b/services/core/java/com/android/server/app/GameManagerService.java
@@ -272,6 +272,13 @@
"com.android.graphics.intervention.wm.allowDownscale";
/**
+ * Metadata that can be included in the app manifest to allow/disallow any ANGLE
+ * interventions. Default value is TRUE.
+ */
+ public static final String METADATA_ANGLE_ALLOW_ANGLE =
+ "com.android.graphics.intervention.angle.allowAngle";
+
+ /**
* Metadata that needs to be included in the app manifest to OPT-IN to PERFORMANCE mode.
* This means the app will assume full responsibility for the experience provided by this
* mode and the system will enable no window manager downscaling.
@@ -294,6 +301,7 @@
private boolean mPerfModeOptedIn;
private boolean mBatteryModeOptedIn;
private boolean mAllowDownscale;
+ private boolean mAllowAngle;
GamePackageConfiguration(String packageName, int userId) {
mPackageName = packageName;
@@ -305,10 +313,12 @@
mPerfModeOptedIn = ai.metaData.getBoolean(METADATA_PERFORMANCE_MODE_ENABLE);
mBatteryModeOptedIn = ai.metaData.getBoolean(METADATA_BATTERY_MODE_ENABLE);
mAllowDownscale = ai.metaData.getBoolean(METADATA_WM_ALLOW_DOWNSCALE, true);
+ mAllowAngle = ai.metaData.getBoolean(METADATA_ANGLE_ALLOW_ANGLE, true);
} else {
mPerfModeOptedIn = false;
mBatteryModeOptedIn = false;
mAllowDownscale = true;
+ mAllowAngle = true;
}
} catch (PackageManager.NameNotFoundException e) {
// Not all packages are installed, hence ignore those that are not installed yet.
@@ -340,14 +350,26 @@
public static final String MODE_KEY = "mode";
public static final String SCALING_KEY = "downscaleFactor";
public static final String DEFAULT_SCALING = "1.0";
+ public static final String ANGLE_KEY = "useAngle";
private final @GameMode int mGameMode;
private final String mScaling;
+ private final boolean mUseAngle;
GameModeConfiguration(KeyValueListParser parser) {
mGameMode = parser.getInt(MODE_KEY, GameManager.GAME_MODE_UNSUPPORTED);
- mScaling = !mAllowDownscale || isGameModeOptedIn(mGameMode)
+ // isGameModeOptedIn() returns if an app will handle all of the changes necessary
+ // for a particular game mode. If so, the Android framework (i.e.
+ // GameManagerService) will not do anything for the app (like window scaling or
+ // using ANGLE).
+ mScaling = !mAllowDownscale || willGamePerformOptimizations(mGameMode)
? DEFAULT_SCALING : parser.getString(SCALING_KEY, DEFAULT_SCALING);
+ // We only want to use ANGLE if:
+ // - We're allowed to use ANGLE (the app hasn't opted out via the manifest) AND
+ // - The app has not opted in to performing the work itself AND
+ // - The Phenotype config has enabled it.
+ mUseAngle = mAllowAngle && !willGamePerformOptimizations(mGameMode)
+ && parser.getBoolean(ANGLE_KEY, false);
}
public int getGameMode() {
@@ -358,6 +380,10 @@
return mScaling;
}
+ public boolean getUseAngle() {
+ return mUseAngle;
+ }
+
public boolean isValid() {
return (mGameMode == GameManager.GAME_MODE_PERFORMANCE
|| mGameMode == GameManager.GAME_MODE_BATTERY)
@@ -368,7 +394,8 @@
* @hide
*/
public String toString() {
- return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + "]";
+ return "[Game Mode:" + mGameMode + ",Scaling:" + mScaling + ",Use Angle:"
+ + mUseAngle + "]";
}
/**
@@ -384,13 +411,14 @@
}
/**
- * Gets whether a package has opted into a game mode via its manifest.
+ * Returns if the app will assume full responsibility for the experience provided by this
+ * mode. If True, the system will not perform any interventions for the app.
*
* @return True if the app package has specified in its metadata either:
* "com.android.app.gamemode.performance.enabled" or
* "com.android.app.gamemode.battery.enabled" with a value of "true"
*/
- public boolean isGameModeOptedIn(@GameMode int gameMode) {
+ public boolean willGamePerformOptimizations(@GameMode int gameMode) {
return (mBatteryModeOptedIn && gameMode == GameManager.GAME_MODE_BATTERY)
|| (mPerfModeOptedIn && gameMode == GameManager.GAME_MODE_PERFORMANCE);
}
@@ -631,7 +659,34 @@
mHandler.sendMessageDelayed(msg, WRITE_SETTINGS_DELAY);
}
}
- updateCompatModeDownscale(packageName, gameMode);
+ updateInterventions(packageName, gameMode);
+ }
+
+ /**
+ * Get if ANGLE is enabled for the package for the currently enabled game mode.
+ * Checks that the caller has {@link android.Manifest.permission#MANAGE_GAME_MODE}.
+ */
+ @Override
+ @RequiresPermission(Manifest.permission.MANAGE_GAME_MODE)
+ public @GameMode boolean getAngleEnabled(String packageName, int userId)
+ throws SecurityException {
+ final int gameMode = getGameMode(packageName, userId);
+ if (gameMode == GameManager.GAME_MODE_UNSUPPORTED) {
+ return false;
+ }
+
+ synchronized (mDeviceConfigLock) {
+ final GamePackageConfiguration config = mConfigs.get(packageName);
+ if (config == null) {
+ return false;
+ }
+ GamePackageConfiguration.GameModeConfiguration gameModeConfiguration =
+ config.getGameModeConfiguration(gameMode);
+ if (gameModeConfiguration == null) {
+ return false;
+ }
+ return gameModeConfiguration.getUseAngle();
+ }
}
/**
@@ -753,7 +808,7 @@
if (DEBUG) {
Slog.v(TAG, dumpDeviceConfigs());
}
- if (packageConfig.isGameModeOptedIn(gameMode)) {
+ if (packageConfig.willGamePerformOptimizations(gameMode)) {
disableCompatScale(packageName);
return;
}
@@ -782,6 +837,17 @@
return (bitField & modeToBitmask(gameMode)) != 0;
}
+ @RequiresPermission(Manifest.permission.WRITE_SECURE_SETTINGS)
+ private void updateUseAngle(String packageName, @GameMode int gameMode) {
+ // TODO (b/188475576): Nothing to do yet. Remove if it's still empty when we're ready to
+ // ship.
+ }
+
+ private void updateInterventions(String packageName, @GameMode int gameMode) {
+ updateCompatModeDownscale(packageName, gameMode);
+ updateUseAngle(packageName, gameMode);
+ }
+
/**
* @hide
*/
@@ -839,11 +905,11 @@
if (newGameMode != gameMode) {
setGameMode(packageName, newGameMode, userId);
}
- updateCompatModeDownscale(packageName, gameMode);
+ updateInterventions(packageName, gameMode);
}
}
} catch (Exception e) {
- Slog.e(TAG, "Failed to update compat modes for user: " + userId);
+ Slog.e(TAG, "Failed to update compat modes for user " + userId + ": " + e);
}
}
@@ -851,7 +917,7 @@
final List<PackageInfo> packages =
mPackageManager.getInstalledPackagesAsUser(0, userId);
return packages.stream().filter(e -> e.applicationInfo != null && e.applicationInfo.category
- == ApplicationInfo.CATEGORY_GAME)
+ == ApplicationInfo.CATEGORY_GAME)
.map(e -> e.packageName)
.toArray(String[]::new);
}
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 8d9479c..b9b90c0 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -93,11 +93,13 @@
import android.media.IPlaybackConfigDispatcher;
import android.media.IRecordingConfigDispatcher;
import android.media.IRingtonePlayer;
+import android.media.ISpatializerCallback;
import android.media.IStrategyPreferredDevicesDispatcher;
import android.media.IVolumeController;
import android.media.MediaMetrics;
import android.media.MediaRecorder.AudioSource;
import android.media.PlayerBase;
+import android.media.Spatializer;
import android.media.VolumePolicy;
import android.media.audiofx.AudioEffect;
import android.media.audiopolicy.AudioMix;
@@ -5292,6 +5294,10 @@
// TODO investigate internal users due to deprecation of SDK API
/** @see AudioManager#setBluetoothA2dpOn(boolean) */
public void setBluetoothA2dpOn(boolean on) {
+ if (!checkAudioSettingsPermission("setBluetoothA2dpOn()")) {
+ return;
+ }
+
// for logging only
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
@@ -5317,6 +5323,10 @@
/** @see AudioManager#startBluetoothSco() */
public void startBluetoothSco(IBinder cb, int targetSdkVersion) {
+ if (!checkAudioSettingsPermission("startBluetoothSco()")) {
+ return;
+ }
+
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final int scoAudioMode =
@@ -5339,6 +5349,10 @@
/** @see AudioManager#startBluetoothScoVirtualCall() */
public void startBluetoothScoVirtualCall(IBinder cb) {
+ if (!checkAudioSettingsPermission("startBluetoothScoVirtualCall()")) {
+ return;
+ }
+
final int uid = Binder.getCallingUid();
final int pid = Binder.getCallingPid();
final String eventSource = new StringBuilder("startBluetoothScoVirtualCall()")
@@ -8225,6 +8239,80 @@
}
//==========================================================================================
+ private final SpatializerHelper mSpatializerHelper = new SpatializerHelper();
+
+ private void enforceModifyDefaultAudioEffectsPermission() {
+ if (mContext.checkCallingOrSelfPermission(
+ android.Manifest.permission.MODIFY_DEFAULT_AUDIO_EFFECTS)
+ != PackageManager.PERMISSION_GRANTED) {
+ throw new SecurityException("Missing MODIFY_DEFAULT_AUDIO_EFFECTS permission");
+ }
+ }
+
+ /** @see AudioManager#getSpatializerImmersiveAudioLevel() */
+ public int getSpatializerImmersiveAudioLevel() {
+ return mSpatializerHelper.getImmersiveAudioLevel();
+ }
+
+ /** @see Spatializer#isEnabled() */
+ public boolean isSpatializerEnabled() {
+ return mSpatializerHelper.isEnabled();
+ }
+
+ /** @see Spatializer#isAvailable() */
+ public boolean isSpatializerAvailable() {
+ return mSpatializerHelper.isAvailable();
+ }
+
+ /** @see Spatializer#setSpatializerEnabled(boolean) */
+ public void setSpatializerEnabled(boolean enabled) {
+ enforceModifyDefaultAudioEffectsPermission();
+ mSpatializerHelper.setEnabled(enabled);
+ }
+
+ /** @see Spatializer#canBeSpatialized() */
+ public boolean canBeSpatialized(
+ @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+ Objects.requireNonNull(attributes);
+ Objects.requireNonNull(format);
+ return mSpatializerHelper.canBeSpatialized(attributes, format);
+ }
+
+ /** @see Spatializer.SpatializerInfoDispatcherStub */
+ public void registerSpatializerCallback(
+ @NonNull ISpatializerCallback dispatcher) {
+ Objects.requireNonNull(dispatcher);
+ mSpatializerHelper.registerStateCallback(dispatcher);
+ }
+
+ /** @see Spatializer.SpatializerInfoDispatcherStub */
+ public void unregisterSpatializerCallback(
+ @NonNull ISpatializerCallback dispatcher) {
+ Objects.requireNonNull(dispatcher);
+ mSpatializerHelper.unregisterStateCallback(dispatcher);
+ }
+
+ /** @see Spatializer#getSpatializerCompatibleAudioDevices() */
+ public @NonNull List<AudioDeviceAttributes> getSpatializerCompatibleAudioDevices() {
+ enforceModifyAudioRoutingPermission();
+ return mSpatializerHelper.getCompatibleAudioDevices();
+ }
+
+ /** @see Spatializer#addSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
+ public void addSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ enforceModifyDefaultAudioEffectsPermission();
+ Objects.requireNonNull(ada);
+ mSpatializerHelper.addCompatibleAudioDevice(ada);
+ }
+
+ /** @see Spatializer#removeSpatializerCompatibleAudioDevice(AudioDeviceAttributes) */
+ public void removeSpatializerCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ enforceModifyDefaultAudioEffectsPermission();
+ Objects.requireNonNull(ada);
+ mSpatializerHelper.removeCompatibleAudioDevice(ada);
+ }
+
+ //==========================================================================================
private boolean readCameraSoundForced() {
return SystemProperties.getBoolean("audio.camerasound.force", false) ||
mContext.getResources().getBoolean(
diff --git a/services/core/java/com/android/server/audio/RotationHelper.java b/services/core/java/com/android/server/audio/RotationHelper.java
index ad72166..872b1fe 100644
--- a/services/core/java/com/android/server/audio/RotationHelper.java
+++ b/services/core/java/com/android/server/audio/RotationHelper.java
@@ -21,20 +21,26 @@
import android.media.AudioSystem;
import android.os.Handler;
import android.util.Log;
+import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
/**
* Class to handle device rotation events for AudioService, and forward device rotation
- * to the audio HALs through AudioSystem.
+ * and current active ID to the audio HALs through AudioSystem.
*
* The role of this class is to monitor device orientation changes, and upon rotation,
* verify the UI orientation. In case of a change, send the new orientation, in increments
* of 90deg, through AudioSystem.
*
+ * Another role of this class is to track current active display ID changes. In case of a
+ * change, send the new active display ID through AudioSystem.
+ *
* Note that even though we're responding to device orientation events, we always
* query the display rotation so audio stays in sync with video/dialogs. This is
* done with .getDefaultDisplay().getRotation() from WINDOW_SERVICE.
+ *
+ * We also monitor current display ID and audio is able to know which display is active.
*/
class RotationHelper {
@@ -43,7 +49,9 @@
private static AudioDisplayListener sDisplayListener;
private static final Object sRotationLock = new Object();
+ private static final Object sActiveDisplayLock = new Object();
private static int sDeviceRotation = Surface.ROTATION_0; // R/W synchronized on sRotationLock
+ private static int sDisplayId = Display.DEFAULT_DISPLAY; // synchronized on sActiveDisplayLock
private static Context sContext;
private static Handler sHandler;
@@ -112,6 +120,18 @@
}
/**
+ * Query current display active id and publish the change if any.
+ */
+ static void updateActiveDisplayId(int displayId) {
+ synchronized (sActiveDisplayLock) {
+ if (displayId != Display.DEFAULT_DISPLAY && sDisplayId != displayId) {
+ sDisplayId = displayId;
+ AudioSystem.setParameters("active_displayId=" + sDisplayId);
+ }
+ }
+ }
+
+ /**
* Uses android.hardware.display.DisplayManager.DisplayListener
*/
final static class AudioDisplayListener implements DisplayManager.DisplayListener {
@@ -126,6 +146,7 @@
@Override
public void onDisplayChanged(int displayId) {
+ updateActiveDisplayId(displayId);
updateOrientation();
}
}
diff --git a/services/core/java/com/android/server/audio/SpatializerHelper.java b/services/core/java/com/android/server/audio/SpatializerHelper.java
new file mode 100644
index 0000000..708d9e1
--- /dev/null
+++ b/services/core/java/com/android/server/audio/SpatializerHelper.java
@@ -0,0 +1,128 @@
+/*
+ * 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.audio;
+
+import android.annotation.NonNull;
+import android.media.AudioAttributes;
+import android.media.AudioDeviceAttributes;
+import android.media.AudioFormat;
+import android.media.ISpatializerCallback;
+import android.media.Spatializer;
+import android.os.RemoteCallbackList;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A helper class to manage Spatializer related functionality
+ */
+public class SpatializerHelper {
+
+ private static final String TAG = "AS.SpatializerHelper";
+
+ //---------------------------------------------------------------
+ // audio device compatibility / enabled
+
+ private final ArrayList<AudioDeviceAttributes> mCompatibleAudioDevices = new ArrayList<>(0);
+
+ /**
+ * @return a shallow copy of the list of compatible audio devices
+ */
+ synchronized @NonNull List<AudioDeviceAttributes> getCompatibleAudioDevices() {
+ return (List<AudioDeviceAttributes>) mCompatibleAudioDevices.clone();
+ }
+
+ synchronized void addCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ if (!mCompatibleAudioDevices.contains(ada)) {
+ mCompatibleAudioDevices.add(ada);
+ }
+ }
+
+ synchronized void removeCompatibleAudioDevice(@NonNull AudioDeviceAttributes ada) {
+ mCompatibleAudioDevices.remove(ada);
+ }
+
+ //------------------------------------------------------
+ // enabled state
+
+ // global state of feature
+ boolean mFeatureEnabled = false;
+ // initialized state, checked after each audio_server start
+ boolean mInitialized = false;
+
+ synchronized boolean isEnabled() {
+ return mFeatureEnabled;
+ }
+
+ synchronized boolean isAvailable() {
+ if (!mInitialized) {
+ return false;
+ }
+ // TODO check device compatibility
+ // ...
+ return true;
+ }
+
+ synchronized void setEnabled(boolean enabled) {
+ final boolean oldState = mFeatureEnabled;
+ mFeatureEnabled = enabled;
+ if (oldState != enabled) {
+ dispatchEnabledState();
+ }
+ }
+
+ public int getImmersiveAudioLevel() {
+ // TODO replace placeholder code with actual effect discovery
+ return Spatializer.SPATIALIZER_IMMERSIVE_LEVEL_NONE;
+ }
+
+ final RemoteCallbackList<ISpatializerCallback> mStateCallbacks =
+ new RemoteCallbackList<ISpatializerCallback>();
+
+ synchronized void registerStateCallback(
+ @NonNull ISpatializerCallback callback) {
+ mStateCallbacks.register(callback);
+ }
+
+ synchronized void unregisterStateCallback(
+ @NonNull ISpatializerCallback callback) {
+ mStateCallbacks.unregister(callback);
+ }
+
+ private synchronized void dispatchEnabledState() {
+ final int nbCallbacks = mStateCallbacks.beginBroadcast();
+ for (int i = 0; i < nbCallbacks; i++) {
+ try {
+ mStateCallbacks.getBroadcastItem(i)
+ .dispatchSpatializerEnabledChanged(mFeatureEnabled);
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error in dispatchSpatializerEnabledChanged", e);
+ }
+ }
+ mStateCallbacks.finishBroadcast();
+ }
+
+ //------------------------------------------------------
+ // virtualization capabilities
+ synchronized boolean canBeSpatialized(
+ @NonNull AudioAttributes attributes, @NonNull AudioFormat format) {
+ // TODO hook up to spatializer effect for query
+ return false;
+ }
+}
diff --git a/services/core/java/com/android/server/biometrics/AuthService.java b/services/core/java/com/android/server/biometrics/AuthService.java
index 0cd2e3d..b42f898 100644
--- a/services/core/java/com/android/server/biometrics/AuthService.java
+++ b/services/core/java/com/android/server/biometrics/AuthService.java
@@ -206,7 +206,7 @@
}
@Override
- public void authenticate(IBinder token, long sessionId, int userId,
+ public long authenticate(IBinder token, long sessionId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo)
throws RemoteException {
// Only allow internal clients to authenticate with a different userId.
@@ -223,18 +223,18 @@
if (!checkAppOps(callingUid, opPackageName, "authenticate()")) {
authenticateFastFail("Denied by app ops: " + opPackageName, receiver);
- return;
+ return -1;
}
if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
authenticateFastFail(
"Unable to authenticate, one or more null arguments", receiver);
- return;
+ return -1;
}
if (!Utils.isForeground(callingUid, callingPid)) {
authenticateFastFail("Caller is not foreground: " + opPackageName, receiver);
- return;
+ return -1;
}
if (promptInfo.containsTestConfigurations()) {
@@ -251,7 +251,7 @@
final long identity = Binder.clearCallingIdentity();
try {
- mBiometricService.authenticate(
+ return mBiometricService.authenticate(
token, sessionId, userId, receiver, opPackageName, promptInfo);
} finally {
Binder.restoreCallingIdentity(identity);
@@ -270,7 +270,7 @@
}
@Override
- public void cancelAuthentication(IBinder token, String opPackageName)
+ public void cancelAuthentication(IBinder token, String opPackageName, long requestId)
throws RemoteException {
checkPermission();
@@ -281,7 +281,7 @@
final long identity = Binder.clearCallingIdentity();
try {
- mBiometricService.cancelAuthentication(token, opPackageName);
+ mBiometricService.cancelAuthentication(token, opPackageName, requestId);
} finally {
Binder.restoreCallingIdentity(identity);
}
diff --git a/services/core/java/com/android/server/biometrics/AuthSession.java b/services/core/java/com/android/server/biometrics/AuthSession.java
index bdde980..0da6a1b 100644
--- a/services/core/java/com/android/server/biometrics/AuthSession.java
+++ b/services/core/java/com/android/server/biometrics/AuthSession.java
@@ -128,6 +128,7 @@
@VisibleForTesting final IBinder mToken;
// Info to be shown on BiometricDialog when all cookies are returned.
@VisibleForTesting final PromptInfo mPromptInfo;
+ private final long mRequestId;
private final long mOperationId;
private final int mUserId;
private final IBiometricSensorReceiver mSensorReceiver;
@@ -142,6 +143,8 @@
private @BiometricMultiSensorMode int mMultiSensorMode;
private @MultiSensorState int mMultiSensorState;
private int[] mSensors;
+ // TODO(b/197265902): merge into state
+ private boolean mCancelled;
// For explicit confirmation, do not send to keystore until the user has confirmed
// the authentication.
private byte[] mTokenEscrow;
@@ -162,6 +165,7 @@
@NonNull ClientDeathReceiver clientDeathReceiver,
@NonNull PreAuthInfo preAuthInfo,
@NonNull IBinder token,
+ long requestId,
long operationId,
int userId,
@NonNull IBiometricSensorReceiver sensorReceiver,
@@ -179,6 +183,7 @@
mClientDeathReceiver = clientDeathReceiver;
mPreAuthInfo = preAuthInfo;
mToken = token;
+ mRequestId = requestId;
mOperationId = operationId;
mUserId = userId;
mSensorReceiver = sensorReceiver;
@@ -187,6 +192,7 @@
mPromptInfo = promptInfo;
mDebugEnabled = debugEnabled;
mFingerprintSensorProperties = fingerprintSensorProperties;
+ mCancelled = false;
try {
mClientReceiver.asBinder().linkToDeath(this, 0 /* flags */);
@@ -233,7 +239,7 @@
Slog.v(TAG, "waiting for cooking for sensor: " + sensor.id);
}
sensor.goToStateWaitingForCookie(requireConfirmation, mToken, mOperationId,
- mUserId, mSensorReceiver, mOpPackageName, cookie,
+ mUserId, mSensorReceiver, mOpPackageName, mRequestId, cookie,
mPromptInfo.isAllowBackgroundAuthentication());
}
}
@@ -255,8 +261,9 @@
true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
- mOpPackageName,
mOperationId,
+ mOpPackageName,
+ mRequestId,
mMultiSensorMode);
} else if (!mPreAuthInfo.eligibleSensors.isEmpty()) {
// Some combination of biometric or biometric|credential is requested
@@ -270,6 +277,11 @@
}
void onCookieReceived(int cookie) {
+ if (mCancelled) {
+ Slog.w(TAG, "Received cookie but already cancelled (ignoring): " + cookie);
+ return;
+ }
+
for (BiometricSensor sensor : mPreAuthInfo.eligibleSensors) {
sensor.goToStateCookieReturnedIfCookieMatches(cookie);
}
@@ -301,8 +313,9 @@
mPreAuthInfo.shouldShowCredential(),
requireConfirmation,
mUserId,
- mOpPackageName,
mOperationId,
+ mOpPackageName,
+ mRequestId,
mMultiSensorMode);
mState = STATE_AUTH_STARTED;
} catch (RemoteException e) {
@@ -369,7 +382,7 @@
final boolean shouldCancel = filter.apply(sensor);
Slog.d(TAG, "sensorId: " + sensor.id + ", shouldCancel: " + shouldCancel);
if (shouldCancel) {
- sensor.goToStateCancelling(mToken, mOpPackageName);
+ sensor.goToStateCancelling(mToken, mOpPackageName, mRequestId);
}
} catch (RemoteException e) {
Slog.e(TAG, "Unable to cancel authentication");
@@ -425,8 +438,9 @@
true /* credentialAllowed */,
false /* requireConfirmation */,
mUserId,
- mOpPackageName,
mOperationId,
+ mOpPackageName,
+ mRequestId,
mMultiSensorMode);
} else {
mClientReceiver.onError(modality, error, vendorCode);
@@ -775,6 +789,8 @@
* @return true if this AuthSession is finished, e.g. should be set to null
*/
boolean onCancelAuthSession(boolean force) {
+ mCancelled = true;
+
final boolean authStarted = mState == STATE_AUTH_CALLED
|| mState == STATE_AUTH_STARTED
|| mState == STATE_AUTH_STARTED_UI_SHOWING;
@@ -820,6 +836,7 @@
return Utils.isCredentialRequested(mPromptInfo);
}
+ @VisibleForTesting
boolean allCookiesReceived() {
final int remainingCookies = mPreAuthInfo.numSensorsWaitingForCookie();
Slog.d(TAG, "Remaining cookies: " + remainingCookies);
@@ -839,6 +856,10 @@
return mState;
}
+ long getRequestId() {
+ return mRequestId;
+ }
+
private int statsModality() {
int modality = 0;
@@ -901,7 +922,9 @@
@Override
public String toString() {
return "State: " + mState
+ + ", cancelled: " + mCancelled
+ ", isCrypto: " + isCrypto()
- + ", PreAuthInfo: " + mPreAuthInfo;
+ + ", PreAuthInfo: " + mPreAuthInfo
+ + ", requestId: " + mRequestId;
}
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricSensor.java b/services/core/java/com/android/server/biometrics/BiometricSensor.java
index 8a842b5..0333c3e 100644
--- a/services/core/java/com/android/server/biometrics/BiometricSensor.java
+++ b/services/core/java/com/android/server/biometrics/BiometricSensor.java
@@ -108,11 +108,11 @@
void goToStateWaitingForCookie(boolean requireConfirmation, IBinder token, long sessionId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
- int cookie, boolean allowBackgroundAuthentication)
+ long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException {
mCookie = cookie;
impl.prepareForAuthentication(requireConfirmation, token,
- sessionId, userId, sensorReceiver, opPackageName, mCookie,
+ sessionId, userId, sensorReceiver, opPackageName, requestId, mCookie,
allowBackgroundAuthentication);
mSensorState = STATE_WAITING_FOR_COOKIE;
}
@@ -129,8 +129,9 @@
mSensorState = STATE_AUTHENTICATING;
}
- void goToStateCancelling(IBinder token, String opPackageName) throws RemoteException {
- impl.cancelAuthenticationFromService(token, opPackageName);
+ void goToStateCancelling(IBinder token, String opPackageName, long requestId)
+ throws RemoteException {
+ impl.cancelAuthenticationFromService(token, opPackageName, requestId);
mSensorState = STATE_CANCELING;
}
diff --git a/services/core/java/com/android/server/biometrics/BiometricService.java b/services/core/java/com/android/server/biometrics/BiometricService.java
index b1d300c..e0775d4 100644
--- a/services/core/java/com/android/server/biometrics/BiometricService.java
+++ b/services/core/java/com/android/server/biometrics/BiometricService.java
@@ -83,6 +83,7 @@
import java.util.Map;
import java.util.Random;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
/**
* System service that arbitrates the modality for BiometricPrompt to use.
@@ -115,6 +116,7 @@
final SettingObserver mSettingObserver;
private final List<EnabledOnKeyguardCallback> mEnabledOnKeyguardCallbacks;
private final Random mRandom = new Random();
+ @NonNull private final AtomicLong mRequestCounter;
@VisibleForTesting
IStatusBarService mStatusBarService;
@@ -194,6 +196,7 @@
SomeArgs args = (SomeArgs) msg.obj;
handleAuthenticate(
(IBinder) args.arg1 /* token */,
+ (long) args.arg6 /* requestId */,
(long) args.arg2 /* operationId */,
args.argi1 /* userid */,
(IBiometricServiceReceiver) args.arg3 /* receiver */,
@@ -204,7 +207,9 @@
}
case MSG_CANCEL_AUTHENTICATION: {
- handleCancelAuthentication();
+ SomeArgs args = (SomeArgs) msg.obj;
+ handleCancelAuthentication((long) args.arg3 /* requestId */);
+ args.recycle();
break;
}
@@ -683,13 +688,13 @@
}
@Override // Binder call
- public void authenticate(IBinder token, long operationId, int userId,
+ public long authenticate(IBinder token, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
checkInternalPermission();
if (token == null || receiver == null || opPackageName == null || promptInfo == null) {
Slog.e(TAG, "Unable to authenticate, one or more null arguments");
- return;
+ return -1;
}
if (!Utils.isValidAuthenticatorConfig(promptInfo)) {
@@ -706,6 +711,8 @@
}
}
+ final long requestId = mRequestCounter.incrementAndGet();
+
SomeArgs args = SomeArgs.obtain();
args.arg1 = token;
args.arg2 = operationId;
@@ -713,15 +720,23 @@
args.arg3 = receiver;
args.arg4 = opPackageName;
args.arg5 = promptInfo;
+ args.arg6 = requestId;
mHandler.obtainMessage(MSG_AUTHENTICATE, args).sendToTarget();
+
+ return requestId;
}
@Override // Binder call
- public void cancelAuthentication(IBinder token, String opPackageName) {
+ public void cancelAuthentication(IBinder token, String opPackageName, long requestId) {
checkInternalPermission();
- mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION).sendToTarget();
+ SomeArgs args = SomeArgs.obtain();
+ args.arg1 = token;
+ args.arg2 = opPackageName;
+ args.arg3 = requestId;
+
+ mHandler.obtainMessage(MSG_CANCEL_AUTHENTICATION, args).sendToTarget();
}
@Override // Binder call
@@ -1111,6 +1126,10 @@
return Settings.Secure.getInt(context.getContentResolver(),
CoexCoordinator.FACE_HAPTIC_DISABLE, 1) != 0;
}
+
+ public AtomicLong getRequestGenerator() {
+ return new AtomicLong(0);
+ }
}
/**
@@ -1136,6 +1155,7 @@
mEnabledOnKeyguardCallbacks = new ArrayList<>();
mSettingObserver = mInjector.getSettingObserver(context, mHandler,
mEnabledOnKeyguardCallbacks);
+ mRequestCounter = mInjector.getRequestGenerator();
// TODO(b/193089985) This logic lives here (outside of CoexCoordinator) so that it doesn't
// need to depend on context. We can remove this code once the advanced logic is enabled
@@ -1349,7 +1369,7 @@
mCurrentAuthSession.onCookieReceived(cookie);
}
- private void handleAuthenticate(IBinder token, long operationId, int userId,
+ private void handleAuthenticate(IBinder token, long requestId, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo) {
mHandler.post(() -> {
try {
@@ -1360,7 +1380,8 @@
final Pair<Integer, Integer> preAuthStatus = preAuthInfo.getPreAuthenticateStatus();
Slog.d(TAG, "handleAuthenticate: modality(" + preAuthStatus.first
- + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo);
+ + "), status(" + preAuthStatus.second + "), preAuthInfo: " + preAuthInfo
+ + " requestId: " + requestId);
if (preAuthStatus.second == BiometricConstants.BIOMETRIC_SUCCESS) {
// If BIOMETRIC_WEAK or BIOMETRIC_STRONG are allowed, but not enrolled, but
@@ -1372,8 +1393,8 @@
promptInfo.setAuthenticators(Authenticators.DEVICE_CREDENTIAL);
}
- authenticateInternal(token, operationId, userId, receiver, opPackageName,
- promptInfo, preAuthInfo);
+ authenticateInternal(token, requestId, operationId, userId, receiver,
+ opPackageName, promptInfo, preAuthInfo);
} else {
receiver.onError(preAuthStatus.first /* modality */,
preAuthStatus.second /* errorCode */,
@@ -1394,7 +1415,7 @@
* Note that this path is NOT invoked when the BiometricPrompt "Try again" button is pressed.
* In that case, see {@link #handleOnTryAgainPressed()}.
*/
- private void authenticateInternal(IBinder token, long operationId, int userId,
+ private void authenticateInternal(IBinder token, long requestId, long operationId, int userId,
IBiometricServiceReceiver receiver, String opPackageName, PromptInfo promptInfo,
PreAuthInfo preAuthInfo) {
Slog.d(TAG, "Creating authSession with authRequest: " + preAuthInfo);
@@ -1412,9 +1433,9 @@
final boolean debugEnabled = mInjector.isDebugEnabled(getContext(), userId);
mCurrentAuthSession = new AuthSession(getContext(), mStatusBarService, mSysuiReceiver,
- mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, operationId, userId,
- mBiometricSensorReceiver, receiver, opPackageName, promptInfo, debugEnabled,
- mInjector.getFingerprintSensorProperties(getContext()));
+ mKeyStore, mRandom, mClientDeathReceiver, preAuthInfo, token, requestId,
+ operationId, userId, mBiometricSensorReceiver, receiver, opPackageName, promptInfo,
+ debugEnabled, mInjector.getFingerprintSensorProperties(getContext()));
try {
mCurrentAuthSession.goToInitialState();
} catch (RemoteException e) {
@@ -1422,11 +1443,21 @@
}
}
- private void handleCancelAuthentication() {
+ private void handleCancelAuthentication(long requestId) {
if (mCurrentAuthSession == null) {
Slog.e(TAG, "handleCancelAuthentication: AuthSession is null");
return;
}
+ if (mCurrentAuthSession.getRequestId() != requestId) {
+ // TODO: actually cancel the operation
+ // This can happen if the operation has been queued, but is cancelled before
+ // it reaches the head of the scheduler. Consider it a programming error for now
+ // and ignore it.
+ Slog.e(TAG, "handleCancelAuthentication: AuthSession mismatch current requestId: "
+ + mCurrentAuthSession.getRequestId() + " cancel for: " + requestId
+ + " (ignoring cancellation)");
+ return;
+ }
final boolean finished = mCurrentAuthSession.onCancelAuthSession(false /* force */);
if (finished) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 3eb6f4a..9764a16 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -26,6 +26,8 @@
import com.android.internal.annotations.VisibleForTesting;
+import java.util.ArrayList;
+import java.util.List;
import java.util.NoSuchElementException;
/**
@@ -70,26 +72,32 @@
}
/** Holder for wrapping multiple handlers into a single Callback. */
- protected static class CompositeCallback implements Callback {
+ public static class CompositeCallback implements Callback {
@NonNull
- private final Callback[] mCallbacks;
+ private final List<Callback> mCallbacks;
public CompositeCallback(@NonNull Callback... callbacks) {
- mCallbacks = callbacks;
+ mCallbacks = new ArrayList<>();
+
+ for (Callback callback : callbacks) {
+ if (callback != null) {
+ mCallbacks.add(callback);
+ }
+ }
}
@Override
public final void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- for (int i = 0; i < mCallbacks.length; i++) {
- mCallbacks[i].onClientStarted(clientMonitor);
+ for (int i = 0; i < mCallbacks.size(); i++) {
+ mCallbacks.get(i).onClientStarted(clientMonitor);
}
}
@Override
public final void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
- for (int i = mCallbacks.length - 1; i >= 0; i--) {
- mCallbacks[i].onClientFinished(clientMonitor, success);
+ for (int i = mCallbacks.size() - 1; i >= 0; i--) {
+ mCallbacks.get(i).onClientFinished(clientMonitor, success);
}
}
}
@@ -101,6 +109,7 @@
private final int mSensorId; // sensorId as configured by the framework
@Nullable private IBinder mToken;
+ private long mRequestId;
@Nullable private ClientMonitorCallbackConverter mListener;
// Currently only used for authentication client. The cookie generated by BiometricService
// is never 0.
@@ -154,6 +163,7 @@
mSequentialId = sCount++;
mContext = context;
mToken = token;
+ mRequestId = -1;
mListener = listener;
mTargetUserId = userId;
mOwner = owner;
@@ -254,10 +264,33 @@
return mToken;
}
- public final int getSensorId() {
+ public int getSensorId() {
return mSensorId;
}
+ /** Unique request id. */
+ public final long getRequestId() {
+ return mRequestId;
+ }
+
+ /** If a unique id has been set via {@link #setRequestId(long)} */
+ public final boolean hasRequestId() {
+ return mRequestId > 0;
+ }
+
+ /**
+ * A unique identifier used to tie this operation to a request (i.e an API invocation).
+ *
+ * Subclasses should not call this method if this operation does not have a direct
+ * correspondence to a request and {@link #hasRequestId()} will return false.
+ */
+ protected final void setRequestId(long id) {
+ if (id <= 0) {
+ throw new IllegalArgumentException("request id must be positive");
+ }
+ mRequestId = id;
+ }
+
@VisibleForTesting
public Callback getCallback() {
return mCallback;
@@ -270,6 +303,7 @@
+ ", proto=" + getProtoEnum()
+ ", owner=" + getOwnerString()
+ ", cookie=" + getCookie()
+ + ", requestId=" + getRequestId()
+ ", userId=" + getTargetUserId() + "}";
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
index feb9e2a..361ec40 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BiometricScheduler.java
@@ -643,22 +643,18 @@
/**
* Requests to cancel authentication or detection.
* @param token from the caller, should match the token passed in when requesting authentication
+ * @param requestId the id returned when requesting authentication
*/
- public void cancelAuthenticationOrDetection(IBinder token) {
- if (mCurrentOperation == null) {
- Slog.e(getTag(), "Unable to cancel authentication, null operation");
- return;
- }
- final boolean isCorrectClient = isAuthenticationOrDetectionOperation(mCurrentOperation);
- final boolean tokenMatches = mCurrentOperation.mClientMonitor.getToken() == token;
+ public void cancelAuthenticationOrDetection(IBinder token, long requestId) {
+ Slog.d(getTag(), "cancelAuthenticationOrDetection, requestId: " + requestId
+ + " current: " + mCurrentOperation
+ + " stack size: " + mPendingOperations.size());
- Slog.d(getTag(), "cancelAuthenticationOrDetection, isCorrectClient: " + isCorrectClient
- + ", tokenMatches: " + tokenMatches);
-
- if (isCorrectClient && tokenMatches) {
+ if (mCurrentOperation != null
+ && canCancelAuthOperation(mCurrentOperation, token, requestId)) {
Slog.d(getTag(), "Cancelling: " + mCurrentOperation);
cancelInternal(mCurrentOperation);
- } else if (!isCorrectClient) {
+ } else {
// Look through the current queue for all authentication clients for the specified
// token, and mark them as STATE_WAITING_IN_QUEUE_CANCELING. Note that we're marking
// all of them, instead of just the first one, since the API surface currently doesn't
@@ -666,8 +662,7 @@
// process. However, this generally does not happen anyway, and would be a class of
// bugs on its own.
for (Operation operation : mPendingOperations) {
- if (isAuthenticationOrDetectionOperation(operation)
- && operation.mClientMonitor.getToken() == token) {
+ if (canCancelAuthOperation(operation, token, requestId)) {
Slog.d(getTag(), "Marking " + operation
+ " as STATE_WAITING_IN_QUEUE_CANCELING");
operation.mState = Operation.STATE_WAITING_IN_QUEUE_CANCELING;
@@ -676,10 +671,26 @@
}
}
- private boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) {
- final boolean isAuthentication = operation.mClientMonitor
- instanceof AuthenticationConsumer;
- final boolean isDetection = operation.mClientMonitor instanceof DetectionConsumer;
+ private static boolean canCancelAuthOperation(Operation operation, IBinder token,
+ long requestId) {
+ // TODO: restrict callers that can cancel without requestId (negative value)?
+ return isAuthenticationOrDetectionOperation(operation)
+ && operation.mClientMonitor.getToken() == token
+ && isMatchingRequestId(operation, requestId);
+ }
+
+ // By default, monitors are not associated with a request id to retain the original
+ // behavior (i.e. if no requestId is explicitly set then assume it matches)
+ private static boolean isMatchingRequestId(Operation operation, long requestId) {
+ return !operation.mClientMonitor.hasRequestId()
+ || operation.mClientMonitor.getRequestId() == requestId;
+ }
+
+ private static boolean isAuthenticationOrDetectionOperation(@NonNull Operation operation) {
+ final boolean isAuthentication =
+ operation.mClientMonitor instanceof AuthenticationConsumer;
+ final boolean isDetection =
+ operation.mClientMonitor instanceof DetectionConsumer;
return isAuthentication || isDetection;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
index a15e14b..9191b8b 100644
--- a/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollClient.java
@@ -31,7 +31,7 @@
/**
* A class to keep track of the enrollment state for a given client.
*/
-public abstract class EnrollClient<T> extends AcquisitionClient<T> {
+public abstract class EnrollClient<T> extends AcquisitionClient<T> implements EnrollmentModifier {
private static final String TAG = "Biometrics/EnrollClient";
@@ -40,6 +40,7 @@
protected final BiometricUtils mBiometricUtils;
private long mEnrollmentStartTimeMs;
+ private final boolean mHasEnrollmentsBeforeStarting;
/**
* @return true if the user has already enrolled the maximum number of templates.
@@ -56,6 +57,18 @@
mBiometricUtils = utils;
mHardwareAuthToken = Arrays.copyOf(hardwareAuthToken, hardwareAuthToken.length);
mTimeoutSec = timeoutSec;
+ mHasEnrollmentsBeforeStarting = hasEnrollments();
+ }
+
+ @Override
+ public boolean hasEnrollmentStateChanged() {
+ final boolean hasEnrollmentsNow = hasEnrollments();
+ return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
+ }
+
+ @Override
+ public boolean hasEnrollments() {
+ return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
}
public void onEnrollResult(BiometricAuthenticator.Identifier identifier, int remaining) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java
new file mode 100644
index 0000000..c2f909b
--- /dev/null
+++ b/services/core/java/com/android/server/biometrics/sensors/EnrollmentModifier.java
@@ -0,0 +1,39 @@
+/*
+ * 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.biometrics.sensors;
+
+/**
+ * Interface for {@link BaseClientMonitor} subclasses that affect the state of enrollment.
+ */
+public interface EnrollmentModifier {
+
+ /**
+ * Callers should typically check this after
+ * {@link BaseClientMonitor.Callback#onClientFinished(BaseClientMonitor, boolean)}
+ *
+ * @return true if the user has gone from:
+ * 1) none-enrolled --> enrolled
+ * 2) enrolled --> none-enrolled
+ * but NOT any-enrolled --> more-enrolled
+ */
+ boolean hasEnrollmentStateChanged();
+
+ /**
+ * @return true if the user has any enrollments
+ */
+ boolean hasEnrollments();
+}
diff --git a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
index 282261e..579dfd6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/InternalCleanupClient.java
@@ -40,7 +40,8 @@
* {@link #onRemoved(BiometricAuthenticator.Identifier, int)} returns true/
*/
public abstract class InternalCleanupClient<S extends BiometricAuthenticator.Identifier, T>
- extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer {
+ extends HalClientMonitor<T> implements EnumerateConsumer, RemovalConsumer,
+ EnrollmentModifier {
private static final String TAG = "Biometrics/InternalCleanupClient";
@@ -61,6 +62,7 @@
private final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds;
private final List<S> mEnrolledList;
+ private final boolean mHasEnrollmentsBeforeStarting;
private BaseClientMonitor mCurrentTask;
private final Callback mEnumerateCallback = new Callback() {
@@ -115,6 +117,7 @@
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
mEnrolledList = enrolledList;
+ mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
}
private void startCleanupUnknownHalTemplates() {
@@ -166,6 +169,18 @@
}
@Override
+ public boolean hasEnrollmentStateChanged() {
+ final boolean hasEnrollmentsNow = !mBiometricUtils
+ .getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
+ return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
+ }
+
+ @Override
+ public boolean hasEnrollments() {
+ return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
+ }
+
+ @Override
public void onEnumerationResult(BiometricAuthenticator.Identifier identifier,
int remaining) {
if (!(mCurrentTask instanceof InternalEnumerateClient)) {
diff --git a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
index 383efce..2a6677e 100644
--- a/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/RemovalClient.java
@@ -33,12 +33,13 @@
* A class to keep track of the remove state for a given client.
*/
public abstract class RemovalClient<S extends BiometricAuthenticator.Identifier, T>
- extends HalClientMonitor<T> implements RemovalConsumer {
+ extends HalClientMonitor<T> implements RemovalConsumer, EnrollmentModifier {
private static final String TAG = "Biometrics/RemovalClient";
private final BiometricUtils<S> mBiometricUtils;
private final Map<Integer, Long> mAuthenticatorIds;
+ private final boolean mHasEnrollmentsBeforeStarting;
public RemovalClient(@NonNull Context context, @NonNull LazyDaemon<T> lazyDaemon,
@NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener,
@@ -49,6 +50,7 @@
BiometricsProtoEnums.CLIENT_UNKNOWN);
mBiometricUtils = utils;
mAuthenticatorIds = authenticatorIds;
+ mHasEnrollmentsBeforeStarting = !utils.getBiometricsForUser(context, userId).isEmpty();
}
@Override
@@ -91,6 +93,18 @@
}
@Override
+ public boolean hasEnrollmentStateChanged() {
+ final boolean hasEnrollmentsNow = !mBiometricUtils
+ .getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
+ return hasEnrollmentsNow != mHasEnrollmentsBeforeStarting;
+ }
+
+ @Override
+ public boolean hasEnrollments() {
+ return !mBiometricUtils.getBiometricsForUser(getContext(), getTargetUserId()).isEmpty();
+ }
+
+ @Override
public int getProtoEnum() {
return BiometricsProto.CM_REMOVE;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
index 0bc4f1b..b2fd46d1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceAuthenticator.java
@@ -61,10 +61,11 @@
@Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
- String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+ String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException {
mFaceService.prepareForAuthentication(mSensorId, requireConfirmation, token, operationId,
- userId, sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
+ userId, sensorReceiver, opPackageName, requestId, cookie,
+ allowBackgroundAuthentication);
}
@Override
@@ -73,9 +74,9 @@
}
@Override
- public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException {
- mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName);
+ mFaceService.cancelAuthenticationFromService(mSensorId, token, opPackageName, requestId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
index 12d6b08..675ee545 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/FaceService.java
@@ -250,7 +250,7 @@
}
@Override // Binder call
- public void authenticate(final IBinder token, final long operationId, int userId,
+ public long authenticate(final IBinder token, final long operationId, int userId,
final IFaceServiceReceiver receiver, final String opPackageName,
boolean isKeyguardBypassEnabled) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -270,38 +270,38 @@
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
- return;
+ return -1;
}
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+ return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
0 /* cookie */,
new ClientMonitorCallbackConverter(receiver), opPackageName, restricted,
statsClient, isKeyguard, isKeyguardBypassEnabled);
}
@Override // Binder call
- public void detectFace(final IBinder token, final int userId,
+ public long detectFace(final IBinder token, final int userId,
final IFaceServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFace called from non-sysui package: " + opPackageName);
- return;
+ return -1;
}
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFace invoked when user is not encrypted or lockdown");
- return;
+ return -1;
}
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFace");
- return;
+ return -1;
}
- provider.second.scheduleFaceDetect(provider.first, token, userId,
+ return provider.second.scheduleFaceDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName,
BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@@ -309,8 +309,8 @@
@Override // Binder call
public void prepareForAuthentication(int sensorId, boolean requireConfirmation,
IBinder token, long operationId, int userId,
- IBiometricSensorReceiver sensorReceiver, String opPackageName, int cookie,
- boolean allowBackgroundAuthentication) {
+ IBiometricSensorReceiver sensorReceiver, String opPackageName, long requestId,
+ int cookie, boolean allowBackgroundAuthentication) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -322,9 +322,9 @@
final boolean isKeyguardBypassEnabled = false; // only valid for keyguard clients
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
- new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
- isKeyguardBypassEnabled);
+ new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
+ restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
}
@Override // Binder call
@@ -341,7 +341,8 @@
}
@Override // Binder call
- public void cancelAuthentication(final IBinder token, final String opPackageName) {
+ public void cancelAuthentication(final IBinder token, final String opPackageName,
+ final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
@@ -350,11 +351,12 @@
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.second.cancelAuthentication(provider.first, token, requestId);
}
@Override // Binder call
- public void cancelFaceDetect(final IBinder token, final String opPackageName) {
+ public void cancelFaceDetect(final IBinder token, final String opPackageName,
+ final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "cancelFaceDetect called from non-sysui package: "
@@ -368,12 +370,12 @@
return;
}
- provider.second.cancelFaceDetect(provider.first, token);
+ provider.second.cancelFaceDetect(provider.first, token, requestId);
}
@Override // Binder call
public void cancelAuthenticationFromService(int sensorId, final IBinder token,
- final String opPackageName) {
+ final String opPackageName, final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -382,7 +384,7 @@
return;
}
- provider.cancelAuthentication(sensorId, token);
+ provider.cancelAuthentication(sensorId, token, requestId);
}
@Override // Binder call
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
index 93ab1b6..e099ba3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/ServiceProvider.java
@@ -101,18 +101,23 @@
void cancelEnrollment(int sensorId, @NonNull IBinder token);
- void scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId,
+ long scheduleFaceDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
int statsClient);
- void cancelFaceDetect(int sensorId, @NonNull IBinder token);
+ void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId);
- void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+ long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
- void cancelAuthentication(int sensorId, @NonNull IBinder token);
+ void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+ int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled);
+
+ void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
void scheduleRemove(int sensorId, @NonNull IBinder token, int faceId, int userId,
@NonNull IFaceServiceReceiver receiver, @NonNull String opPackageName);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
index d66a279..cbceba6 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceAuthenticationClient.java
@@ -65,7 +65,8 @@
@FaceManager.FaceAcquired private int mLastAcquire = FaceManager.FACE_ACQUIRED_UNKNOWN;
FaceAuthenticationClient(@NonNull Context context,
- @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull UsageStats usageStats,
@@ -76,6 +77,7 @@
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
isKeyguardBypassEnabled);
+ setRequestId(requestId);
mUsageStats = usageStats;
mLockoutCache = lockoutCache;
mNotificationManager = context.getSystemService(NotificationManager.class);
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
index 1e73ac5..2ef0911 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceDetectClient.java
@@ -43,11 +43,13 @@
@Nullable private ICancellationSignal mCancellationSignal;
public FaceDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
- @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull IBinder token, long requestId,
+ @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId, boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FACE,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+ setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
index 718b9da..4bae775 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/aidl/FaceProvider.java
@@ -65,6 +65,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Provider for a single instance of the {@link IFace} HAL.
@@ -83,6 +84,8 @@
@NonNull private final UsageStats mUsageStats;
@NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
+ // for requests that do not use biometric prompt
+ @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@Nullable private IFace mDaemon;
@@ -110,8 +113,8 @@
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler()
- .cancelAuthenticationOrDetection(client.getToken());
+ mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
}
@@ -356,34 +359,39 @@
}
@Override
- public void scheduleFaceDetect(int sensorId, @NonNull IBinder token,
+ public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
int userId, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, int statsClient) {
+ final long id = mRequestCounter.incrementAndGet();
+
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceDetectClient client = new FaceDetectClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, callback, userId, opPackageName,
+ mSensors.get(sensorId).getLazySession(),
+ token, id, callback, userId, opPackageName,
sensorId, isStrongBiometric, statsClient);
scheduleForSensor(sensorId, client);
});
+
+ return id;
}
@Override
- public void cancelFaceDetect(int sensorId, @NonNull IBinder token) {
+ public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler()
- .cancelAuthenticationOrDetection(token));
+ .cancelAuthenticationOrDetection(token, requestId));
}
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
- @NonNull String opPackageName, boolean restricted, int statsClient,
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(
- mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
- operationId, restricted, opPackageName, cookie,
+ mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
+ userId, operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mUsageStats, mSensors.get(sensorId).getLockoutCache(),
allowBackgroundAuthentication, isKeyguardBypassEnabled);
@@ -392,9 +400,23 @@
}
@Override
- public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+ public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
+ final long id = mRequestCounter.incrementAndGet();
+
+ scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
+ opPackageName, id, restricted, statsClient,
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
+
+ return id;
+ }
+
+ @Override
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler()
- .cancelAuthenticationOrDetection(token));
+ .cancelAuthenticationOrDetection(token, requestId));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
index d05333d..f4dcbbb 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/Face10.java
@@ -87,6 +87,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Supports a single instance of the {@link android.hardware.biometrics.face.V1_0} or its extended
@@ -115,6 +116,8 @@
@NonNull private final Map<Integer, Long> mAuthenticatorIds;
@Nullable private IBiometricsFace mDaemon;
@NonNull private final HalResultController mHalResultController;
+ // for requests that do not use biometric prompt
+ @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL;
private final int mSensorId;
private final List<Long> mGeneratedChallengeCount = new ArrayList<>();
@@ -605,7 +608,7 @@
}
@Override
- public void scheduleFaceDetect(int sensorId, @NonNull IBinder token,
+ public long scheduleFaceDetect(int sensorId, @NonNull IBinder token,
int userId, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, int statsClient) {
throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
@@ -613,7 +616,7 @@
}
@Override
- public void cancelFaceDetect(int sensorId, @NonNull IBinder token) {
+ public void cancelFaceDetect(int sensorId, @NonNull IBinder token, long requestId) {
throw new IllegalStateException("Face detect not supported by IBiometricsFace@1.0. Did you"
+ "forget to check the supportsFaceDetection flag?");
}
@@ -621,26 +624,38 @@
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
- @NonNull String opPackageName, boolean restricted, int statsClient,
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorId);
final FaceAuthenticationClient client = new FaceAuthenticationClient(mContext,
- mLazyDaemon, token, receiver, userId, operationId, restricted, opPackageName,
- cookie, false /* requireConfirmation */, mSensorId, isStrongBiometric,
- statsClient, mLockoutTracker, mUsageStats, allowBackgroundAuthentication,
- isKeyguardBypassEnabled);
+ mLazyDaemon, token, requestId, receiver, userId, operationId, restricted,
+ opPackageName, cookie, false /* requireConfirmation */, mSensorId,
+ isStrongBiometric, statsClient, mLockoutTracker, mUsageStats,
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
mScheduler.scheduleClientMonitor(client);
});
}
@Override
- public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
- mHandler.post(() -> {
- mScheduler.cancelAuthenticationOrDetection(token);
- });
+ public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter receiver,
+ @NonNull String opPackageName, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication, boolean isKeyguardBypassEnabled) {
+ final long id = mRequestCounter.incrementAndGet();
+
+ scheduleAuthenticate(sensorId, token, operationId, userId, cookie, receiver,
+ opPackageName, id, restricted, statsClient,
+ allowBackgroundAuthentication, isKeyguardBypassEnabled);
+
+ return id;
+ }
+
+ @Override
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
+ mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
index 33950af..40f2801 100644
--- a/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/face/hidl/FaceAuthenticationClient.java
@@ -57,7 +57,8 @@
private int mLastAcquire;
FaceAuthenticationClient(@NonNull Context context,
- @NonNull LazyDaemon<IBiometricsFace> lazyDaemon, @NonNull IBinder token,
+ @NonNull LazyDaemon<IBiometricsFace> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, String owner, int cookie, boolean requireConfirmation, int sensorId,
boolean isStrongBiometric, int statsClient, @NonNull LockoutTracker lockoutTracker,
@@ -68,6 +69,7 @@
BiometricsProtoEnums.MODALITY_FACE, statsClient, null /* taskStackListener */,
lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
isKeyguardBypassEnabled);
+ setRequestId(requestId);
mUsageStats = usageStats;
final Resources resources = getContext().getResources();
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
index 1e59429..52d887a 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintAuthenticator.java
@@ -61,10 +61,10 @@
@Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long operationId, int userId, IBiometricSensorReceiver sensorReceiver,
- String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+ String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException {
mFingerprintService.prepareForAuthentication(mSensorId, token, operationId, userId,
- sensorReceiver, opPackageName, cookie, allowBackgroundAuthentication);
+ sensorReceiver, opPackageName, requestId, cookie, allowBackgroundAuthentication);
}
@Override
@@ -73,9 +73,10 @@
}
@Override
- public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException {
- mFingerprintService.cancelAuthenticationFromService(mSensorId, token, opPackageName);
+ mFingerprintService.cancelAuthenticationFromService(
+ mSensorId, token, opPackageName, requestId);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
index 183fabd..f35bb7f 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintService.java
@@ -35,6 +35,7 @@
import android.app.AppOpsManager;
import android.content.Context;
import android.content.pm.PackageManager;
+import android.content.pm.UserInfo;
import android.hardware.biometrics.BiometricManager;
import android.hardware.biometrics.BiometricPrompt;
import android.hardware.biometrics.BiometricsProtoEnums;
@@ -62,11 +63,13 @@
import android.os.CancellationSignal;
import android.os.Handler;
import android.os.IBinder;
+import android.os.Looper;
import android.os.Process;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.os.UserHandle;
+import android.os.UserManager;
import android.provider.Settings;
import android.util.EventLog;
import android.util.Pair;
@@ -111,6 +114,7 @@
private final FingerprintServiceWrapper mServiceWrapper;
@NonNull private final List<ServiceProvider> mServiceProviders;
@NonNull private final FingerprintStateCallback mFingerprintStateCallback;
+ @NonNull private final Handler mHandler;
@GuardedBy("mLock")
@NonNull private final RemoteCallbackList<IFingerprintAuthenticatorsRegisteredCallback>
@@ -125,6 +129,37 @@
*/
public void registerFingerprintStateListener(@NonNull IFingerprintStateListener listener) {
mFingerprintStateCallback.registerFingerprintStateListener(listener);
+ broadcastCurrentEnrollmentState(listener);
+ }
+
+ /**
+ * @param listener if non-null, notifies only this listener. if null, notifies all listeners
+ * in {@link FingerprintStateCallback}. This is slightly ugly, but reduces
+ * redundant code.
+ */
+ private void broadcastCurrentEnrollmentState(@Nullable IFingerprintStateListener listener) {
+ final UserManager um = UserManager.get(getContext());
+ synchronized (mLock) {
+ // Update the new listener with current state of all sensors
+ for (FingerprintSensorPropertiesInternal prop : mSensorProps) {
+ final ServiceProvider provider = getProviderForSensor(prop.sensorId);
+ for (UserInfo userInfo : um.getAliveUsers()) {
+ final boolean enrolled = !provider
+ .getEnrolledFingerprints(prop.sensorId, userInfo.id).isEmpty();
+
+ // Defer this work and allow the loop to release the lock sooner
+ mHandler.post(() -> {
+ if (listener != null) {
+ mFingerprintStateCallback.notifyFingerprintEnrollmentStateChanged(
+ listener, userInfo.id, prop.sensorId, enrolled);
+ } else {
+ mFingerprintStateCallback.notifyAllFingerprintEnrollmentStateChanged(
+ userInfo.id, prop.sensorId, enrolled);
+ }
+ });
+ }
+ }
+ }
}
/**
@@ -143,8 +178,7 @@
return null;
}
- return provider.createTestSession(sensorId, callback, mFingerprintStateCallback,
- opPackageName);
+ return provider.createTestSession(sensorId, callback, opPackageName);
}
@Override
@@ -227,7 +261,7 @@
}
provider.second.scheduleEnroll(provider.first, token, hardwareAuthToken, userId,
- receiver, opPackageName, enrollReason, mFingerprintStateCallback);
+ receiver, opPackageName, enrollReason);
}
@Override // Binder call
@@ -245,7 +279,7 @@
@SuppressWarnings("deprecation")
@Override // Binder call
- public void authenticate(final IBinder token, final long operationId,
+ public long authenticate(final IBinder token, final long operationId,
final int sensorId, final int userId, final IFingerprintServiceReceiver receiver,
final String opPackageName) {
final int callingUid = Binder.getCallingUid();
@@ -255,7 +289,7 @@
if (!canUseFingerprint(opPackageName, true /* requireForeground */, callingUid,
callingPid, callingUserId)) {
Slog.w(TAG, "Authenticate rejecting package: " + opPackageName);
- return;
+ return -1;
}
// Keyguard check must be done on the caller's binder identity, since it also checks
@@ -270,7 +304,7 @@
// SafetyNet for b/79776455
EventLog.writeEvent(0x534e4554, "79776455");
Slog.e(TAG, "Authenticate invoked when user is encrypted or lockdown");
- return;
+ return -1;
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -290,7 +324,7 @@
}
if (provider == null) {
Slog.w(TAG, "Null provider for authenticate");
- return;
+ return -1;
}
final FingerprintSensorPropertiesInternal sensorProps =
@@ -299,18 +333,17 @@
&& sensorProps != null && sensorProps.isAnyUdfpsType()) {
identity = Binder.clearCallingIdentity();
try {
- authenticateWithPrompt(operationId, sensorProps, userId, receiver);
+ return authenticateWithPrompt(operationId, sensorProps, userId, receiver);
} finally {
Binder.restoreCallingIdentity(identity);
}
- } else {
- provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
- 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
- restricted, statsClient, isKeyguard, mFingerprintStateCallback);
}
+ return provider.second.scheduleAuthenticate(provider.first, token, operationId, userId,
+ 0 /* cookie */, new ClientMonitorCallbackConverter(receiver), opPackageName,
+ restricted, statsClient, isKeyguard);
}
- private void authenticateWithPrompt(
+ private long authenticateWithPrompt(
final long operationId,
@NonNull final FingerprintSensorPropertiesInternal props,
final int userId,
@@ -387,41 +420,41 @@
}
};
- biometricPrompt.authenticateUserForOperation(
+ return biometricPrompt.authenticateUserForOperation(
new CancellationSignal(), executor, promptCallback, userId, operationId);
}
@Override
- public void detectFingerprint(final IBinder token, final int userId,
+ public long detectFingerprint(final IBinder token, final int userId,
final IFingerprintServiceReceiver receiver, final String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "detectFingerprint called from non-sysui package: " + opPackageName);
- return;
+ return -1;
}
if (!Utils.isUserEncryptedOrLockdown(mLockPatternUtils, userId)) {
// If this happens, something in KeyguardUpdateMonitor is wrong. This should only
// ever be invoked when the user is encrypted or lockdown.
Slog.e(TAG, "detectFingerprint invoked when user is not encrypted or lockdown");
- return;
+ return -1;
}
final Pair<Integer, ServiceProvider> provider = getSingleProvider();
if (provider == null) {
Slog.w(TAG, "Null provider for detectFingerprint");
- return;
+ return -1;
}
- provider.second.scheduleFingerDetect(provider.first, token, userId,
+ return provider.second.scheduleFingerDetect(provider.first, token, userId,
new ClientMonitorCallbackConverter(receiver), opPackageName,
- BiometricsProtoEnums.CLIENT_KEYGUARD, mFingerprintStateCallback);
+ BiometricsProtoEnums.CLIENT_KEYGUARD);
}
@Override // Binder call
public void prepareForAuthentication(int sensorId, IBinder token, long operationId,
int userId, IBiometricSensorReceiver sensorReceiver, String opPackageName,
- int cookie, boolean allowBackgroundAuthentication) {
+ long requestId, int cookie, boolean allowBackgroundAuthentication) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
final ServiceProvider provider = getProviderForSensor(sensorId);
@@ -432,9 +465,9 @@
final boolean restricted = true; // BiometricPrompt is always restricted
provider.scheduleAuthenticate(sensorId, token, operationId, userId, cookie,
- new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, restricted,
- BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT, allowBackgroundAuthentication,
- mFingerprintStateCallback);
+ new ClientMonitorCallbackConverter(sensorReceiver), opPackageName, requestId,
+ restricted, BiometricsProtoEnums.CLIENT_BIOMETRIC_PROMPT,
+ allowBackgroundAuthentication);
}
@Override // Binder call
@@ -452,7 +485,8 @@
@Override // Binder call
- public void cancelAuthentication(final IBinder token, final String opPackageName) {
+ public void cancelAuthentication(final IBinder token, final String opPackageName,
+ long requestId) {
final int callingUid = Binder.getCallingUid();
final int callingPid = Binder.getCallingPid();
final int callingUserId = UserHandle.getCallingUserId();
@@ -469,11 +503,12 @@
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.second.cancelAuthentication(provider.first, token, requestId);
}
@Override // Binder call
- public void cancelFingerprintDetect(final IBinder token, final String opPackageName) {
+ public void cancelFingerprintDetect(final IBinder token, final String opPackageName,
+ final long requestId) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
if (!Utils.isKeyguard(getContext(), opPackageName)) {
Slog.w(TAG, "cancelFingerprintDetect called from non-sysui package: "
@@ -489,12 +524,12 @@
return;
}
- provider.second.cancelAuthentication(provider.first, token);
+ provider.second.cancelAuthentication(provider.first, token, requestId);
}
@Override // Binder call
public void cancelAuthenticationFromService(final int sensorId, final IBinder token,
- final String opPackageName) {
+ final String opPackageName, final long requestId) {
Utils.checkPermission(getContext(), MANAGE_BIOMETRIC);
@@ -506,7 +541,7 @@
return;
}
- provider.cancelAuthentication(sensorId, token);
+ provider.cancelAuthentication(sensorId, token, requestId);
}
@Override // Binder call
@@ -686,27 +721,6 @@
.isEmpty();
}
- @Override // Binder call
- public boolean hasEnrolledTemplatesForAnySensor(int userId,
- @NonNull List<FingerprintSensorPropertiesInternal> sensors,
- @NonNull String opPackageName) {
- Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
-
- for (FingerprintSensorPropertiesInternal prop : sensors) {
- final ServiceProvider provider = getProviderForSensor(prop.sensorId);
- if (provider == null) {
- Slog.w(TAG, "Null provider for sensorId: " + prop.sensorId
- + ", caller: " + opPackageName);
- continue;
- }
-
- if (!provider.getEnrolledFingerprints(prop.sensorId, userId).isEmpty()) {
- return true;
- }
- }
- return false;
- }
-
public boolean hasEnrolledFingerprints(int sensorId, int userId, String opPackageName) {
Utils.checkPermission(getContext(), USE_BIOMETRIC_INTERNAL);
@@ -796,10 +810,12 @@
&& Settings.Secure.getIntForUser(getContext().getContentResolver(),
Fingerprint21UdfpsMock.CONFIG_ENABLE_TEST_UDFPS, 0 /* default */,
UserHandle.USER_CURRENT) != 0) {
- fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(), hidlSensor,
+ fingerprint21 = Fingerprint21UdfpsMock.newInstance(getContext(),
+ mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
} else {
- fingerprint21 = Fingerprint21.newInstance(getContext(), hidlSensor,
+ fingerprint21 = Fingerprint21.newInstance(getContext(),
+ mFingerprintStateCallback, hidlSensor,
mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
mServiceProviders.add(fingerprint21);
@@ -822,8 +838,9 @@
try {
final SensorProps[] props = fp.getSensorProps();
final FingerprintProvider provider =
- new FingerprintProvider(getContext(), props, instance,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ new FingerprintProvider(getContext(), mFingerprintStateCallback, props,
+ instance, mLockoutResetDispatcher,
+ mGestureAvailabilityDispatcher);
mServiceProviders.add(provider);
} catch (RemoteException e) {
Slog.e(TAG, "Remote exception in getSensorProps: " + fqName);
@@ -877,6 +894,7 @@
}
}
+ broadcastCurrentEnrollmentState(null); // broadcasts to all listeners
broadcastAllAuthenticatorsRegistered();
});
}
@@ -974,6 +992,7 @@
mFingerprintStateCallback = new FingerprintStateCallback();
mAuthenticatorsRegisteredCallbacks = new RemoteCallbackList<>();
mSensorProps = new ArrayList<>();
+ mHandler = new Handler(Looper.getMainLooper());
}
// Notifies the callbacks that all of the authenticators have been registered and removes the
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
index 5f998d8..0050a89 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallback.java
@@ -23,6 +23,7 @@
import static android.hardware.fingerprint.FingerprintStateListener.STATE_KEYGUARD_AUTH;
import android.annotation.NonNull;
+import android.content.Context;
import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IFingerprintStateListener;
import android.os.RemoteException;
@@ -31,6 +32,9 @@
import com.android.server.biometrics.Utils;
import com.android.server.biometrics.sensors.AuthenticationClient;
import com.android.server.biometrics.sensors.BaseClientMonitor;
+import com.android.server.biometrics.sensors.EnrollClient;
+import com.android.server.biometrics.sensors.EnrollmentModifier;
+import com.android.server.biometrics.sensors.RemovalConsumer;
import com.android.server.biometrics.sensors.fingerprint.hidl.FingerprintEnrollClient;
import java.util.concurrent.CopyOnWriteArrayList;
@@ -39,9 +43,11 @@
* A callback for receiving notifications about changes in fingerprint state.
*/
public class FingerprintStateCallback implements BaseClientMonitor.Callback {
- private @FingerprintStateListener.State int mFingerprintState;
+
@NonNull private final CopyOnWriteArrayList<IFingerprintStateListener>
- mFingerprintStateListeners = new CopyOnWriteArrayList<>();
+ mFingerprintStateListeners = new CopyOnWriteArrayList<>();
+
+ private @FingerprintStateListener.State int mFingerprintState;
public FingerprintStateCallback() {
mFingerprintState = STATE_IDLE;
@@ -54,8 +60,9 @@
@Override
public void onClientStarted(@NonNull BaseClientMonitor client) {
final int previousFingerprintState = mFingerprintState;
+
if (client instanceof AuthenticationClient) {
- AuthenticationClient authClient = (AuthenticationClient) client;
+ final AuthenticationClient<?> authClient = (AuthenticationClient<?>) client;
if (authClient.isKeyguard()) {
mFingerprintState = STATE_KEYGUARD_AUTH;
} else if (authClient.isBiometricPrompt()) {
@@ -70,6 +77,7 @@
"Other authentication client: " + Utils.getClientName(client));
mFingerprintState = STATE_IDLE;
}
+
Slog.d(FingerprintService.TAG, "Fps state updated from " + previousFingerprintState
+ " to " + mFingerprintState + ", client " + client);
notifyFingerprintStateListeners(mFingerprintState);
@@ -81,6 +89,18 @@
Slog.d(FingerprintService.TAG,
"Client finished, fps state updated to " + mFingerprintState + ", client "
+ client);
+
+ if (client instanceof EnrollmentModifier) {
+ EnrollmentModifier enrollmentModifier = (EnrollmentModifier) client;
+ final boolean enrollmentStateChanged = enrollmentModifier.hasEnrollmentStateChanged();
+ Slog.d(FingerprintService.TAG, "Enrollment state changed: " + enrollmentStateChanged);
+ if (enrollmentStateChanged) {
+ notifyAllFingerprintEnrollmentStateChanged(client.getTargetUserId(),
+ client.getSensorId(),
+ enrollmentModifier.hasEnrollments());
+ }
+ }
+
notifyFingerprintStateListeners(mFingerprintState);
}
@@ -95,6 +115,32 @@
}
/**
+ * This should be invoked when:
+ * 1) Enrolled --> None-enrolled
+ * 2) None-enrolled --> enrolled
+ * 3) HAL becomes ready
+ * 4) Listener is registered
+ */
+ void notifyAllFingerprintEnrollmentStateChanged(int userId, int sensorId,
+ boolean hasEnrollments) {
+ for (IFingerprintStateListener listener : mFingerprintStateListeners) {
+ notifyFingerprintEnrollmentStateChanged(listener, userId, sensorId, hasEnrollments);
+ }
+ }
+
+ /**
+ * Notifies the listener of enrollment state changes.
+ */
+ void notifyFingerprintEnrollmentStateChanged(@NonNull IFingerprintStateListener listener,
+ int userId, int sensorId, boolean hasEnrollments) {
+ try {
+ listener.onEnrollmentsChanged(userId, sensorId, hasEnrollments);
+ } catch (RemoteException e) {
+ Slog.e(FingerprintService.TAG, "Remote exception", e);
+ }
+ }
+
+ /**
* Enables clients to register a FingerprintStateListener. Used by FingerprintService to forward
* updates in fingerprint sensor state to the SideFpNsEventHandler
* @param listener
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
index 706ac10..1772f81 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/ServiceProvider.java
@@ -90,25 +90,27 @@
*/
void scheduleEnroll(int sensorId, @NonNull IBinder token, @NonNull byte[] hardwareAuthToken,
int userId, @NonNull IFingerprintServiceReceiver receiver,
- @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintStateCallback fingerprintStateCallback);
+ @NonNull String opPackageName, @FingerprintManager.EnrollReason int enrollReason);
void cancelEnrollment(int sensorId, @NonNull IBinder token);
- void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+ long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
- int statsClient,
- @NonNull FingerprintStateCallback fingerprintStateCallback);
+ int statsClient);
void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication);
+
+ long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId, int userId,
+ int cookie, @NonNull ClientMonitorCallbackConverter callback,
@NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication,
- @NonNull FingerprintStateCallback fingerprintStateCallback);
+ boolean allowBackgroundAuthentication);
void startPreparedClient(int sensorId, int cookie);
- void cancelAuthentication(int sensorId, @NonNull IBinder token);
+ void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId);
void scheduleRemove(int sensorId, @NonNull IBinder token,
@NonNull IFingerprintServiceReceiver receiver, int fingerId, int userId,
@@ -163,6 +165,5 @@
@NonNull
ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName);
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
index 29f2f20..2b50b96 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/BiometricTestSessionImpl.java
@@ -143,8 +143,7 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mProvider.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL,
- mFingerprintStateCallback);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
index 37ee76a..9d911e0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintAuthenticationClient.java
@@ -61,7 +61,8 @@
private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context,
- @NonNull LazyDaemon<ISession> lazyDaemon, @NonNull IBinder token,
+ @NonNull LazyDaemon<ISession> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsClient,
@@ -74,6 +75,7 @@
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutCache, allowBackgroundAuthentication, true /* shouldVibrate */,
false /* isKeyguardBypassEnabled */);
+ setRequestId(requestId);
mLockoutCache = lockoutCache;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
index c5dc449..da91cdd 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintDetectClient.java
@@ -47,13 +47,15 @@
@Nullable private ICancellationSignal mCancellationSignal;
FingerprintDetectClient(@NonNull Context context, @NonNull LazyDaemon<ISession> lazyDaemon,
- @NonNull IBinder token, @NonNull ClientMonitorCallbackConverter listener, int userId,
+ @NonNull IBinder token, long requestId,
+ @NonNull ClientMonitorCallbackConverter listener, int userId,
@NonNull String owner, int sensorId,
@Nullable IUdfpsOverlayController udfpsOverlayController, boolean isStrongBiometric,
int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+ setRequestId(requestId);
mIsStrongBiometric = isStrongBiometric;
mUdfpsOverlayController = udfpsOverlayController;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
index 102b074..ca83dda 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProvider.java
@@ -71,6 +71,7 @@
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Provider for a single instance of the {@link IFingerprint} HAL.
@@ -81,6 +82,7 @@
private boolean mTestHalEnabled;
@NonNull private final Context mContext;
+ @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
@NonNull private final String mHalInstanceName;
@NonNull @VisibleForTesting
final SparseArray<Sensor> mSensors; // Map of sensors that this HAL supports
@@ -88,6 +90,8 @@
@NonNull private final LockoutResetDispatcher mLockoutResetDispatcher;
@NonNull private final ActivityTaskManager mActivityTaskManager;
@NonNull private final BiometricTaskStackListener mTaskStackListener;
+ // for requests that do not use biometric prompt
+ @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
@Nullable private IFingerprint mDaemon;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@@ -118,8 +122,8 @@
&& !client.isAlreadyDone()) {
Slog.e(getTag(), "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client);
- mSensors.valueAt(i).getScheduler()
- .cancelAuthenticationOrDetection(client.getToken());
+ mSensors.valueAt(i).getScheduler().cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
}
@@ -127,10 +131,13 @@
}
}
- public FingerprintProvider(@NonNull Context context, @NonNull SensorProps[] props,
- @NonNull String halInstanceName, @NonNull LockoutResetDispatcher lockoutResetDispatcher,
+ public FingerprintProvider(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
+ @NonNull SensorProps[] props, @NonNull String halInstanceName,
+ @NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
mContext = context;
+ mFingerprintStateCallback = fingerprintStateCallback;
mHalInstanceName = halInstanceName;
mSensors = new SparseArray<>();
mHandler = new Handler(Looper.getMainLooper());
@@ -332,8 +339,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ @FingerprintManager.EnrollReason int enrollReason) {
mHandler.post(() -> {
final int maxTemplatesPerUser = mSensors.get(sensorId).getSensorProperties()
.maxEnrollmentsPerUser;
@@ -347,13 +353,13 @@
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- fingerprintStateCallback.onClientStarted(clientMonitor);
+ mFingerprintStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
- fingerprintStateCallback.onClientFinished(clientMonitor, success);
+ mFingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) {
scheduleLoadAuthenticatorIdsForUser(sensorId, userId);
scheduleInvalidationRequest(sensorId, userId);
@@ -369,48 +375,62 @@
}
@Override
- public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+ public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter callback, @NonNull String opPackageName,
- int statsClient,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ int statsClient) {
+ final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
- mSensors.get(sensorId).getLazySession(), token, callback, userId,
+ mSensors.get(sensorId).getLazySession(), token, id, callback, userId,
opPackageName, sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient);
- scheduleForSensor(sensorId, client, fingerprintStateCallback);
+ scheduleForSensor(sensorId, client, mFingerprintStateCallback);
});
+
+ return id;
}
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
- @NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
final boolean isStrongBiometric = Utils.isStrongBiometric(sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
- mContext, mSensors.get(sensorId).getLazySession(), token, callback, userId,
- operationId, restricted, opPackageName, cookie,
+ mContext, mSensors.get(sensorId).getLazySession(), token, requestId, callback,
+ userId, operationId, restricted, opPackageName, cookie,
false /* requireConfirmation */, sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mSensors.get(sensorId).getLockoutCache(),
mUdfpsOverlayController, allowBackgroundAuthentication,
mSensors.get(sensorId).getSensorProperties());
- scheduleForSensor(sensorId, client, fingerprintStateCallback);
+ scheduleForSensor(sensorId, client, mFingerprintStateCallback);
});
}
@Override
+ public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter callback,
+ @NonNull String opPackageName, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication) {
+ final long id = mRequestCounter.incrementAndGet();
+
+ scheduleAuthenticate(sensorId, token, operationId, userId, cookie, callback,
+ opPackageName, id, restricted, statsClient, allowBackgroundAuthentication);
+
+ return id;
+ }
+
+ @Override
public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler().startPreparedClient(cookie));
}
@Override
- public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
mHandler.post(() -> mSensors.get(sensorId).getScheduler()
- .cancelAuthenticationOrDetection(token));
+ .cancelAuthenticationOrDetection(token, requestId));
}
@Override
@@ -444,7 +464,7 @@
new ClientMonitorCallbackConverter(receiver), fingerprintIds, userId,
opPackageName, FingerprintUtils.getInstance(sensorId), sensorId,
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client);
+ scheduleForSensor(sensorId, client, mFingerprintStateCallback);
});
}
@@ -459,7 +479,8 @@
mContext.getOpPackageName(), sensorId, enrolledList,
FingerprintUtils.getInstance(sensorId),
mSensors.get(sensorId).getAuthenticatorIds());
- scheduleForSensor(sensorId, client, callback);
+ scheduleForSensor(sensorId, client, new BaseClientMonitor.CompositeCallback(callback,
+ mFingerprintStateCallback));
});
}
@@ -604,9 +625,8 @@
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) {
- return mSensors.get(sensorId).createTestSession(callback, fingerprintStateCallback);
+ return mSensors.get(sensorId).createTestSession(callback, mFingerprintStateCallback);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
index c00daff..79c6b1b3 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/BiometricTestSessionImpl.java
@@ -143,8 +143,7 @@
Utils.checkPermission(mContext, TEST_BIOMETRIC);
mFingerprint21.scheduleEnroll(mSensorId, new Binder(), new byte[69], userId, mReceiver,
- mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL,
- mFingerprintStateCallback);
+ mContext.getOpPackageName(), FingerprintManager.ENROLL_ENROLL);
}
@Override
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
index 2f5b5c7..d2882aa4 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21.java
@@ -88,6 +88,7 @@
import java.util.HashMap;
import java.util.List;
import java.util.Map;
+import java.util.concurrent.atomic.AtomicLong;
/**
* Supports a single instance of the {@link android.hardware.biometrics.fingerprint.V2_1} or
@@ -101,6 +102,7 @@
private boolean mTestHalEnabled;
final Context mContext;
+ @NonNull private final FingerprintStateCallback mFingerprintStateCallback;
private final ActivityTaskManager mActivityTaskManager;
@NonNull private final FingerprintSensorPropertiesInternal mSensorProperties;
private final BiometricScheduler mScheduler;
@@ -115,6 +117,8 @@
@NonNull private final HalResultController mHalResultController;
@Nullable private IUdfpsOverlayController mUdfpsOverlayController;
@Nullable private ISidefpsController mSidefpsController;
+ // for requests that do not use biometric prompt
+ @NonNull private final AtomicLong mRequestCounter = new AtomicLong(0);
private int mCurrentUserId = UserHandle.USER_NULL;
private final boolean mIsUdfps;
private final int mSensorId;
@@ -142,7 +146,8 @@
&& !client.isAlreadyDone()) {
Slog.e(TAG, "Stopping background authentication, top: "
+ topPackage + " currentClient: " + client);
- mScheduler.cancelAuthenticationOrDetection(client.getToken());
+ mScheduler.cancelAuthenticationOrDetection(
+ client.getToken(), client.getRequestId());
}
}
});
@@ -313,11 +318,13 @@
}
Fingerprint21(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
mContext = context;
+ mFingerprintStateCallback = fingerprintStateCallback;
mSensorProperties = sensorProps;
mSensorId = sensorProps.sensorId;
@@ -347,6 +354,7 @@
}
public static Fingerprint21 newInstance(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -358,8 +366,8 @@
final HalResultController controller = new HalResultController(sensorProps.sensorId,
context, handler,
scheduler);
- return new Fingerprint21(context, sensorProps, scheduler, handler, lockoutResetDispatcher,
- controller);
+ return new Fingerprint21(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller);
}
@Override
@@ -553,8 +561,7 @@
public void scheduleEnroll(int sensorId, @NonNull IBinder token,
@NonNull byte[] hardwareAuthToken, int userId,
@NonNull IFingerprintServiceReceiver receiver, @NonNull String opPackageName,
- @FingerprintManager.EnrollReason int enrollReason,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ @FingerprintManager.EnrollReason int enrollReason) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
@@ -566,13 +573,13 @@
mScheduler.scheduleClientMonitor(client, new BaseClientMonitor.Callback() {
@Override
public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
- fingerprintStateCallback.onClientStarted(clientMonitor);
+ mFingerprintStateCallback.onClientStarted(clientMonitor);
}
@Override
public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
boolean success) {
- fingerprintStateCallback.onClientFinished(clientMonitor, success);
+ mFingerprintStateCallback.onClientFinished(clientMonitor, success);
if (success) {
// Update authenticatorIds
scheduleUpdateActiveUserWithoutHandler(clientMonitor.getTargetUserId(),
@@ -591,51 +598,65 @@
}
@Override
- public void scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
+ public long scheduleFingerDetect(int sensorId, @NonNull IBinder token, int userId,
@NonNull ClientMonitorCallbackConverter listener, @NonNull String opPackageName,
- int statsClient,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ int statsClient) {
+ final long id = mRequestCounter.incrementAndGet();
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
final FingerprintDetectClient client = new FingerprintDetectClient(mContext,
- mLazyDaemon, token, listener, userId, opPackageName,
+ mLazyDaemon, token, id, listener, userId, opPackageName,
mSensorProperties.sensorId, mUdfpsOverlayController, isStrongBiometric,
statsClient);
- mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
+
+ return id;
}
@Override
public void scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
- @NonNull String opPackageName, boolean restricted, int statsClient,
- boolean allowBackgroundAuthentication,
- @NonNull FingerprintStateCallback fingerprintStateCallback) {
+ @NonNull String opPackageName, long requestId, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication) {
mHandler.post(() -> {
scheduleUpdateActiveUserWithoutHandler(userId);
final boolean isStrongBiometric = Utils.isStrongBiometric(mSensorProperties.sensorId);
final FingerprintAuthenticationClient client = new FingerprintAuthenticationClient(
- mContext, mLazyDaemon, token, listener, userId, operationId, restricted,
- opPackageName, cookie, false /* requireConfirmation */,
+ mContext, mLazyDaemon, token, requestId, listener, userId, operationId,
+ restricted, opPackageName, cookie, false /* requireConfirmation */,
mSensorProperties.sensorId, isStrongBiometric, statsClient,
mTaskStackListener, mLockoutTracker, mUdfpsOverlayController,
allowBackgroundAuthentication, mSensorProperties);
- mScheduler.scheduleClientMonitor(client, fingerprintStateCallback);
+ mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
}
@Override
+ public long scheduleAuthenticate(int sensorId, @NonNull IBinder token, long operationId,
+ int userId, int cookie, @NonNull ClientMonitorCallbackConverter listener,
+ @NonNull String opPackageName, boolean restricted, int statsClient,
+ boolean allowBackgroundAuthentication) {
+ final long id = mRequestCounter.incrementAndGet();
+
+ scheduleAuthenticate(sensorId, token, operationId, userId, cookie, listener,
+ opPackageName, id, restricted, statsClient, allowBackgroundAuthentication);
+
+ return id;
+ }
+
+ @Override
public void startPreparedClient(int sensorId, int cookie) {
mHandler.post(() -> mScheduler.startPreparedClient(cookie));
}
@Override
- public void cancelAuthentication(int sensorId, @NonNull IBinder token) {
+ public void cancelAuthentication(int sensorId, @NonNull IBinder token, long requestId) {
Slog.d(TAG, "cancelAuthentication, sensorId: " + sensorId);
- mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token));
+ mHandler.post(() -> mScheduler.cancelAuthenticationOrDetection(token, requestId));
}
@Override
@@ -649,7 +670,7 @@
mLazyDaemon, token, new ClientMonitorCallbackConverter(receiver), fingerId,
userId, opPackageName, FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds);
- mScheduler.scheduleClientMonitor(client);
+ mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
}
@@ -666,7 +687,7 @@
0 /* fingerprintId */, userId, opPackageName,
FingerprintUtils.getLegacyInstance(mSensorId),
mSensorProperties.sensorId, mAuthenticatorIds);
- mScheduler.scheduleClientMonitor(client);
+ mScheduler.scheduleClientMonitor(client, mFingerprintStateCallback);
});
}
@@ -688,7 +709,8 @@
@Override
public void scheduleInternalCleanup(int sensorId, int userId,
@Nullable BaseClientMonitor.Callback callback) {
- scheduleInternalCleanup(userId, callback);
+ scheduleInternalCleanup(userId, new BaseClientMonitor.CompositeCallback(callback,
+ mFingerprintStateCallback));
}
@Override
@@ -896,9 +918,8 @@
@NonNull
@Override
public ITestSession createTestSession(int sensorId, @NonNull ITestSessionCallback callback,
- @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull String opPackageName) {
return new BiometricTestSessionImpl(mContext, mSensorProperties.sensorId, callback,
- fingerprintStateCallback, this, mHalResultController);
+ mFingerprintStateCallback, this, mHalResultController);
}
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
index 24ce867..79ad8e1 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21UdfpsMock.java
@@ -26,6 +26,7 @@
import android.hardware.fingerprint.FingerprintManager.AuthenticationResult;
import android.hardware.fingerprint.FingerprintSensorProperties;
import android.hardware.fingerprint.FingerprintSensorPropertiesInternal;
+import android.hardware.fingerprint.FingerprintStateListener;
import android.hardware.fingerprint.IUdfpsOverlayController;
import android.os.Handler;
import android.os.IBinder;
@@ -42,6 +43,7 @@
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import java.util.ArrayList;
@@ -270,6 +272,7 @@
}
public static Fingerprint21UdfpsMock newInstance(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
@@ -280,8 +283,8 @@
new TestableBiometricScheduler(TAG, gestureAvailabilityDispatcher);
final MockHalResultController controller =
new MockHalResultController(sensorProps.sensorId, context, handler, scheduler);
- return new Fingerprint21UdfpsMock(context, sensorProps, scheduler, handler,
- lockoutResetDispatcher, controller);
+ return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler,
+ handler, lockoutResetDispatcher, controller);
}
private static abstract class FakeFingerRunnable implements Runnable {
@@ -400,17 +403,19 @@
// internal preemption logic is not run.
mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token,
operationId, user, cookie, listener, opPackageName, restricted, statsClient,
- isKeyguard, null /* fingerprintStateCallback */);
+ isKeyguard);
}
}
private Fingerprint21UdfpsMock(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull TestableBiometricScheduler scheduler,
@NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull MockHalResultController controller) {
- super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller);
+ super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller);
mScheduler = scheduler;
mScheduler.init(this);
mHandler = handler;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
index 5060744..7d95ec0 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintAuthenticationClient.java
@@ -59,7 +59,8 @@
private boolean mIsPointerDown;
FingerprintAuthenticationClient(@NonNull Context context,
- @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int targetUserId, long operationId,
boolean restricted, @NonNull String owner, int cookie, boolean requireConfirmation,
int sensorId, boolean isStrongBiometric, int statsClient,
@@ -73,6 +74,7 @@
BiometricsProtoEnums.MODALITY_FINGERPRINT, statsClient, taskStackListener,
lockoutTracker, allowBackgroundAuthentication, true /* shouldVibrate */,
false /* isKeyguardBypassEnabled */);
+ setRequestId(requestId);
mLockoutFrameworkImpl = lockoutTracker;
mUdfpsOverlayController = udfpsOverlayController;
mSensorProps = sensorProps;
diff --git a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
index 8e73ee6b..147a206 100644
--- a/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
+++ b/services/core/java/com/android/server/biometrics/sensors/fingerprint/hidl/FingerprintDetectClient.java
@@ -52,13 +52,15 @@
private boolean mIsPointerDown;
public FingerprintDetectClient(@NonNull Context context,
- @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon, @NonNull IBinder token,
+ @NonNull LazyDaemon<IBiometricsFingerprint> lazyDaemon,
+ @NonNull IBinder token, long requestId,
@NonNull ClientMonitorCallbackConverter listener, int userId, @NonNull String owner,
int sensorId, @Nullable IUdfpsOverlayController udfpsOverlayController,
boolean isStrongBiometric, int statsClient) {
super(context, lazyDaemon, token, listener, userId, owner, 0 /* cookie */, sensorId,
true /* shouldVibrate */, BiometricsProtoEnums.MODALITY_FINGERPRINT,
BiometricsProtoEnums.ACTION_AUTHENTICATE, statsClient);
+ setRequestId(requestId);
mUdfpsOverlayController = udfpsOverlayController;
mIsStrongBiometric = isStrongBiometric;
}
diff --git a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
index 4918185..5c0c362 100644
--- a/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
+++ b/services/core/java/com/android/server/biometrics/sensors/iris/IrisAuthenticator.java
@@ -59,7 +59,7 @@
@Override
public void prepareForAuthentication(boolean requireConfirmation, IBinder token,
long sessionId, int userId, IBiometricSensorReceiver sensorReceiver,
- String opPackageName, int cookie, boolean allowBackgroundAuthentication)
+ String opPackageName, long requestId, int cookie, boolean allowBackgroundAuthentication)
throws RemoteException {
}
@@ -68,7 +68,7 @@
}
@Override
- public void cancelAuthenticationFromService(IBinder token, String opPackageName)
+ public void cancelAuthenticationFromService(IBinder token, String opPackageName, long requestId)
throws RemoteException {
}
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index 6610e8c..42b676f 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -692,8 +692,11 @@
}
try {
- WindowManagerGlobal.getWindowManagerService().registerDisplayWindowListener(
- mDisplayWindowListener);
+ int[] displayIds = WindowManagerGlobal.getWindowManagerService()
+ .registerDisplayWindowListener(mDisplayWindowListener);
+ for (int i = 0; i < displayIds.length; i++) {
+ mDisplayWindowListener.onDisplayAdded(displayIds[i]);
+ }
} catch (RemoteException e) {
Log.e(TAG, "Failed to register display window listener!");
}
diff --git a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
index 383b392..806a5dd 100644
--- a/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
+++ b/services/core/java/com/android/server/devicestate/DeviceStateManagerService.java
@@ -19,7 +19,6 @@
import static android.Manifest.permission.CONTROL_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MAXIMUM_DEVICE_STATE;
import static android.hardware.devicestate.DeviceStateManager.MINIMUM_DEVICE_STATE;
-import static android.os.Process.THREAD_PRIORITY_DISPLAY;
import static com.android.server.devicestate.OverrideRequestController.STATUS_ACTIVE;
import static com.android.server.devicestate.OverrideRequestController.STATUS_CANCELED;
@@ -36,7 +35,6 @@
import android.hardware.devicestate.IDeviceStateManagerCallback;
import android.os.Binder;
import android.os.Handler;
-import android.os.HandlerThread;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.ResultReceiver;
@@ -48,8 +46,8 @@
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.util.DumpUtils;
import com.android.internal.util.FrameworkStatsLog;
+import com.android.server.DisplayThread;
import com.android.server.LocalServices;
-import com.android.server.ServiceThread;
import com.android.server.SystemService;
import com.android.server.policy.DeviceStatePolicyImpl;
import com.android.server.wm.ActivityTaskManagerInternal;
@@ -93,10 +91,9 @@
private static final boolean DEBUG = false;
private final Object mLock = new Object();
- // Internal system service thread used to dispatch calls to the policy and to registered
+ // Handler on the {@link DisplayThread} used to dispatch calls to the policy and to registered
// callbacks though its handler (mHandler). Provides a guarantee of callback order when
// leveraging mHandler and also enables posting messages with the service lock held.
- private final HandlerThread mHandlerThread;
private final Handler mHandler;
@NonNull
private final DeviceStatePolicy mDeviceStatePolicy;
@@ -149,11 +146,10 @@
@VisibleForTesting
DeviceStateManagerService(@NonNull Context context, @NonNull DeviceStatePolicy policy) {
super(context);
- // Service thread assigned THREAD_PRIORITY_DISPLAY because this service indirectly drives
+ // We use the DisplayThread because this service indirectly drives
// display (on/off) and window (position) events through its callbacks.
- mHandlerThread = new ServiceThread(TAG, THREAD_PRIORITY_DISPLAY, false /* allowIo */);
- mHandlerThread.start();
- mHandler = mHandlerThread.getThreadHandler();
+ DisplayThread displayThread = DisplayThread.get();
+ mHandler = new Handler(displayThread.getLooper());
mOverrideRequestController = new OverrideRequestController(
this::onOverrideRequestStatusChangedLocked);
mDeviceStatePolicy = policy;
@@ -552,7 +548,7 @@
}
ProcessRecord record = new ProcessRecord(callback, pid, this::handleProcessDied,
- mHandlerThread.getThreadHandler());
+ mHandler);
try {
callback.asBinder().linkToDeath(record, 0);
} catch (RemoteException ex) {
diff --git a/services/core/java/com/android/server/display/DisplayDeviceConfig.java b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
index 4c9d0f2..2ae5cbb 100644
--- a/services/core/java/com/android/server/display/DisplayDeviceConfig.java
+++ b/services/core/java/com/android/server/display/DisplayDeviceConfig.java
@@ -590,7 +590,7 @@
newIndex = i - newStart;
final float newBacklightVal;
final float newNitsVal;
- isLastValue = mRawBacklight[i] > mBacklightMaximum
+ isLastValue = mRawBacklight[i] >= mBacklightMaximum
|| i >= mRawBacklight.length - 1;
// Clamp beginning and end to valid backlight values.
if (newIndex == 0) {
diff --git a/services/core/java/com/android/server/display/DisplayModeDirector.java b/services/core/java/com/android/server/display/DisplayModeDirector.java
index d66d7ee..5797b06 100644
--- a/services/core/java/com/android/server/display/DisplayModeDirector.java
+++ b/services/core/java/com/android/server/display/DisplayModeDirector.java
@@ -36,9 +36,14 @@
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.net.Uri;
import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
import android.os.Looper;
import android.os.Message;
+import android.os.RemoteException;
+import android.os.ServiceManager;
import android.os.SystemClock;
+import android.os.Temperature;
import android.os.UserHandle;
import android.provider.DeviceConfig;
import android.provider.Settings;
@@ -108,6 +113,7 @@
private final UdfpsObserver mUdfpsObserver;
private final SensorObserver mSensorObserver;
private final HbmObserver mHbmObserver;
+ private final SkinThermalStatusObserver mSkinThermalStatusObserver;
private final DeviceConfigInterface mDeviceConfig;
private final DeviceConfigDisplaySettings mDeviceConfigDisplaySettings;
@@ -156,6 +162,7 @@
};
mSensorObserver = new SensorObserver(context, ballotBox, injector);
mHbmObserver = new HbmObserver(injector, ballotBox, BackgroundThread.getHandler());
+ mSkinThermalStatusObserver = new SkinThermalStatusObserver(injector, ballotBox);
mDeviceConfigDisplaySettings = new DeviceConfigDisplaySettings();
mDeviceConfig = injector.getDeviceConfig();
mAlwaysRespectAppRequest = false;
@@ -174,6 +181,7 @@
mBrightnessObserver.observe(sensorManager);
mSensorObserver.observe();
mHbmObserver.observe();
+ mSkinThermalStatusObserver.observe();
synchronized (mLock) {
// We may have a listener already registered before the call to start, so go ahead and
// notify them to pick up our newly initialized state.
@@ -606,6 +614,7 @@
mUdfpsObserver.dumpLocked(pw);
mSensorObserver.dumpLocked(pw);
mHbmObserver.dumpLocked(pw);
+ mSkinThermalStatusObserver.dumpLocked(pw);
}
}
@@ -714,7 +723,6 @@
return mUdfpsObserver;
}
-
@VisibleForTesting
DesiredDisplayModeSpecs getDesiredDisplayModeSpecsWithInjectedFpsSettings(
float minRefreshRate, float peakRefreshRate, float defaultRefreshRate) {
@@ -950,16 +958,19 @@
// user seeing the display flickering when the switches occur.
public static final int PRIORITY_FLICKER_REFRESH_RATE_SWITCH = 8;
+ // Force display to [0, 60HZ] if skin temperature is at or above CRITICAL.
+ public static final int PRIORITY_SKIN_TEMPERATURE = 9;
+
// High-brightness-mode may need a specific range of refresh-rates to function properly.
- public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 9;
+ public static final int PRIORITY_HIGH_BRIGHTNESS_MODE = 10;
// The proximity sensor needs the refresh rate to be locked in order to function, so this is
// set to a high priority.
- public static final int PRIORITY_PROXIMITY = 10;
+ public static final int PRIORITY_PROXIMITY = 11;
// The Under-Display Fingerprint Sensor (UDFPS) needs the refresh rate to be locked in order
// to function, so this needs to be the highest priority of all votes.
- public static final int PRIORITY_UDFPS = 11;
+ public static final int PRIORITY_UDFPS = 12;
// Whenever a new priority is added, remember to update MIN_PRIORITY, MAX_PRIORITY, and
// APP_REQUEST_REFRESH_RATE_RANGE_PRIORITY_CUTOFF, as well as priorityToString.
@@ -1054,6 +1065,8 @@
return "PRIORITY_PROXIMITY";
case PRIORITY_LOW_POWER_MODE:
return "PRIORITY_LOW_POWER_MODE";
+ case PRIORITY_SKIN_TEMPERATURE:
+ return "PRIORITY_SKIN_TEMPERATURE";
case PRIORITY_UDFPS:
return "PRIORITY_UDFPS";
case PRIORITY_USER_SETTING_MIN_REFRESH_RATE:
@@ -2309,6 +2322,52 @@
}
}
+ private final class SkinThermalStatusObserver extends IThermalEventListener.Stub {
+ private final BallotBox mBallotBox;
+ private final Injector mInjector;
+
+ private @Temperature.ThrottlingStatus int mStatus = -1;
+
+ SkinThermalStatusObserver(Injector injector, BallotBox ballotBox) {
+ mInjector = injector;
+ mBallotBox = ballotBox;
+ }
+
+ @Override
+ public void notifyThrottling(Temperature temp) {
+ mStatus = temp.getStatus();
+ if (mLoggingEnabled) {
+ Slog.d(TAG, "New thermal throttling status "
+ + ", current thermal status = " + mStatus);
+ }
+ final Vote vote;
+ if (mStatus >= Temperature.THROTTLING_CRITICAL) {
+ vote = Vote.forRefreshRates(0f, 60f);
+ } else {
+ vote = null;
+ }
+ mBallotBox.vote(GLOBAL_ID, Vote.PRIORITY_SKIN_TEMPERATURE, vote);
+ }
+
+ public void observe() {
+ IThermalService thermalService = mInjector.getThermalService();
+ if (thermalService == null) {
+ Slog.w(TAG, "Could not observe thermal status. Service not available");
+ return;
+ }
+ try {
+ thermalService.registerThermalEventListenerWithType(this, Temperature.TYPE_SKIN);
+ } catch (RemoteException e) {
+ Slog.e(TAG, "Failed to register thermal status listener", e);
+ }
+ }
+
+ void dumpLocked(PrintWriter writer) {
+ writer.println(" SkinThermalStatusObserver:");
+ writer.println(" mStatus: " + mStatus);
+ }
+ }
+
private class DeviceConfigDisplaySettings implements DeviceConfig.OnPropertiesChangedListener {
public DeviceConfigDisplaySettings() {
}
@@ -2470,6 +2529,8 @@
BrightnessInfo getBrightnessInfo(int displayId);
boolean isDozeState(Display d);
+
+ IThermalService getThermalService();
}
@VisibleForTesting
@@ -2530,6 +2591,12 @@
return Display.isDozeState(d.getState());
}
+ @Override
+ public IThermalService getThermalService() {
+ return IThermalService.Stub.asInterface(
+ ServiceManager.getService(Context.THERMAL_SERVICE));
+ }
+
private DisplayManager getDisplayManager() {
if (mDisplayManager == null) {
mDisplayManager = mContext.getSystemService(DisplayManager.class);
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 1769712..5a9efd7 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -601,8 +601,6 @@
&& SystemProperties.getBoolean(PROPERTY_EMULATOR_CIRCULAR, false))) {
mInfo.flags |= DisplayDeviceInfo.FLAG_ROUND;
}
- mInfo.roundedCorners = RoundedCorners.fromResources(
- res, mInfo.width, mInfo.height);
} else {
if (!res.getBoolean(
com.android.internal.R.bool.config_localDisplaysMirrorContent)) {
@@ -620,6 +618,9 @@
mInfo.displayCutout = DisplayCutout.fromResourcesRectApproximation(res,
mInfo.uniqueId, mInfo.width, mInfo.height);
+ mInfo.roundedCorners = RoundedCorners.fromResources(
+ res, mInfo.uniqueId, mInfo.width, mInfo.height);
+
if (mStaticDisplayInfo.isInternal) {
mInfo.type = Display.TYPE_INTERNAL;
mInfo.touch = DisplayDeviceInfo.TOUCH_INTERNAL;
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index 34d2b01..a592192 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -303,6 +303,9 @@
@Override
public Point getDisplaySurfaceDefaultSize() {
+ if (mSurface == null) {
+ return null;
+ }
return mSurface.getDefaultSize();
}
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index a23d6cf..b0b8be2 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -180,7 +180,7 @@
private static final boolean UNTRUSTED_TOUCHES_TOAST = false;
public static final boolean ENABLE_PER_WINDOW_INPUT_ROTATION =
- SystemProperties.getBoolean("persist.debug.per_window_input_rotation", true);
+ SystemProperties.getBoolean("persist.debug.per_window_input_rotation", false);
// Pointer to native input manager service object.
private final long mPtr;
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index fe6f2da..0e82c2a 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2581,14 +2581,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;
diff --git a/services/core/java/com/android/server/location/provider/LocationProviderManager.java b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
index 8955c28..62d8c32 100644
--- a/services/core/java/com/android/server/location/provider/LocationProviderManager.java
+++ b/services/core/java/com/android/server/location/provider/LocationProviderManager.java
@@ -1078,7 +1078,7 @@
}
private void onTransportFailure(Exception e) {
- if (e instanceof RemoteException) {
+ if (e instanceof PendingIntent.CanceledException) {
Log.w(TAG, mName + " provider registration " + getIdentity() + " removed", e);
synchronized (mLock) {
remove();
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 207baf5..78c909d 100755
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -7449,15 +7449,21 @@
sentAccessibilityEvent = true;
}
if (DBG) Slog.v(TAG, "Interrupting!");
+ boolean isInsistentUpdate = isInsistentUpdate(record);
if (hasValidSound) {
- if (isInCall()) {
- playInCallNotification();
+ if (isInsistentUpdate) {
+ // don't reset insistent sound, it's jarring
beep = true;
} else {
- beep = playSound(record, soundUri);
- }
- if(beep) {
- mSoundNotificationKey = key;
+ if (isInCall()) {
+ playInCallNotification();
+ beep = true;
+ } else {
+ beep = playSound(record, soundUri);
+ }
+ if (beep) {
+ mSoundNotificationKey = key;
+ }
}
}
@@ -7465,9 +7471,13 @@
mAudioManager.getRingerModeInternal()
== AudioManager.RINGER_MODE_SILENT;
if (!isInCall() && hasValidVibrate && !ringerModeSilent) {
- buzz = playVibration(record, vibration, hasValidSound);
- if(buzz) {
- mVibrateNotificationKey = key;
+ if (isInsistentUpdate) {
+ buzz = true;
+ } else {
+ buzz = playVibration(record, vibration, hasValidSound);
+ if (buzz) {
+ mVibrateNotificationKey = key;
+ }
}
}
} else if ((record.getFlags() & Notification.FLAG_INSISTENT) != 0) {
@@ -7571,6 +7581,19 @@
}
@GuardedBy("mNotificationLock")
+ boolean isInsistentUpdate(final NotificationRecord record) {
+ return (Objects.equals(record.getKey(), mSoundNotificationKey)
+ || Objects.equals(record.getKey(), mVibrateNotificationKey))
+ && isCurrentlyInsistent();
+ }
+
+ @GuardedBy("mNotificationLock")
+ boolean isCurrentlyInsistent() {
+ return isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
+ || isLoopingRingtoneNotification(mNotificationsByKey.get(mVibrateNotificationKey));
+ }
+
+ @GuardedBy("mNotificationLock")
boolean shouldMuteNotificationLocked(final NotificationRecord record) {
// Suppressed because it's a silent update
final Notification notification = record.getNotification();
@@ -7609,10 +7632,8 @@
return true;
}
- // A looping ringtone, such as an incoming call is playing
- if (isLoopingRingtoneNotification(mNotificationsByKey.get(mSoundNotificationKey))
- || isLoopingRingtoneNotification(
- mNotificationsByKey.get(mVibrateNotificationKey))) {
+ // A different looping ringtone, such as an incoming call is playing
+ if (isCurrentlyInsistent() && !isInsistentUpdate(record)) {
return true;
}
@@ -8756,10 +8777,22 @@
void snoozeNotificationInt(String key, long duration, String snoozeCriterionId,
ManagedServiceInfo listener) {
- String listenerName = listener == null ? null : listener.component.toShortString();
+ if (listener == null) {
+ return;
+ }
+ String listenerName = listener.component.toShortString();
if ((duration <= 0 && snoozeCriterionId == null) || key == null) {
return;
}
+ synchronized (mNotificationLock) {
+ final NotificationRecord r = findInCurrentAndSnoozedNotificationByKeyLocked(key);
+ if (r == null) {
+ return;
+ }
+ if (!listener.enabledAndUserMatches(r.getSbn().getNormalizedUserId())){
+ return;
+ }
+ }
if (DBG) {
Slog.d(TAG, String.format("snooze event(%s, %d, %s, %s)", key, duration,
diff --git a/services/core/java/com/android/server/notification/NotificationShellCmd.java b/services/core/java/com/android/server/notification/NotificationShellCmd.java
index 7112ae1..628a322 100644
--- a/services/core/java/com/android/server/notification/NotificationShellCmd.java
+++ b/services/core/java/com/android/server/notification/NotificationShellCmd.java
@@ -22,6 +22,7 @@
import static android.app.NotificationManager.INTERRUPTION_FILTER_PRIORITY;
import static android.app.NotificationManager.INTERRUPTION_FILTER_UNKNOWN;
+import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.INotificationManager;
import android.app.Notification;
@@ -44,6 +45,8 @@
import android.os.RemoteException;
import android.os.ShellCommand;
import android.os.UserHandle;
+import android.service.notification.NotificationListenerService;
+import android.service.notification.StatusBarNotification;
import android.text.TextUtils;
import android.util.Slog;
@@ -392,19 +395,28 @@
+ "--context <snooze-criterion-id>) <key>");
return 1;
}
- if (null == mDirectService.getNotificationRecord(key)) {
- pw.println("error: no notification matching key: " + key);
- return 1;
- }
if (duration > 0 || criterion != null) {
+ ShellNls nls = new ShellNls();
+ nls.registerAsSystemService(mDirectService.getContext(),
+ new ComponentName(nls.getClass().getPackageName(),
+ nls.getClass().getName()),
+ ActivityManager.getCurrentUser());
+ if (!waitForBind(nls)) {
+ pw.println("error: could not bind a listener in time");
+ return 1;
+ }
if (duration > 0) {
pw.println(String.format("snoozing <%s> until time: %s", key,
new Date(System.currentTimeMillis() + duration)));
+ nls.snoozeNotification(key, duration);
} else {
pw.println(String.format("snoozing <%s> until criterion: %s", key,
criterion));
+ nls.snoozeNotification(key, criterion);
}
- mDirectService.snoozeNotificationInt(key, duration, criterion, null);
+ waitForSnooze(nls, key);
+ nls.unregisterAsSystemService();
+ waitForUnbind(nls);
} else {
pw.println("error: invalid value for --" + subflag + ": " + flagarg);
return 1;
@@ -527,14 +539,17 @@
final PendingIntent pi;
if ("broadcast".equals(intentKind)) {
pi = PendingIntent.getBroadcastAsUser(
- context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED,
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_MUTABLE_UNAUDITED,
UserHandle.CURRENT);
} else if ("service".equals(intentKind)) {
pi = PendingIntent.getService(
- context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED);
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_MUTABLE_UNAUDITED);
} else {
pi = PendingIntent.getActivityAsUser(
- context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
+ context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT
+ | PendingIntent.FLAG_MUTABLE_UNAUDITED, null,
UserHandle.CURRENT);
}
builder.setContentIntent(pi);
@@ -685,9 +700,79 @@
return 0;
}
+ private void waitForSnooze(ShellNls nls, String key) {
+ for (int i = 0; i < 20; i++) {
+ StatusBarNotification[] sbns = nls.getSnoozedNotifications();
+ for (StatusBarNotification sbn : sbns) {
+ if (sbn.getKey().equals(key)) {
+ return;
+ }
+ }
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ return;
+ }
+
+ private boolean waitForBind(ShellNls nls) {
+ for (int i = 0; i < 20; i++) {
+ if (nls.isConnected) {
+ Slog.i(TAG, "Bound Shell NLS");
+ return true;
+ } else {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ return false;
+ }
+
+ private void waitForUnbind(ShellNls nls) {
+ for (int i = 0; i < 10; i++) {
+ if (!nls.isConnected) {
+ Slog.i(TAG, "Unbound Shell NLS");
+ return;
+ } else {
+ try {
+ Thread.sleep(100);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
@Override
public void onHelp() {
getOutPrintWriter().println(USAGE);
}
+
+ @SuppressLint("OverrideAbstract")
+ private static class ShellNls extends NotificationListenerService {
+ private static ShellNls
+ sNotificationListenerInstance = null;
+ boolean isConnected;
+
+ @Override
+ public void onListenerConnected() {
+ super.onListenerConnected();
+ sNotificationListenerInstance = this;
+ isConnected = true;
+ }
+ @Override
+ public void onListenerDisconnected() {
+ isConnected = false;
+ }
+
+ public static ShellNls getInstance() {
+ return sNotificationListenerInstance;
+ }
+ }
}
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 96bde3d..e8a3a81 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -330,8 +330,7 @@
}
}
- if (isShortcutOk(channel) && isDeletionOk(channel)
- && !channel.isSoundMissing()) {
+ if (isShortcutOk(channel) && isDeletionOk(channel)) {
r.channels.put(id, channel);
}
}
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 140098d..3691f60 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2132,6 +2132,13 @@
boolean filterAppAccess(String packageName, int callingUid, int userId);
@LiveImplementation(override = LiveImplementation.MANDATORY)
void dump(int type, FileDescriptor fd, PrintWriter pw, DumpState dumpState);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered);
+ @LiveImplementation(override = LiveImplementation.NOT_ALLOWED)
+ ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean debug, int userId);
}
/**
@@ -2914,7 +2921,24 @@
}
allHomeCandidates.addAll(resolveInfos);
- final String packageName = mDefaultAppProvider.getDefaultHome(userId);
+ String packageName = mDefaultAppProvider.getDefaultHome(userId);
+ if (packageName == null) {
+ // Role changes are not and cannot be atomic because its implementation lives inside
+ // a system app, so when the home role changes, there is a window when the previous
+ // role holder is removed and the new role holder is granted the preferred activity,
+ // but hasn't become the role holder yet. However, this case may be easily hit
+ // because the preferred activity change triggers a broadcast and receivers may try
+ // to get the default home activity there. So we need to fix it for this time
+ // window, and an easy workaround is to fallback to the current preferred activity.
+ final int appId = UserHandle.getAppId(Binder.getCallingUid());
+ final boolean filtered = appId >= Process.FIRST_APPLICATION_UID;
+ FindPreferredActivityBodyResult result = findPreferredActivityInternal(
+ intent, null, 0, resolveInfos, true, false, false, userId, filtered);
+ ResolveInfo preferredResolveInfo = result.mPreferredResolveInfo;
+ if (preferredResolveInfo != null && preferredResolveInfo.activityInfo != null) {
+ packageName = preferredResolveInfo.activityInfo.packageName;
+ }
+ }
if (packageName == null) {
return null;
}
@@ -4846,6 +4870,284 @@
}
} // switch
}
+
+ // The body of findPreferredActivity.
+ protected FindPreferredActivityBodyResult findPreferredActivityBody(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+ int callingUid, boolean isDeviceProvisioned) {
+ FindPreferredActivityBodyResult result = new FindPreferredActivityBodyResult();
+
+ flags = updateFlagsForResolve(
+ flags, userId, callingUid, false /*includeInstantApps*/,
+ isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId,
+ resolvedType, flags));
+ intent = updateIntentForResolve(intent);
+
+ // Try to find a matching persistent preferred activity.
+ result.mPreferredResolveInfo = findPersistentPreferredActivityLP(intent,
+ resolvedType, flags, query, debug, userId);
+
+ // If a persistent preferred activity matched, use it.
+ if (result.mPreferredResolveInfo != null) {
+ return result;
+ }
+
+ PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
+ // Get the list of preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
+ List<PreferredActivity> prefs = pir != null
+ ? pir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : null;
+ if (prefs != null && prefs.size() > 0) {
+
+ // First figure out how good the original match set is.
+ // We will only allow preferred activities that came
+ // from the same match quality.
+ int match = 0;
+
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
+
+ final int N = query.size();
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Match for " + ri.activityInfo
+ + ": 0x" + Integer.toHexString(match));
+ }
+ if (ri.match > match) {
+ match = ri.match;
+ }
+ }
+
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Best match: 0x" + Integer.toHexString(match));
+ }
+ match &= IntentFilter.MATCH_CATEGORY_MASK;
+ final int M = prefs.size();
+ for (int i = 0; i < M; i++) {
+ final PreferredActivity pa = prefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PreferredActivity ds="
+ + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
+ + "\n component=" + pa.mPref.mComponent);
+ pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ if (pa.mPref.mMatch != match) {
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Skipping bad match "
+ + Integer.toHexString(pa.mPref.mMatch));
+ }
+ continue;
+ }
+ // If it's not an "always" type preferred activity and that's what we're
+ // looking for, skip it.
+ if (always && !pa.mPref.mAlways) {
+ if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
+ continue;
+ }
+ final ActivityInfo ai = getActivityInfo(
+ pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
+ | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
+ userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
+ && !isDeviceProvisioned;
+ final boolean allowSetMutation = !excludeSetupWizardHomeActivity
+ && !queryMayBeFiltered;
+ if (ai == null) {
+ // Do not remove launcher's preferred activity during SetupWizard
+ // due to it may not install yet
+ if (!allowSetMutation) {
+ continue;
+ }
+
+ // This previously registered preferred activity
+ // component is no longer known. Most likely an update
+ // to the app was installed and in the new version this
+ // component no longer exists. Clean it up by removing
+ // it from the preferred activities list, and skip it.
+ Slog.w(TAG, "Removing dangling preferred activity: "
+ + pa.mPref.mComponent);
+ pir.removeFilter(pa);
+ result.mChanged = true;
+ continue;
+ }
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+
+ if (removeMatches && allowSetMutation) {
+ pir.removeFilter(pa);
+ result.mChanged = true;
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
+ }
+ break;
+ }
+
+ // Okay we found a previously set preferred or last chosen app.
+ // If the result set is different from when this
+ // was created, and is not a subset of the preferred set, we need to
+ // clear it and re-ask the user their preference, if we're looking for
+ // an "always" type entry.
+
+ if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
+ if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
+ if (allowSetMutation) {
+ // some components of the set are no longer present in
+ // the query, but the preferred activity can still be reused
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Result set changed, but PreferredActivity"
+ + " is still valid as only non-preferred"
+ + " components were removed for " + intent
+ + " type " + resolvedType);
+ }
+ // remove obsolete components and re-add the up-to-date
+ // filter
+ PreferredActivity freshPa = new PreferredActivity(pa,
+ pa.mPref.mMatch,
+ pa.mPref.discardObsoleteComponents(query),
+ pa.mPref.mComponent,
+ pa.mPref.mAlways);
+ pir.removeFilter(pa);
+ pir.addFilter(freshPa);
+ result.mChanged = true;
+ } else {
+ if (DEBUG_PREFERRED) {
+ Slog.i(TAG, "Do not remove preferred activity");
+ }
+ }
+ } else {
+ if (allowSetMutation) {
+ Slog.i(TAG,
+ "Result set changed, dropping preferred activity "
+ + "for " + intent + " type "
+ + resolvedType);
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG,
+ "Removing preferred activity since set changed "
+ + pa.mPref.mComponent);
+ }
+ pir.removeFilter(pa);
+ // Re-add the filter as a "last chosen" entry (!always)
+ PreferredActivity lastChosen = new PreferredActivity(
+ pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
+ false);
+ pir.addFilter(lastChosen);
+ result.mChanged = true;
+ }
+ result.mPreferredResolveInfo = null;
+ return result;
+ }
+ }
+
+ // Yay! Either the set matched or we're looking for the last chosen
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning preferred activity: "
+ + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ result.mPreferredResolveInfo = ri;
+ return result;
+ }
+ }
+ }
+ return result;
+ }
+
+ public final FindPreferredActivityBodyResult findPreferredActivityInternal(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+
+ final int callingUid = Binder.getCallingUid();
+ // Do NOT hold the packages lock; this calls up into the settings provider which
+ // could cause a deadlock.
+ final boolean isDeviceProvisioned =
+ android.provider.Settings.Global.getInt(mContext.getContentResolver(),
+ android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
+ // Find the preferred activity - the lock is held inside the method.
+ return findPreferredActivityBody(
+ intent, resolvedType, flags, query, always, removeMatches, debug,
+ userId, queryMayBeFiltered, callingUid, isDeviceProvisioned);
+ }
+
+ public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType,
+ int flags, List<ResolveInfo> query, boolean debug, int userId) {
+ final int N = query.size();
+ PersistentPreferredIntentResolver ppir =
+ mSettings.getPersistentPreferredActivities(userId);
+ // Get the list of persistent preferred activities that handle the intent
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Looking for persistent preferred activities...");
+ }
+ List<PersistentPreferredActivity> pprefs = ppir != null
+ ? ppir.queryIntent(intent, resolvedType,
+ (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
+ userId)
+ : null;
+ if (pprefs != null && pprefs.size() > 0) {
+ final int M = pprefs.size();
+ for (int i = 0; i < M; i++) {
+ final PersistentPreferredActivity ppa = pprefs.get(i);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Checking PersistentPreferredActivity ds="
+ + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
+ + "\n component=" + ppa.mComponent);
+ ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ }
+ final ActivityInfo ai = getActivityInfo(ppa.mComponent,
+ flags | MATCH_DISABLED_COMPONENTS, userId);
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Found persistent preferred activity:");
+ if (ai != null) {
+ ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
+ } else {
+ Slog.v(TAG, " null");
+ }
+ }
+ if (ai == null) {
+ // This previously registered persistent preferred activity
+ // component is no longer known. Ignore it and do NOT remove it.
+ continue;
+ }
+ for (int j = 0; j < N; j++) {
+ final ResolveInfo ri = query.get(j);
+ if (!ri.activityInfo.applicationInfo.packageName
+ .equals(ai.applicationInfo.packageName)) {
+ continue;
+ }
+ if (!ri.activityInfo.name.equals(ai.name)) {
+ continue;
+ }
+ // Found a persistent preference that can handle the intent.
+ if (DEBUG_PREFERRED || debug) {
+ Slog.v(TAG, "Returning persistent preferred activity: "
+ + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
+ }
+ return ri;
+ }
+ }
+ }
+ return null;
+ }
}
/**
@@ -5005,6 +5307,16 @@
super.dump(type, fd, pw, dumpState);
}
}
+ public final FindPreferredActivityBodyResult findPreferredActivityBody(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered,
+ int callingUid, boolean isDeviceProvisioned) {
+ synchronized (mLock) {
+ return super.findPreferredActivityBody(intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId, queryMayBeFiltered, callingUid,
+ isDeviceProvisioned);
+ }
+ }
}
/**
@@ -5572,6 +5884,28 @@
current.release();
}
}
+ public final FindPreferredActivityBodyResult findPreferredActivityInternal(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+ ThreadComputer current = live();
+ try {
+ return current.mComputer.findPreferredActivityInternal(intent, resolvedType, flags,
+ query, always, removeMatches, debug, userId, queryMayBeFiltered);
+ } finally {
+ current.release();
+ }
+ }
+ public final ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType, int flags, List<ResolveInfo> query, boolean debug,
+ int userId) {
+ ThreadComputer current = live();
+ try {
+ return current.mComputer.findPersistentPreferredActivityLP(intent, resolvedType,
+ flags, query, debug, userId);
+ } finally {
+ current.release();
+ }
+ }
}
@@ -9068,7 +9402,7 @@
/**
* Update given intent when being used to request {@link ResolveInfo}.
*/
- private Intent updateIntentForResolve(Intent intent) {
+ private static Intent updateIntentForResolve(Intent intent) {
if (intent.getSelector() != null) {
intent = intent.getSelector();
}
@@ -10411,69 +10745,38 @@
}
@GuardedBy("mLock")
- private ResolveInfo findPersistentPreferredActivityLP(Intent intent, String resolvedType,
+ private ResolveInfo findPersistentPreferredActivityLP(Intent intent,
+ String resolvedType,
int flags, List<ResolveInfo> query, boolean debug, int userId) {
- final int N = query.size();
- PersistentPreferredIntentResolver ppir = mSettings.getPersistentPreferredActivities(userId);
- // Get the list of persistent preferred activities that handle the intent
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for presistent preferred activities...");
- List<PersistentPreferredActivity> pprefs = ppir != null
- ? ppir.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId)
- : null;
- if (pprefs != null && pprefs.size() > 0) {
- final int M = pprefs.size();
- for (int i=0; i<M; i++) {
- final PersistentPreferredActivity ppa = pprefs.get(i);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Checking PersistentPreferredActivity ds="
- + (ppa.countDataSchemes() > 0 ? ppa.getDataScheme(0) : "<none>")
- + "\n component=" + ppa.mComponent);
- ppa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- }
- final ActivityInfo ai = getActivityInfo(ppa.mComponent,
- flags | MATCH_DISABLED_COMPONENTS, userId);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Found persistent preferred activity:");
- if (ai != null) {
- ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- } else {
- Slog.v(TAG, " null");
- }
- }
- if (ai == null) {
- // This previously registered persistent preferred activity
- // component is no longer known. Ignore it and do NOT remove it.
- continue;
- }
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (!ri.activityInfo.applicationInfo.packageName
- .equals(ai.applicationInfo.packageName)) {
- continue;
- }
- if (!ri.activityInfo.name.equals(ai.name)) {
- continue;
- }
- // Found a persistent preference that can handle the intent.
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Returning persistent preferred activity: " +
- ri.activityInfo.packageName + "/" + ri.activityInfo.name);
- }
- return ri;
- }
- }
- }
- return null;
+ return mComputer.findPersistentPreferredActivityLP(intent,
+ resolvedType,
+ flags, query, debug, userId);
}
- private boolean isHomeIntent(Intent intent) {
+ private static boolean isHomeIntent(Intent intent) {
return ACTION_MAIN.equals(intent.getAction())
&& intent.hasCategory(CATEGORY_HOME)
&& intent.hasCategory(CATEGORY_DEFAULT);
}
+
+ // findPreferredActivityBody returns two items: a "things changed" flag and a
+ // ResolveInfo, which is the preferred activity itself.
+ private static class FindPreferredActivityBodyResult {
+ boolean mChanged;
+ ResolveInfo mPreferredResolveInfo;
+ }
+
+ private FindPreferredActivityBodyResult findPreferredActivityInternal(
+ Intent intent, String resolvedType, int flags,
+ List<ResolveInfo> query, boolean always,
+ boolean removeMatches, boolean debug, int userId, boolean queryMayBeFiltered) {
+ return mComputer.findPreferredActivityInternal(
+ intent, resolvedType, flags,
+ query, always,
+ removeMatches, debug, userId, queryMayBeFiltered);
+ }
+
ResolveInfo findPreferredActivityNotLocked(Intent intent, String resolvedType, int flags,
List<ResolveInfo> query, int priority, boolean always,
boolean removeMatches, boolean debug, int userId) {
@@ -10492,206 +10795,22 @@
+ " is holding mLock", new Throwable());
}
if (!mUserManager.exists(userId)) return null;
- final int callingUid = Binder.getCallingUid();
- // Do NOT hold the packages lock; this calls up into the settings provider which
- // could cause a deadlock.
- final boolean isDeviceProvisioned =
- android.provider.Settings.Global.getInt(mContext.getContentResolver(),
- android.provider.Settings.Global.DEVICE_PROVISIONED, 0) == 1;
- flags = updateFlagsForResolve(
- flags, userId, callingUid, false /*includeInstantApps*/,
- isImplicitImageCaptureIntentAndNotSetByDpcLocked(intent, userId, resolvedType,
- flags));
- intent = updateIntentForResolve(intent);
- // writer
- synchronized (mLock) {
- // Try to find a matching persistent preferred activity.
- ResolveInfo pri = findPersistentPreferredActivityLP(intent, resolvedType, flags, query,
- debug, userId);
- // If a persistent preferred activity matched, use it.
- if (pri != null) {
- return pri;
+ FindPreferredActivityBodyResult body = findPreferredActivityInternal(
+ intent, resolvedType, flags, query, always,
+ removeMatches, debug, userId, queryMayBeFiltered);
+ if (body.mChanged) {
+ if (DEBUG_PREFERRED) {
+ Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
}
-
- PreferredIntentResolver pir = mSettings.getPreferredActivities(userId);
- // Get the list of preferred activities that handle the intent
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Looking for preferred activities...");
- List<PreferredActivity> prefs = pir != null
- ? pir.queryIntent(intent, resolvedType,
- (flags & PackageManager.MATCH_DEFAULT_ONLY) != 0,
- userId)
- : null;
- if (prefs != null && prefs.size() > 0) {
- boolean changed = false;
- try {
- // First figure out how good the original match set is.
- // We will only allow preferred activities that came
- // from the same match quality.
- int match = 0;
-
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Figuring out best match...");
-
- final int N = query.size();
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Match for " + ri.activityInfo
- + ": 0x" + Integer.toHexString(match));
- if (ri.match > match) {
- match = ri.match;
- }
- }
-
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Best match: 0x"
- + Integer.toHexString(match));
-
- match &= IntentFilter.MATCH_CATEGORY_MASK;
- final int M = prefs.size();
- for (int i=0; i<M; i++) {
- final PreferredActivity pa = prefs.get(i);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Checking PreferredActivity ds="
- + (pa.countDataSchemes() > 0 ? pa.getDataScheme(0) : "<none>")
- + "\n component=" + pa.mPref.mComponent);
- pa.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- }
- if (pa.mPref.mMatch != match) {
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping bad match "
- + Integer.toHexString(pa.mPref.mMatch));
- continue;
- }
- // If it's not an "always" type preferred activity and that's what we're
- // looking for, skip it.
- if (always && !pa.mPref.mAlways) {
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Skipping mAlways=false entry");
- continue;
- }
- final ActivityInfo ai = getActivityInfo(
- pa.mPref.mComponent, flags | MATCH_DISABLED_COMPONENTS
- | MATCH_DIRECT_BOOT_AWARE | MATCH_DIRECT_BOOT_UNAWARE,
- userId);
- if (DEBUG_PREFERRED || debug) {
- Slog.v(TAG, "Found preferred activity:");
- if (ai != null) {
- ai.dump(new LogPrinter(Log.VERBOSE, TAG, Log.LOG_ID_SYSTEM), " ");
- } else {
- Slog.v(TAG, " null");
- }
- }
- final boolean excludeSetupWizardHomeActivity = isHomeIntent(intent)
- && !isDeviceProvisioned;
- final boolean allowSetMutation = !excludeSetupWizardHomeActivity
- && !queryMayBeFiltered;
- if (ai == null) {
- // Do not remove launcher's preferred activity during SetupWizard
- // due to it may not install yet
- if (!allowSetMutation) {
- continue;
- }
-
- // This previously registered preferred activity
- // component is no longer known. Most likely an update
- // to the app was installed and in the new version this
- // component no longer exists. Clean it up by removing
- // it from the preferred activities list, and skip it.
- Slog.w(TAG, "Removing dangling preferred activity: "
- + pa.mPref.mComponent);
- pir.removeFilter(pa);
- changed = true;
- continue;
- }
- for (int j=0; j<N; j++) {
- final ResolveInfo ri = query.get(j);
- if (!ri.activityInfo.applicationInfo.packageName
- .equals(ai.applicationInfo.packageName)) {
- continue;
- }
- if (!ri.activityInfo.name.equals(ai.name)) {
- continue;
- }
-
- if (removeMatches && allowSetMutation) {
- pir.removeFilter(pa);
- changed = true;
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Removing match " + pa.mPref.mComponent);
- }
- break;
- }
-
- // Okay we found a previously set preferred or last chosen app.
- // If the result set is different from when this
- // was created, and is not a subset of the preferred set, we need to
- // clear it and re-ask the user their preference, if we're looking for
- // an "always" type entry.
-
- if (always && !pa.mPref.sameSet(query, excludeSetupWizardHomeActivity)) {
- if (pa.mPref.isSuperset(query, excludeSetupWizardHomeActivity)) {
- if (allowSetMutation) {
- // some components of the set are no longer present in
- // the query, but the preferred activity can still be reused
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Result set changed, but PreferredActivity"
- + " is still valid as only non-preferred"
- + " components were removed for " + intent
- + " type " + resolvedType);
- }
- // remove obsolete components and re-add the up-to-date
- // filter
- PreferredActivity freshPa = new PreferredActivity(pa,
- pa.mPref.mMatch,
- pa.mPref.discardObsoleteComponents(query),
- pa.mPref.mComponent,
- pa.mPref.mAlways);
- pir.removeFilter(pa);
- pir.addFilter(freshPa);
- changed = true;
- } else {
- if (DEBUG_PREFERRED) {
- Slog.i(TAG, "Do not remove preferred activity");
- }
- }
- } else {
- if (allowSetMutation) {
- Slog.i(TAG,
- "Result set changed, dropping preferred activity "
- + "for " + intent + " type "
- + resolvedType);
- if (DEBUG_PREFERRED) {
- Slog.v(TAG,
- "Removing preferred activity since set changed "
- + pa.mPref.mComponent);
- }
- pir.removeFilter(pa);
- // Re-add the filter as a "last chosen" entry (!always)
- PreferredActivity lastChosen = new PreferredActivity(
- pa, pa.mPref.mMatch, null, pa.mPref.mComponent,
- false);
- pir.addFilter(lastChosen);
- changed = true;
- }
- return null;
- }
- }
-
- // Yay! Either the set matched or we're looking for the last chosen
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "Returning preferred activity: "
- + ri.activityInfo.packageName + "/" + ri.activityInfo.name);
- return ri;
- }
- }
- } finally {
- if (changed) {
- if (DEBUG_PREFERRED) {
- Slog.v(TAG, "Preferred activity bookkeeping changed; writing restrictions");
- }
- scheduleWritePackageRestrictionsLocked(userId);
- }
- }
+ synchronized (mLock) {
+ scheduleWritePackageRestrictionsLocked(userId);
}
}
- if (DEBUG_PREFERRED || debug) Slog.v(TAG, "No preferred activity to return");
- return null;
+ if ((DEBUG_PREFERRED || debug) && body.mPreferredResolveInfo == null) {
+ Slog.v(TAG, "No preferred activity to return");
+ }
+ return body.mPreferredResolveInfo;
}
/*
diff --git a/services/core/java/com/android/server/pm/permission/Permission.java b/services/core/java/com/android/server/pm/permission/Permission.java
index cda4806..94e551a 100644
--- a/services/core/java/com/android/server/pm/permission/Permission.java
+++ b/services/core/java/com/android/server/pm/permission/Permission.java
@@ -480,9 +480,10 @@
r.append("DUP:");
r.append(permissionInfo.name);
}
- if (permission.isRuntime() && (ownerChanged || wasNonRuntime)) {
- // If this is a runtime permission and the owner has changed, or this wasn't a runtime
- // permission, then permission state should be cleaned up
+ if ((permission.isInternal() && ownerChanged)
+ || (permission.isRuntime() && (ownerChanged || wasNonRuntime))) {
+ // If this is an internal/runtime permission and the owner has changed, or this wasn't a
+ // runtime permission, then permission state should be cleaned up.
permission.mDefinitionChanged = true;
}
if (PackageManagerService.DEBUG_PACKAGE_SCANNING && r != null) {
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index c11ffb4..54a6c67 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -1654,7 +1654,8 @@
isRolePermission = permission.isRole();
}
final boolean mayRevokeRolePermission = isRolePermission
- && mayManageRolePermission(callingUid);
+ // Allow ourselves to revoke role permissions due to definition changes.
+ && (callingUid == Process.myUid() || mayManageRolePermission(callingUid));
final boolean isRuntimePermission;
synchronized (mLock) {
@@ -2332,11 +2333,13 @@
for (int permNum = 0; permNum < numPermissions; permNum++) {
final String permName = permissionsToRevoke.get(permNum);
+ final boolean isInternalPermission;
synchronized (mLock) {
final Permission bp = mRegistry.getPermission(permName);
- if (bp == null || !bp.isRuntime()) {
+ if (bp == null || !(bp.isInternal() || bp.isRuntime())) {
continue;
}
+ isInternalPermission = bp.isInternal();
}
mPackageManagerInt.forEachPackage(pkg -> {
final String packageName = pkg.getPackageName();
@@ -2356,12 +2359,18 @@
if (permissionState == PackageManager.PERMISSION_GRANTED
&& (flags & flagMask) == 0) {
final int uid = UserHandle.getUid(userId, appId);
- EventLog.writeEvent(0x534e4554, "154505240", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
- EventLog.writeEvent(0x534e4554, "168319670", uid,
- "Revoking permission " + permName + " from package "
- + packageName + " due to definition change");
+ if (isInternalPermission) {
+ EventLog.writeEvent(0x534e4554, "195338390", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ } else {
+ EventLog.writeEvent(0x534e4554, "154505240", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ EventLog.writeEvent(0x534e4554, "168319670", uid,
+ "Revoking permission " + permName + " from package "
+ + packageName + " due to definition change");
+ }
Slog.e(TAG, "Revoking permission " + permName + " from package "
+ packageName + " due to definition change");
try {
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index ff7e903..b58ca1f 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -785,13 +785,14 @@
@Override
public void showAuthenticationDialog(PromptInfo promptInfo, IBiometricSysuiReceiver receiver,
int[] sensorIds, boolean credentialAllowed, boolean requireConfirmation,
- int userId, String opPackageName, long operationId,
+ int userId, long operationId, String opPackageName, long requestId,
@BiometricMultiSensorMode int multiSensorConfig) {
enforceBiometricDialog();
if (mBar != null) {
try {
mBar.showAuthenticationDialog(promptInfo, receiver, sensorIds, credentialAllowed,
- requireConfirmation, userId, opPackageName, operationId, multiSensorConfig);
+ requireConfirmation, userId, operationId, opPackageName, requestId,
+ multiSensorConfig);
} catch (RemoteException ex) {
}
}
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 36a854e..2894708 100755
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -2304,10 +2304,9 @@
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
+ final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+ Binder.getCallingUid(), userId, "requestChannelBrowsable");
final long identity = Binder.clearCallingIdentity();
- final int callingUid = Binder.getCallingUid();
- final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
- userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
diff --git a/services/core/java/com/android/server/vr/Vr2dDisplay.java b/services/core/java/com/android/server/vr/Vr2dDisplay.java
index a713e5b..39d7a15 100644
--- a/services/core/java/com/android/server/vr/Vr2dDisplay.java
+++ b/services/core/java/com/android/server/vr/Vr2dDisplay.java
@@ -302,7 +302,8 @@
builder.setUniqueId(UNIQUE_DISPLAY_ID);
builder.setFlags(flags);
mVirtualDisplay = mDisplayManager.createVirtualDisplay(null /* projection */,
- builder.build(), null /* callback */, null /* handler */);
+ builder.build(), null /* callback */, null /* handler */,
+ null /* windowContext */);
if (mVirtualDisplay != null) {
updateDisplayId(mVirtualDisplay.getDisplay().getDisplayId());
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index a4d2348..cea30ed 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -43,6 +43,7 @@
import static com.android.server.accessibility.AccessibilityTraceProto.WINDOW_MANAGER_SERVICE;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowTracing.WINSCOPE_EXT;
import static com.android.server.wm.utils.RegionUtils.forEachRect;
import android.accessibilityservice.AccessibilityTrace;
@@ -2081,7 +2082,7 @@
}
private static final int BUFFER_CAPACITY = 1024 * 1024 * 12;
- private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace.pb";
+ private static final String TRACE_FILENAME = "/data/misc/a11ytrace/a11y_trace" + WINSCOPE_EXT;
private static final String TAG = "AccessibilityTracing";
private static final long MAGIC_NUMBER_VALUE =
((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 67043db..8f777e6 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -285,7 +285,6 @@
import android.os.SystemClock;
import android.os.Trace;
import android.os.UserHandle;
-import android.os.storage.StorageManager;
import android.service.contentcapture.ActivityEvent;
import android.service.dreams.DreamActivity;
import android.service.dreams.DreamManagerInternal;
@@ -317,7 +316,7 @@
import android.view.WindowManager.LayoutParams;
import android.view.WindowManager.TransitionOldType;
import android.view.animation.Animation;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.SizeConfigurationBuckets;
import android.window.SplashScreen;
import android.window.SplashScreenView;
@@ -491,7 +490,7 @@
private ActivityOptions mPendingOptions;
/** Non-null if {@link #mPendingOptions} specifies the remote animation. */
private RemoteAnimationAdapter mPendingRemoteAnimation;
- private IRemoteTransition mPendingRemoteTransition;
+ private RemoteTransition mPendingRemoteTransition;
ActivityOptions returningOptions; // options that are coming back via convertToTranslucent
AppTimeTracker appTimeTracker; // set if we are tracking the time in this app/task/activity
ActivityServiceConnectionsHolder mServiceConnectionsHolder; // Service connections.
@@ -730,7 +729,7 @@
// TODO: rename to mNoDisplay
@VisibleForTesting
boolean noDisplay;
- boolean mShowForAllUsers;
+ final boolean mShowForAllUsers;
// TODO: Make this final
int mTargetSdk;
@@ -1022,7 +1021,8 @@
pw.println(mPendingRemoteAnimation.getCallingPid());
}
if (mPendingRemoteTransition != null) {
- pw.print(prefix + " pendingRemoteTransition=" + mPendingRemoteTransition);
+ pw.print(prefix + " pendingRemoteTransition="
+ + mPendingRemoteTransition.getRemoteTransition());
}
if (appTimeTracker != null) {
appTimeTracker.dumpWithHeader(pw, prefix, false);
@@ -1354,14 +1354,8 @@
updatePictureInPictureMode(null, false);
} else {
mLastReportedMultiWindowMode = inMultiWindowMode;
- // If the activity is in stopping or stopped state, for instance, it's in the
- // split screen task and not the top one, the last configuration it should keep
- // is the one before multi-window mode change.
- final State state = getState();
- if (state != STOPPED && state != STOPPING) {
- ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
- true /* ignoreVisibility */);
- }
+ ensureActivityConfiguration(0 /* globalChanges */, PRESERVE_WINDOWS,
+ false /* ignoreVisibility */);
}
}
}
@@ -2595,6 +2589,13 @@
return task != null ? task.getOrganizedTask() : null;
}
+ /** Returns the organized parent {@link TaskFragment}. */
+ @Nullable
+ TaskFragment getOrganizedTaskFragment() {
+ final TaskFragment parent = getTaskFragment();
+ return parent != null ? parent.getOrganizedTaskFragment() : null;
+ }
+
@Override
@Nullable
TaskDisplayArea getDisplayArea() {
@@ -4307,7 +4308,7 @@
// The activity now gets access to the data associated with this Intent.
mAtmService.mUgmInternal.grantUriPermissionUncheckedFromIntent(intentGrants,
getUriPermissionsLocked());
- final ReferrerIntent rintent = new ReferrerIntent(intent, referrer);
+ final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer));
boolean unsent = true;
final boolean isTopActivityWhileSleeping = isTopRunningActivity() && isSleeping();
@@ -4578,8 +4579,8 @@
return opts;
}
- IRemoteTransition takeRemoteTransition() {
- IRemoteTransition out = mPendingRemoteTransition;
+ RemoteTransition takeRemoteTransition() {
+ RemoteTransition out = mPendingRemoteTransition;
mPendingRemoteTransition = null;
return out;
}
@@ -4893,6 +4894,15 @@
// getting visible so we also wait for them.
forAllWindows(mWmService::makeWindowFreezingScreenIfNeededLocked, true);
}
+ // dispatchTaskInfoChangedIfNeeded() right after ActivityRecord#setVisibility() can report
+ // the stale visible state, because the state will be updated after the app transition.
+ // So tries to report the actual visible state again where the state is changed.
+ if (!mTaskSupervisor.inActivityVisibilityUpdate()) {
+ final Task task = getOrganizedTask();
+ if (task != null) {
+ task.dispatchTaskInfoChangedIfNeeded(false /* force */);
+ }
+ }
ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
"commitVisibility: %s: visible=%b mVisibleRequested=%b", this,
isVisible(), mVisibleRequested);
@@ -5298,7 +5308,7 @@
void updateVisibilityIgnoringKeyguard(boolean behindFullscreenActivity) {
visibleIgnoringKeyguard = (!behindFullscreenActivity || mLaunchTaskBehind)
- && okToShowLocked();
+ && showToCurrentUser();
}
boolean shouldBeVisible() {
@@ -6335,22 +6345,8 @@
return this;
}
- /** Checks whether the activity should be shown for current user. */
- public boolean okToShowLocked() {
- // We cannot show activities when the device is locked and the application is not
- // encryption aware.
- if (!StorageManager.isUserKeyUnlocked(mUserId)
- && !info.applicationInfo.isEncryptionAware()) {
- return false;
- }
-
- return (info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0
- || (mTaskSupervisor.isCurrentProfileLocked(mUserId)
- && mAtmService.mAmInternal.isUserRunning(mUserId, 0 /* flags */));
- }
-
boolean canBeTopRunning() {
- return !finishing && okToShowLocked();
+ return !finishing && showToCurrentUser();
}
/**
@@ -6958,7 +6954,7 @@
Rect appRect;
if (win != null) {
insets = win.getInsetsStateWithVisibilityOverride().calculateInsets(
- win.getFrame(), Type.systemBars(), false /* ignoreVisibility */);
+ win.getFrame(), Type.systemBars(), false /* ignoreVisibility */).toRect();
appRect = new Rect(win.getFrame());
appRect.inset(insets);
} else {
@@ -8411,7 +8407,9 @@
startFreezingScreenLocked(globalChanges);
}
forceNewConfig = false;
- preserveWindow &= isResizeOnlyChange(changes);
+ // Do not preserve window if it is freezing screen because the original window won't be
+ // able to update drawn state that causes freeze timeout.
+ preserveWindow &= isResizeOnlyChange(changes) && !mFreezingScreen;
final boolean hasResizeChange = hasResizeChange(changes & ~info.getRealConfigChanged());
if (hasResizeChange) {
final boolean isDragResizing = task.isDragResizing();
@@ -8815,6 +8813,19 @@
}
/**
+ * Gets the referrer package name with respect to package visibility. This method returns null
+ * if the given package is not visible to this activity.
+ */
+ String getFilteredReferrer(String referrerPackage) {
+ if (referrerPackage == null || (!referrerPackage.equals(packageName)
+ && mWmService.mPmInternal.filterAppAccess(
+ referrerPackage, info.applicationInfo.uid, mUserId))) {
+ return null;
+ }
+ return referrerPackage;
+ }
+
+ /**
* Determines whether this ActivityRecord can turn the screen on. It checks whether the flag
* {@link ActivityRecord#getTurnScreenOnFlag} is set and checks whether the ActivityRecord
* should be visible depending on Keyguard state.
@@ -9211,7 +9222,7 @@
return null;
}
final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
- task.getBounds(), Type.systemBars(), false /* ignoreVisibility */);
+ task.getBounds(), Type.systemBars(), false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, getLetterboxInsets());
return new RemoteAnimationTarget(task.mTaskId, record.getMode(),
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index af538272..3b43e48 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -115,7 +115,7 @@
import android.util.DebugUtils;
import android.util.Pools.SynchronizedPool;
import android.util.Slog;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.app.HeavyWeightSwitcherActivity;
@@ -1568,7 +1568,7 @@
final Transition newTransition = (!mService.getTransitionController().isCollecting()
&& mService.getTransitionController().getTransitionPlayer() != null)
? mService.getTransitionController().createTransition(TRANSIT_OPEN) : null;
- IRemoteTransition remoteTransition = r.takeRemoteTransition();
+ RemoteTransition remoteTransition = r.takeRemoteTransition();
if (newTransition != null && remoteTransition != null) {
newTransition.setRemoteTransition(remoteTransition);
}
@@ -2357,7 +2357,7 @@
// of this in the record so that we can skip it when trying to find
// the top running activity.
mDoResume = doResume;
- if (!doResume || !r.okToShowLocked() || mLaunchTaskBehind) {
+ if (!doResume || !r.showToCurrentUser() || mLaunchTaskBehind) {
r.delayedResume = true;
mDoResume = false;
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index 081c618..1652c3b 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -4066,6 +4066,9 @@
final long origId = Binder.clearCallingIdentity();
try {
synchronized (mGlobalLock) {
+ // Window configuration is unrelated to persistent configuration (e.g. font scale,
+ // locale). Unset it to avoid affecting the current display configuration.
+ values.windowConfiguration.setToDefaults();
updateConfigurationLocked(values, null, false, true, userId,
false /* deferResume */);
}
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index e593c1c..e6aa4fc 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -857,9 +857,9 @@
// and override configs.
mergedConfiguration.getGlobalConfiguration(),
mergedConfiguration.getOverrideConfiguration(), r.compat,
- r.launchedFromPackage, task.voiceInteractor, proc.getReportedProcState(),
- r.getSavedState(), r.getPersistentSavedState(), results, newIntents,
- r.takeOptions(), isTransitionForward,
+ r.getFilteredReferrer(r.launchedFromPackage), task.voiceInteractor,
+ proc.getReportedProcState(), r.getSavedState(), r.getPersistentSavedState(),
+ results, newIntents, r.takeOptions(), isTransitionForward,
proc.createProfilerInfoIfNeeded(), r.assistToken, activityClientController,
r.createFixedRotationAdjustmentsIfNeeded(), r.shareableActivityToken,
r.getLaunchedFromBubble(), fragmentToken));
@@ -1872,12 +1872,6 @@
mHandler.obtainMessage(LAUNCH_TASK_BEHIND_COMPLETE, token).sendToTarget();
}
- /** Checks whether the userid is a profile of the current user. */
- boolean isCurrentProfileLocked(int userId) {
- if (userId == mRootWindowContainer.mCurrentUser) return true;
- return mService.mAmInternal.isCurrentProfile(userId);
- }
-
/**
* Processes the activities to be stopped or destroyed. This should be called when the resumed
* activities are idle or drawn.
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 544cade..7a42351 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -86,6 +86,7 @@
import android.view.WindowManager.TransitionOldType;
import android.view.WindowManager.TransitionType;
import android.view.animation.Animation;
+import android.window.ITaskFragmentOrganizer;
import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.common.ProtoLog;
@@ -233,7 +234,11 @@
final ActivityRecord topChangingApp =
getTopApp(mDisplayContent.mChangingContainers, false /* ignoreHidden */);
final WindowManager.LayoutParams animLp = getAnimLp(animLpActivity);
- overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+
+ // Check if there is any override
+ if (!overrideWithTaskFragmentRemoteAnimation(transit, activityTypes)) {
+ overrideWithRemoteAnimationIfSet(animLpActivity, transit, activityTypes);
+ }
final boolean voiceInteraction = containsVoiceInteraction(mDisplayContent.mOpeningApps)
|| containsVoiceInteraction(mDisplayContent.mOpeningApps);
@@ -483,6 +488,7 @@
return TYPE_NONE;
}
+ @Nullable
private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) {
final WindowState mainWindow = activity != null ? activity.findMainWindow() : null;
return mainWindow != null ? mainWindow.mAttrs : null;
@@ -506,6 +512,61 @@
}
/**
+ * Overrides the pending transition with the remote animation defined by the
+ * {@link ITaskFragmentOrganizer} if all windows in the transition are children of
+ * {@link TaskFragment} that are organized by the same organizer.
+ *
+ * @return {@code true} if the transition is overridden.
+ */
+ @VisibleForTesting
+ boolean overrideWithTaskFragmentRemoteAnimation(@TransitionOldType int transit,
+ ArraySet<Integer> activityTypes) {
+ final ArrayList<WindowContainer> allWindows = new ArrayList<>();
+ allWindows.addAll(mDisplayContent.mClosingApps);
+ allWindows.addAll(mDisplayContent.mOpeningApps);
+ allWindows.addAll(mDisplayContent.mChangingContainers);
+
+ // Find the common TaskFragmentOrganizer of all windows.
+ ITaskFragmentOrganizer organizer = null;
+ for (int i = allWindows.size() - 1; i >= 0; i--) {
+ final ActivityRecord r = getAppFromContainer(allWindows.get(i));
+ if (r == null) {
+ return false;
+ }
+ final TaskFragment organizedTaskFragment = r.getOrganizedTaskFragment();
+ final ITaskFragmentOrganizer curOrganizer = organizedTaskFragment != null
+ ? organizedTaskFragment.getTaskFragmentOrganizer()
+ : null;
+ if (curOrganizer == null) {
+ // All windows must below an organized TaskFragment.
+ return false;
+ }
+ if (organizer == null) {
+ organizer = curOrganizer;
+ } else if (!organizer.asBinder().equals(curOrganizer.asBinder())) {
+ // They must be controlled by the same organizer.
+ return false;
+ }
+ }
+
+ final RemoteAnimationDefinition definition = organizer != null
+ ? mDisplayContent.mAtmService.mTaskFragmentOrganizerController
+ .getRemoteAnimationDefinition(organizer)
+ : null;
+ final RemoteAnimationAdapter adapter = definition != null
+ ? definition.getAdapter(transit, activityTypes)
+ : null;
+ if (adapter == null) {
+ return false;
+ }
+ mDisplayContent.mAppTransition.overridePendingAppTransitionRemote(adapter);
+ ProtoLog.v(WM_DEBUG_APP_TRANSITIONS,
+ "Override with TaskFragment remote animation for transit=%s",
+ AppTransition.appTransitionOldToString(transit));
+ return true;
+ }
+
+ /**
* Overrides the pending transition with the remote animation defined for the transition in the
* set of defined remote animations in the app window token.
*/
@@ -524,13 +585,14 @@
}
static ActivityRecord getAppFromContainer(WindowContainer wc) {
- return wc.asTask() != null ? wc.asTask().getTopNonFinishingActivity()
+ return wc.asTaskFragment() != null ? wc.asTaskFragment().getTopNonFinishingActivity()
: wc.asActivityRecord();
}
/**
* @return The window token that determines the animation theme.
*/
+ @Nullable
private ActivityRecord findAnimLayoutParamsToken(@TransitionOldType int transit,
ArraySet<Integer> activityTypes) {
ActivityRecord result;
@@ -543,7 +605,7 @@
w -> w.getRemoteAnimationDefinition() != null
&& w.getRemoteAnimationDefinition().hasTransition(transit, activityTypes));
if (result != null) {
- return getAppFromContainer(result);
+ return result;
}
result = lookForHighestTokenWithFilter(closingApps, openingApps, changingApps,
w -> w.fillsParent() && w.findMainWindow() != null);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 62a6f39..199159e 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -61,7 +61,6 @@
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
import static android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN;
@@ -88,6 +87,7 @@
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_FOCUS_LIGHT;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_LAYER_MIRRORING;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_SCREEN_ON;
import static com.android.internal.protolog.ProtoLogGroup.WM_SHOW_TRANSACTIONS;
@@ -305,7 +305,8 @@
@VisibleForTesting IBinder mTokenToMirror = null;
/**
- * The surface for mirroring the contents of this hierarchy.
+ * The surface for mirroring the contents of this hierarchy, or null if layer mirroring is
+ * temporarily disabled.
*/
private SurfaceControl mMirroredSurface = null;
@@ -314,6 +315,11 @@
*/
private Rect mLastMirroredDisplayAreaBounds = null;
+ /**
+ * The last state of the display.
+ */
+ private int mLastDisplayState;
+
// Contains all IME window containers. Note that the z-ordering of the IME windows will depend
// on the IME target. We mainly have this container grouping so we can keep track of all the IME
// window containers together and move them in-sync if/when needed. We use a subclass of
@@ -1142,10 +1148,6 @@
if (DEBUG_DISPLAY) Slog.v(TAG_WM, "Creating display=" + display);
mWmService.mDisplayWindowSettings.applySettingsToDisplayLocked(this);
-
- // Check if this DisplayContent is for a new VirtualDisplay, that should use layer mirroring
- // to capture the contents of a DisplayArea.
- startMirrorIfNeeded();
}
boolean isReady() {
@@ -1207,10 +1209,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;
}
@@ -1288,7 +1290,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;
@@ -2504,19 +2506,42 @@
// Update mirroring surface for MediaProjection, if this DisplayContent is being used
// for layer mirroring.
- if (mMirroredSurface != null) {
- // Retrieve the size of the DisplayArea to mirror, and continue with the update if the
- // bounds have changed.
+ if (isCurrentlyMirroring() && mLastMirroredDisplayAreaBounds != null) {
+ // Mirroring has already begun, but update mirroring since the display is now on.
final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
mTokenToMirror);
- if (wc != null && mLastMirroredDisplayAreaBounds != null) {
- // Retrieve the size of the DisplayArea to mirror, and continue with the update
- // if the bounds or orientation has changed.
- final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
- int displayAreaOrientation = wc.getDisplayContent().getOrientation();
- if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
- || lastOrientation != displayAreaOrientation) {
- updateMirroredSurface(mWmService.mTransactionFactory.get(), displayAreaBounds);
+ if (wc == null) {
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Unable to retrieve window container to update layer mirroring for "
+ + "display %d",
+ mDisplayId);
+ return;
+ }
+
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Display %d was already layer mirroring, so apply transformations if necessary",
+ mDisplayId);
+ // Retrieve the size of the DisplayArea to mirror, and continue with the update
+ // if the bounds or orientation has changed.
+ final Rect displayAreaBounds = wc.getDisplayContent().getBounds();
+ int displayAreaOrientation = wc.getDisplayContent().getOrientation();
+ if (!mLastMirroredDisplayAreaBounds.equals(displayAreaBounds)
+ || lastOrientation != displayAreaOrientation) {
+ Point surfaceSize = fetchSurfaceSizeIfPresent();
+ if (surfaceSize != null) {
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Going ahead with updating layer mirroring for display %d to new "
+ + "bounds %s and/or orientation %d.",
+ mDisplayId, displayAreaBounds, displayAreaOrientation);
+ updateMirroredSurface(mWmService.mTransactionFactory.get(),
+ displayAreaBounds, surfaceSize);
+ } else {
+ // If the surface removed, do nothing. We will handle this via onDisplayChanged
+ // (the display will be off if the surface is removed).
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Unable to update layer mirroring for display %d to new bounds %s"
+ + " and/or orientation %d, since the surface is not available.",
+ mDisplayId, displayAreaBounds, displayAreaOrientation);
}
}
}
@@ -3139,6 +3164,12 @@
return mScreenRotationAnimation;
}
+ /** If the display is in transition, there should be a screenshot covering it. */
+ @Override
+ boolean inTransition() {
+ return mScreenRotationAnimation != null || super.inTransition();
+ }
+
@Override
public void dumpDebug(ProtoOutputStream proto, long fieldId,
@WindowTraceLogLevel int logLevel) {
@@ -4399,6 +4430,7 @@
mTmpApplySurfaceChangesTransactionState.preferMinimalPostProcessing,
true /* inTraversal, must call performTraversalInTrans... below */);
}
+ // If the display now has content, or no longer has content, update layer mirroring.
updateMirroring();
final boolean wallpaperVisible = mWallpaperController.isWallpaperVisible();
@@ -5498,6 +5530,15 @@
} else if (displayState == Display.STATE_ON) {
mOffTokenAcquirer.release(mDisplayId);
}
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Display %d state is now (%d), so update layer mirroring?",
+ mDisplayId, displayState);
+ if (mLastDisplayState != displayState) {
+ // If state is on due to surface being added, then start layer mirroring.
+ // If state is off due to surface being removed, then stop layer mirroring.
+ updateMirroring();
+ }
+ mLastDisplayState = displayState;
}
mWmService.requestTraversal();
}
@@ -5687,7 +5728,8 @@
final Configuration currOverrideConfig = getRequestedOverrideConfiguration();
final int currRotation = currOverrideConfig.windowConfiguration.getRotation();
final int overrideRotation = overrideConfiguration.windowConfiguration.getRotation();
- if (currRotation != ROTATION_UNDEFINED && currRotation != overrideRotation) {
+ if (currRotation != ROTATION_UNDEFINED && overrideRotation != ROTATION_UNDEFINED
+ && currRotation != overrideRotation) {
applyRotationAndFinishFixedRotation(currRotation, overrideRotation);
}
mCurrentOverrideConfigurationChanges = currOverrideConfig.diff(overrideConfiguration);
@@ -5976,31 +6018,48 @@
* back to original MediaProjection approach.
*/
private void startMirrorIfNeeded() {
- // Only mirror if this display does not have its own content.
- if (mLastHasContent) {
+ // Only mirror if this display does not have its own content, is not mirroring already,
+ // and if this display is on (it has a surface to write output to).
+ if (mLastHasContent || isCurrentlyMirroring() || mDisplay.getState() == Display.STATE_OFF) {
return;
}
+
// Given the WindowToken of the DisplayArea to mirror, retrieve the associated
// SurfaceControl.
IBinder tokenToMirror = mWmService.mDisplayManagerInternal.getWindowTokenClientToMirror(
mDisplayId);
-
if (tokenToMirror == null) {
// This DisplayContent instance is not involved in layer mirroring. If the display
// has been created for capturing, fall back to prior MediaProjection approach.
return;
}
+
final WindowContainer wc = mWmService.mWindowContextListenerController.getContainer(
tokenToMirror);
if (wc == null) {
// Un-set the window token to mirror for this VirtualDisplay, to fall back to the
// original MediaProjection approach.
mWmService.mDisplayManagerInternal.setWindowTokenClientToMirror(mDisplayId, null);
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Unable to retrieve window container to start layer mirroring for display %d",
+ mDisplayId);
return;
}
- SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
+
+ Point surfaceSize = fetchSurfaceSizeIfPresent();
+ if (surfaceSize == null) {
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Unable to start layer mirroring for display %d since the surface is not "
+ + "available.",
+ mDisplayId);
+ return;
+ }
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Display %d has no content and is on, so start layer mirroring for state %d",
+ mDisplayId, mDisplay.getState());
// Create a mirrored hierarchy for the SurfaceControl of the DisplayArea to capture.
+ SurfaceControl sc = wc.getDisplayContent().getSurfaceControl();
mMirroredSurface = SurfaceControl.mirrorSurface(sc);
SurfaceControl.Transaction transaction = mWmService.mTransactionFactory.get()
// Set the mMirroredSurface's parent to the root SurfaceControl for this
@@ -6013,7 +6072,7 @@
// VirtualDisplay will show up as part of the mirrored content.
.reparent(mWindowingLayer, null);
// Retrieve the size of the DisplayArea to mirror.
- updateMirroredSurface(transaction, wc.getDisplayContent().getBounds());
+ updateMirroredSurface(transaction, wc.getDisplayContent().getBounds(), surfaceSize);
mTokenToMirror = tokenToMirror;
// No need to clean up. In SurfaceFlinger, parents hold references to their children. The
@@ -6023,11 +6082,18 @@
}
/**
- * Start or stop mirroring if this DisplayContent now has content, or no longer has content.
+ * Start mirroring if this DisplayContent no longer has content. Stop mirroring if it now
+ * has content or the display is not on.
*/
private void updateMirroring() {
- if (mLastHasContent && mMirroredSurface != null) {
- // Display now has content, so stop mirroring to it.
+ if (isCurrentlyMirroring() && (mLastHasContent
+ || mDisplay.getState() == Display.STATE_OFF)) {
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Display %d has content (%b) so disable layer mirroring", mDisplayId,
+ mLastHasContent);
+ // If the display is not on and it is a virtual display, then it no longer has an
+ // associated surface to write output to.
+ // If the display now has content, stop mirroring to it.
mWmService.mTransactionFactory.get()
// Remove the reference to mMirroredSurface, to clean up associated memory.
.remove(mMirroredSurface)
@@ -6038,8 +6104,9 @@
// Stop mirroring by destroying the reference to the mirrored layer.
mMirroredSurface = null;
// Do not un-set the token, in case content is removed and mirroring should begin again.
- } else if (!mLastHasContent && mMirroredSurface == null) {
- // Display no longer has content, so start mirroring to it.
+ } else {
+ // Display no longer has content, or now has a surface to write to, so try to start
+ // mirroring to it.
startMirrorIfNeeded();
}
}
@@ -6048,21 +6115,15 @@
* Apply transformations to the mirrored surface to ensure the captured contents are scaled to
* fit and centred in the output surface.
*
- * @param transaction the transaction to include transformations of mMirroredSurface
- * to. Transaction is not applied before returning.
- * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by
- * the app.
+ * @param transaction the transaction to include transformations of mMirroredSurface
+ * to. Transaction is not applied before returning.
+ * @param displayAreaBounds bounds of the DisplayArea to mirror to the surface provided by
+ * the app.
+ * @param surfaceSize the default size of the surface to write the display area content to
*/
@VisibleForTesting
void updateMirroredSurface(SurfaceControl.Transaction transaction,
- Rect displayAreaBounds) {
- // Retrieve the default size of the surface the app provided to
- // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
- // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
- // it writes the mirrored layers to the buffers.
- final Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
- mDisplayId);
-
+ Rect displayAreaBounds, Point surfaceSize) {
// Calculate the scale to apply to the root mirror SurfaceControl to fit the size of the
// output surface.
float scaleX = surfaceSize.x / (float) displayAreaBounds.width();
@@ -6097,6 +6158,36 @@
mLastMirroredDisplayAreaBounds = new Rect(displayAreaBounds);
}
+ /**
+ * Returns a non-null {@link Point} if the surface is present, or null otherwise
+ */
+ Point fetchSurfaceSizeIfPresent() {
+ // Retrieve the default size of the surface the app provided to
+ // MediaProjection#createVirtualDisplay. Note the app is the consumer of the surface,
+ // since it reads out buffers from the surface, and SurfaceFlinger is the producer since
+ // it writes the mirrored layers to the buffers.
+ Point surfaceSize = mWmService.mDisplayManagerInternal.getDisplaySurfaceDefaultSize(
+ mDisplayId);
+ if (surfaceSize == null) {
+ // Layer mirroring started with a null surface, so do not apply any transformations yet.
+ // State of virtual display will change to 'ON' when the surface is set.
+ // will get event DISPLAY_DEVICE_EVENT_CHANGED
+ ProtoLog.v(WM_DEBUG_LAYER_MIRRORING,
+ "Provided surface for layer mirroring on display %d is not present, so do not"
+ + " update the surface",
+ mDisplayId);
+ return null;
+ }
+ return surfaceSize;
+ }
+
+ /**
+ * Returns {@code true} if this DisplayContent is currently layer mirroring.
+ */
+ boolean isCurrentlyMirroring() {
+ return mTokenToMirror != null && mMirroredSurface != null;
+ }
+
/** The entry for proceeding to handle {@link #mFixedRotationLaunchingApp}. */
class FixedRotationTransitionListener extends WindowManagerInternal.AppTransitionListener {
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index c1d6c17..3dff680 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -377,6 +377,8 @@
private PointerLocationView mPointerLocationView;
+ private int mDisplayCutoutTouchableRegionSize;
+
/**
* The area covered by system windows which belong to another display. Forwarded insets is set
* in case this is a virtual display, this is displayed on another display that has insets, and
@@ -480,7 +482,8 @@
if (mStatusBar != null) {
requestTransientBars(mStatusBar);
}
- checkAltBarSwipeForTransientBars(ALT_BAR_TOP);
+ checkAltBarSwipeForTransientBars(ALT_BAR_TOP,
+ false /* allowForAllPositions */);
}
}
@@ -491,7 +494,8 @@
&& mNavigationBarPosition == NAV_BAR_BOTTOM) {
requestTransientBars(mNavigationBar);
}
- checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM);
+ checkAltBarSwipeForTransientBars(ALT_BAR_BOTTOM,
+ false /* allowForAllPositions */);
}
}
@@ -501,13 +505,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- final boolean excluded =
- mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+ final boolean allowSideSwipe = mNavigationBarAlwaysShowOnSideGesture &&
+ !mSystemGestures.currentGestureStartedInRegion(excludedRegion);
if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_RIGHT
- || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+ || allowSideSwipe)) {
requestTransientBars(mNavigationBar);
}
- checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT);
+ checkAltBarSwipeForTransientBars(ALT_BAR_RIGHT, allowSideSwipe);
}
excludedRegion.recycle();
}
@@ -518,13 +522,13 @@
synchronized (mLock) {
mDisplayContent.calculateSystemGestureExclusion(
excludedRegion, null /* outUnrestricted */);
- final boolean excluded =
- mSystemGestures.currentGestureStartedInRegion(excludedRegion);
+ final boolean allowSideSwipe = mNavigationBarAlwaysShowOnSideGesture &&
+ !mSystemGestures.currentGestureStartedInRegion(excludedRegion);
if (mNavigationBar != null && (mNavigationBarPosition == NAV_BAR_LEFT
- || !excluded && mNavigationBarAlwaysShowOnSideGesture)) {
+ || allowSideSwipe)) {
requestTransientBars(mNavigationBar);
}
- checkAltBarSwipeForTransientBars(ALT_BAR_LEFT);
+ checkAltBarSwipeForTransientBars(ALT_BAR_LEFT, allowSideSwipe);
}
excludedRegion.recycle();
}
@@ -678,17 +682,19 @@
mHandler.post(mGestureNavigationSettingsObserver::register);
}
- private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos) {
- if (mStatusBarAlt != null && mStatusBarAltPosition == pos) {
+ private void checkAltBarSwipeForTransientBars(@WindowManagerPolicy.AltBarPosition int pos,
+ boolean allowForAllPositions) {
+ if (mStatusBarAlt != null && (mStatusBarAltPosition == pos || allowForAllPositions)) {
requestTransientBars(mStatusBarAlt);
}
- if (mNavigationBarAlt != null && mNavigationBarAltPosition == pos) {
+ if (mNavigationBarAlt != null
+ && (mNavigationBarAltPosition == pos || allowForAllPositions)) {
requestTransientBars(mNavigationBarAlt);
}
- if (mClimateBarAlt != null && mClimateBarAltPosition == pos) {
+ if (mClimateBarAlt != null && (mClimateBarAltPosition == pos || allowForAllPositions)) {
requestTransientBars(mClimateBarAlt);
}
- if (mExtraNavBarAlt != null && mExtraNavBarAltPosition == pos) {
+ if (mExtraNavBarAlt != null && (mExtraNavBarAltPosition == pos || allowForAllPositions)) {
requestTransientBars(mExtraNavBarAlt);
}
}
@@ -1109,8 +1115,21 @@
rect.bottom = rect.top + getStatusBarHeight(displayFrames);
}
};
+ final TriConsumer<DisplayFrames, WindowState, Rect> gestureFrameProvider =
+ (displayFrames, windowState, rect) -> {
+ rect.bottom = rect.top + getStatusBarHeight(displayFrames);
+ final DisplayCutout cutout =
+ displayFrames.mInsetsState.getDisplayCutout();
+ if (cutout != null) {
+ final Rect top = cutout.getBoundingRectTop();
+ if (!top.isEmpty()) {
+ rect.bottom = rect.bottom + mDisplayCutoutTouchableRegionSize;
+ }
+ }
+ };
mDisplayContent.setInsetProvider(ITYPE_STATUS_BAR, win, frameProvider);
- mDisplayContent.setInsetProvider(ITYPE_TOP_MANDATORY_GESTURES, win, frameProvider);
+ mDisplayContent.setInsetProvider(
+ ITYPE_TOP_MANDATORY_GESTURES, win, gestureFrameProvider);
mDisplayContent.setInsetProvider(ITYPE_TOP_TAPPABLE_ELEMENT, win, frameProvider);
break;
case TYPE_NAVIGATION_BAR:
@@ -1175,6 +1194,12 @@
default:
if (attrs.providesInsetsTypes != null) {
for (@InternalInsetsType int insetsType : attrs.providesInsetsTypes) {
+ final TriConsumer<DisplayFrames, WindowState, Rect> imeFrameProvider =
+ !attrs.providedInternalImeInsets.equals(Insets.NONE)
+ ? (displayFrames, windowState, inOutFrame) ->
+ inOutFrame.inset(windowState.getLayoutingAttrs(
+ displayFrames.mRotation).providedInternalImeInsets)
+ : null;
switch (insetsType) {
case ITYPE_STATUS_BAR:
mStatusBarAlt = win;
@@ -1194,12 +1219,13 @@
break;
}
if (!INSETS_LAYOUT_GENERALIZATION) {
- mDisplayContent.setInsetProvider(insetsType, win, null);
+ mDisplayContent.setInsetProvider(insetsType, win, null,
+ imeFrameProvider);
} else {
mDisplayContent.setInsetProvider(insetsType, win, (displayFrames,
windowState, inOutFrame) -> inOutFrame.inset(
windowState.getLayoutingAttrs(displayFrames.mRotation)
- .providedInternalInsets));
+ .providedInternalInsets), imeFrameProvider);
}
}
}
@@ -2091,11 +2117,14 @@
mStatusBarHeightForRotation[landscapeRotation] =
mStatusBarHeightForRotation[seascapeRotation] =
res.getDimensionPixelSize(R.dimen.status_bar_height_landscape);
+ mDisplayCutoutTouchableRegionSize = res.getDimensionPixelSize(
+ R.dimen.display_cutout_touchable_region_size);
} else {
mStatusBarHeightForRotation[portraitRotation] =
mStatusBarHeightForRotation[upsideDownRotation] =
mStatusBarHeightForRotation[landscapeRotation] =
mStatusBarHeightForRotation[seascapeRotation] = 0;
+ mDisplayCutoutTouchableRegionSize = 0;
}
// Height of the navigation bar when presented horizontally at bottom
@@ -2255,7 +2284,10 @@
void notifyDisplayReady() {
mHandler.post(() -> {
final int displayId = getDisplayId();
- getStatusBarManagerInternal().onDisplayReady(displayId);
+ StatusBarManagerInternal statusBar = getStatusBarManagerInternal();
+ if (statusBar != null) {
+ statusBar.onDisplayReady(displayId);
+ }
final WallpaperManagerInternal wpMgr = LocalServices
.getService(WallpaperManagerInternal.class);
if (wpMgr != null) {
@@ -2391,7 +2423,7 @@
*/
float getWindowCornerRadius() {
return mDisplayContent.getDisplay().getType() == TYPE_INTERNAL
- ? ScreenDecorationsUtils.getWindowCornerRadius(mContext.getResources()) : 0f;
+ ? ScreenDecorationsUtils.getWindowCornerRadius(mContext) : 0f;
}
boolean isShowingDreamLw() {
diff --git a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
index b627b33..4141090 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowListenerController.java
@@ -19,6 +19,7 @@
import android.content.res.Configuration;
import android.os.RemoteCallbackList;
import android.os.RemoteException;
+import android.util.IntArray;
import android.view.IDisplayWindowListener;
/**
@@ -28,23 +29,20 @@
class DisplayWindowListenerController {
RemoteCallbackList<IDisplayWindowListener> mDisplayListeners = new RemoteCallbackList<>();
-// private final ArrayList<DisplayContainerListener> mDisplayListeners = new ArrayList<>();
private final WindowManagerService mService;
DisplayWindowListenerController(WindowManagerService service) {
mService = service;
}
- void registerListener(IDisplayWindowListener listener) {
+ int[] registerListener(IDisplayWindowListener listener) {
synchronized (mService.mGlobalLock) {
mDisplayListeners.register(listener);
- try {
- for (int i = 0; i < mService.mAtmService.mRootWindowContainer.getChildCount();
- ++i) {
- DisplayContent d = mService.mAtmService.mRootWindowContainer.getChildAt(i);
- listener.onDisplayAdded(d.mDisplayId);
- }
- } catch (RemoteException e) { }
+ final IntArray displayIds = new IntArray();
+ mService.mAtmService.mRootWindowContainer.forAllDisplays((displayContent) -> {
+ displayIds.add(displayContent.mDisplayId);
+ });
+ return displayIds.toArray();
}
}
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
index 8fcdf2e..4a70fa3 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettingsProvider.java
@@ -264,8 +264,14 @@
@NonNull
private static AtomicFile getVendorSettingsFile() {
- final File vendorFile = new File(Environment.getVendorDirectory(),
+ // First look under product path for treblized builds.
+ File vendorFile = new File(Environment.getProductDirectory(),
VENDOR_DISPLAY_SETTINGS_FILE_PATH);
+ if (!vendorFile.exists()) {
+ // Try and look in vendor path.
+ vendorFile = new File(Environment.getVendorDirectory(),
+ VENDOR_DISPLAY_SETTINGS_FILE_PATH);
+ }
return new AtomicFile(vendorFile, WM_DISPLAY_COMMIT_TAG);
}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 9f24b50..1bc1d46 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -581,9 +581,12 @@
if (mAddRecentsAnimationInputConsumerHandle && shouldApplyRecentsInputConsumer) {
if (recentsAnimationController.updateInputConsumerForApp(
mRecentsAnimationInputConsumer.mWindowHandle)) {
- mRecentsAnimationInputConsumer.show(mInputTransaction,
- recentsAnimationController.getHighestLayerActivity());
- mAddRecentsAnimationInputConsumerHandle = false;
+ final WindowState highestLayerWindow =
+ recentsAnimationController.getHighestLayerWindow();
+ if (highestLayerWindow != null) {
+ mRecentsAnimationInputConsumer.show(mInputTransaction, highestLayerWindow);
+ mAddRecentsAnimationInputConsumerHandle = false;
+ }
}
}
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 869d351..3d19f54 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -43,16 +43,20 @@
import android.view.InsetsSourceControl;
import android.view.InsetsState;
import android.view.InsetsState.InternalInsetsType;
+import android.view.InternalInsetsAnimationController;
import android.view.SurfaceControl;
import android.view.SyncRtSurfaceTransactionApplier;
+import android.view.WindowInsets.Type;
import android.view.WindowInsetsAnimation;
import android.view.WindowInsetsAnimation.Bounds;
import android.view.WindowInsetsAnimationControlListener;
+import android.view.WindowInsetsAnimationController;
import android.view.WindowManager;
import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.DisplayThread;
+import com.android.server.statusbar.StatusBarManagerInternal;
/**
* Policy that implements who gets control over the windows generating insets.
@@ -169,8 +173,12 @@
changed = true;
}
if (changed) {
- mPolicy.getStatusBarManagerInternal().showTransient(mDisplayContent.getDisplayId(),
- mShowingTransientTypes.toArray());
+ StatusBarManagerInternal statusBarManagerInternal =
+ mPolicy.getStatusBarManagerInternal();
+ if (statusBarManagerInternal != null) {
+ statusBarManagerInternal.showTransient(
+ mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
+ }
updateBarControlTarget(mFocusedWin);
// The leashes can be created while updating bar control target. The surface transaction
@@ -305,9 +313,11 @@
abortTypes.add(type);
}
}
- if (abortTypes.size() > 0) {
- mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
- abortTypes.toArray());
+ StatusBarManagerInternal statusBarManagerInternal =
+ mPolicy.getStatusBarManagerInternal();
+ if (abortTypes.size() > 0 && statusBarManagerInternal != null) {
+ statusBarManagerInternal.abortTransient(
+ mDisplayContent.getDisplayId(), abortTypes.toArray());
}
}
}
@@ -317,14 +327,17 @@
* updateBarControlTarget(mFocusedWin) after this invocation.
*/
private void abortTransient() {
- mPolicy.getStatusBarManagerInternal().abortTransient(mDisplayContent.getDisplayId(),
- mShowingTransientTypes.toArray());
+ StatusBarManagerInternal statusBarManagerInternal = mPolicy.getStatusBarManagerInternal();
+ if (statusBarManagerInternal != null) {
+ statusBarManagerInternal.abortTransient(
+ mDisplayContent.getDisplayId(), mShowingTransientTypes.toArray());
+ }
mShowingTransientTypes.clear();
}
private @Nullable InsetsControlTarget getStatusControlTarget(@Nullable WindowState focusedWin,
boolean fake) {
- if (mShowingTransientTypes.indexOf(ITYPE_STATUS_BAR) != -1 && !fake) {
+ if (!fake && isShowingTransientTypes(Type.statusBars())) {
return mDummyControlTarget;
}
final WindowState notificationShade = mPolicy.getNotificationShade();
@@ -374,7 +387,7 @@
// Force showing navigation bar while IME is visible.
return null;
}
- if (mShowingTransientTypes.indexOf(ITYPE_NAVIGATION_BAR) != -1 && !fake) {
+ if (!fake && isShowingTransientTypes(Type.navigationBars())) {
return mDummyControlTarget;
}
if (focusedWin == mPolicy.getNotificationShade()) {
@@ -400,6 +413,16 @@
return focusedWin;
}
+ private boolean isShowingTransientTypes(@Type.InsetsType int types) {
+ final IntArray showingTransientTypes = mShowingTransientTypes;
+ for (int i = showingTransientTypes.size() - 1; i >= 0; i--) {
+ if ((InsetsState.toPublicType(showingTransientTypes.get(i)) & types) != 0) {
+ return true;
+ }
+ }
+ return false;
+ }
+
/**
* Determines whether the remote insets controller should take control of system bars for all
* windows.
@@ -477,8 +500,12 @@
final int state = visible ? WINDOW_STATE_SHOWING : WINDOW_STATE_HIDDEN;
if (mState != state) {
mState = state;
- mPolicy.getStatusBarManagerInternal().setWindowState(
- mDisplayContent.getDisplayId(), mId, state);
+ StatusBarManagerInternal statusBarManagerInternal =
+ mPolicy.getStatusBarManagerInternal();
+ if (statusBarManagerInternal != null) {
+ statusBarManagerInternal.setWindowState(
+ mDisplayContent.getDisplayId(), mId, state);
+ }
}
}
}
@@ -570,8 +597,8 @@
}
@Override
- public void startAnimation(InsetsAnimationControlImpl controller,
- WindowInsetsAnimationControlListener listener, int types,
+ public <T extends InsetsAnimationControlRunner & InternalInsetsAnimationController>
+ void startAnimation(T runner, WindowInsetsAnimationControlListener listener, int types,
WindowInsetsAnimation animation,
Bounds bounds) {
}
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index f3e52f2..f93e085 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -22,7 +22,7 @@
import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
import static android.view.InsetsState.ITYPE_STATUS_BAR;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
import static com.android.server.wm.InsetsSourceProviderProto.CAPTURED_LEASH;
import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
@@ -164,7 +164,8 @@
mWin.cancelAnimation();
mWin.mProvidedInsetsSources.remove(mSource.getType());
}
- ProtoLog.d(WM_DEBUG_IME, "InsetsSource setWin %s", win);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "InsetsSource setWin %s for type %s", win,
+ InsetsState.typeToString(mSource.getType()));
mWin = win;
mFrameProvider = frameProvider;
mImeFrameProvider = imeFrameProvider;
@@ -343,7 +344,7 @@
updateVisibility();
mControl = new InsetsSourceControl(mSource.getType(), leash, surfacePosition,
mSource.calculateInsets(mWin.getBounds(), true /* ignoreVisibility */));
- ProtoLog.d(WM_DEBUG_IME,
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
"InsetsSource Control %s for target %s", mControl, mControlTarget);
}
@@ -392,8 +393,9 @@
protected void updateVisibility() {
mSource.setVisible(mServerVisible && (isMirroredSource() || mClientVisible));
- ProtoLog.d(WM_DEBUG_IME,
- "InsetsSource updateVisibility serverVisible: %s clientVisible: %s",
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS,
+ "InsetsSource updateVisibility for %s, serverVisible: %s clientVisible: %s",
+ InsetsState.typeToString(mSource.getType()),
mServerVisible, mClientVisible);
}
@@ -539,7 +541,7 @@
t.setAlpha(animationLeash, 1 /* alpha */);
t.hide(animationLeash);
}
- ProtoLog.i(WM_DEBUG_IME,
+ ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
"ControlAdapter startAnimation mSource: %s controlTarget: %s", mSource,
mControlTarget);
@@ -555,7 +557,7 @@
mControlTarget = null;
mAdapter = null;
setClientVisible(InsetsState.getDefaultVisibility(mSource.getType()));
- ProtoLog.i(WM_DEBUG_IME,
+ ProtoLog.i(WM_DEBUG_WINDOW_INSETS,
"ControlAdapter onAnimationCancelled mSource: %s mControlTarget: %s",
mSource, mControlTarget);
}
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 6f3edbc..4a8c36f 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -375,7 +375,7 @@
// TODO(b/113840485): Handle app transition for individual display, and apply occluded
// state change to secondary displays.
// For now, only default display fully supports occluded change. Other displays only
- // updates keygaurd sleep token on that display.
+ // updates keyguard sleep token on that display.
if (displayId != DEFAULT_DISPLAY) {
updateKeyguardSleepToken(displayId);
return;
@@ -390,15 +390,6 @@
isDisplayOccluded(DEFAULT_DISPLAY)
? TRANSIT_KEYGUARD_OCCLUDE
: TRANSIT_KEYGUARD_UNOCCLUDE, 0 /* flags */);
- // When the occluding activity also turns on the display, visibility of the activity
- // can be committed before KEYGUARD_OCCLUDE transition is handled.
- // Set mRequestForceTransition flag to make sure that the app transition animation
- // is applied for such case.
- // TODO(b/194243906): Fix this before enabling the remote keyguard animation.
- if (WindowManagerService.sEnableRemoteKeyguardGoingAwayAnimation
- && topActivity != null) {
- topActivity.mRequestForceTransition = true;
- }
updateKeyguardSleepToken(DEFAULT_DISPLAY);
mWindowManager.executeAppTransition();
} finally {
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index d7dc306..ba85c98 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -581,7 +581,7 @@
contentInsets = targetAppMainWindow
.getInsetsStateWithVisibilityOverride()
.calculateInsets(mTargetActivityRecord.getBounds(), Type.systemBars(),
- false /* ignoreVisibility */);
+ false /* ignoreVisibility */).toRect();
} else {
// If the window for the activity had not yet been created, use the display insets.
mService.getStableInsets(mDisplayId, mTmpRect);
@@ -1103,9 +1103,9 @@
}
/**
- * Returns the activity with the highest layer, or null if none is found.
+ * Returns the window with the highest layer, or null if none is found.
*/
- public ActivityRecord getHighestLayerActivity() {
+ public WindowState getHighestLayerWindow() {
int highestLayer = Integer.MIN_VALUE;
Task highestLayerTask = null;
for (int i = mPendingAnimations.size() - 1; i >= 0; i--) {
@@ -1116,7 +1116,7 @@
highestLayerTask = adapter.mTask;
}
}
- return highestLayerTask.getTopMostActivity();
+ return highestLayerTask.getTopMostActivity().getTopChild();
}
boolean isAnimatingTask(Task task) {
@@ -1209,7 +1209,7 @@
return null;
}
final Rect insets = mainWindow.getInsetsStateWithVisibilityOverride().calculateInsets(
- mBounds, Type.systemBars(), false /* ignoreVisibility */);
+ mBounds, Type.systemBars(), false /* ignoreVisibility */).toRect();
InsetUtils.addInsets(insets, mainWindow.mActivityRecord.getLetterboxInsets());
final int mode = topApp.getActivityType() == mTargetActivityType
? MODE_OPENING
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 079868d..6c2322b 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -1965,7 +1965,7 @@
private boolean startActivityForAttachedApplicationIfNeeded(ActivityRecord r,
WindowProcessController app, ActivityRecord top) {
- if (r.finishing || !r.okToShowLocked() || !r.visibleIgnoringKeyguard || r.app != null
+ if (r.finishing || !r.showToCurrentUser() || !r.visibleIgnoringKeyguard || r.app != null
|| app.mUid != r.info.applicationInfo.uid || !app.mName.equals(r.processName)) {
return false;
}
diff --git a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
index d440a14..d1460f4 100644
--- a/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
+++ b/services/core/java/com/android/server/wm/ScreenRotationAnimation.java
@@ -729,7 +729,12 @@
mScreenshotRotationAnimator = null;
mRotateScreenAnimator = null;
mService.mAnimator.mBulkUpdateParams |= WindowSurfacePlacer.SET_UPDATE_ROTATION;
- kill();
+ if (mDisplayContent.getRotationAnimation() == ScreenRotationAnimation.this) {
+ // It also invokes kill().
+ mDisplayContent.setRotationAnimation(null);
+ } else {
+ kill();
+ }
mService.updateRotation(false, false);
}
}
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 567936d..7bdb1a0 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -5159,7 +5159,7 @@
}
final ActivityRecord prev = baseTask.getActivity(
- a -> a.mStartingData != null && a.okToShowLocked());
+ a -> a.mStartingData != null && a.showToCurrentUser());
r.showStartingWindow(prev, newTask, isTaskSwitch,
true /* startActivity */, sourceRecord);
}
@@ -5530,7 +5530,7 @@
// Don't refocus if invisible to current user
final ActivityRecord top = tr.getTopNonFinishingActivity();
- if (top == null || !top.okToShowLocked()) {
+ if (top == null || !top.showToCurrentUser()) {
positionChildAtTop(tr);
if (top != null) {
mTaskSupervisor.mRecentTasks.add(top.getTask());
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index 242693b..7c939e6 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -655,7 +655,6 @@
* @param includingEmbeddedTask whether the activity in a task that being embedded from this
* one should be included.
* @see #topRunningActivity(boolean, boolean)
- * @see ActivityRecord#okToShowLocked()
*/
ActivityRecord getTopNonFinishingActivity(boolean includeOverlays,
boolean includingEmbeddedTask) {
@@ -2014,6 +2013,8 @@
|| mDisplayContent == null
|| mTaskFragmentOrganizer == null
|| getSurfaceControl() == null
+ // The change transition will be covered by display.
+ || mDisplayContent.inTransition()
|| !isVisible()) {
return false;
}
@@ -2078,12 +2079,18 @@
}
final Point positionInParent = new Point();
getRelativePosition(positionInParent);
+ final int[] runningActivityCount = new int[1];
+ forAllActivities(a -> {
+ if (!a.finishing) {
+ runningActivityCount[0]++;
+ }
+ });
return new TaskFragmentInfo(
mFragmentToken,
mRemoteToken.toWindowContainerToken(),
getConfiguration(),
getChildCount() == 0,
- hasRunningActivity(this),
+ runningActivityCount[0],
isVisible(),
childActivities,
positionInParent);
@@ -2095,7 +2102,6 @@
}
@Nullable
- @VisibleForTesting
ITaskFragmentOrganizer getTaskFragmentOrganizer() {
return mTaskFragmentOrganizer;
}
diff --git a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
index 690f67c..30d2a32 100644
--- a/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskFragmentOrganizerController.java
@@ -30,6 +30,7 @@
import android.os.RemoteException;
import android.util.ArrayMap;
import android.util.Slog;
+import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.ITaskFragmentOrganizerController;
@@ -81,6 +82,13 @@
private final Map<TaskFragment, Configuration> mLastSentTaskFragmentParentConfigs =
new WeakHashMap<>();
+ /**
+ * @see android.window.TaskFragmentOrganizer#registerRemoteAnimations(
+ * RemoteAnimationDefinition)
+ */
+ @Nullable
+ private RemoteAnimationDefinition mRemoteAnimationDefinition;
+
TaskFragmentOrganizerState(ITaskFragmentOrganizer organizer) {
mOrganizer = organizer;
try {
@@ -245,6 +253,61 @@
}
}
+ @Override
+ public void registerRemoteAnimations(ITaskFragmentOrganizer organizer,
+ RemoteAnimationDefinition definition) {
+ final int pid = Binder.getCallingPid();
+ final int uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Register remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ throw new IllegalStateException("The organizer hasn't been registered.");
+ }
+ if (organizerState.mRemoteAnimationDefinition != null) {
+ throw new IllegalStateException(
+ "The organizer has already registered remote animations="
+ + organizerState.mRemoteAnimationDefinition);
+ }
+
+ definition.setCallingPidUid(pid, uid);
+ organizerState.mRemoteAnimationDefinition = definition;
+ }
+ }
+
+ @Override
+ public void unregisterRemoteAnimations(ITaskFragmentOrganizer organizer) {
+ final int pid = Binder.getCallingPid();
+ final long uid = Binder.getCallingUid();
+ synchronized (mGlobalLock) {
+ ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER,
+ "Unregister remote animations for organizer=%s uid=%d pid=%d",
+ organizer.asBinder(), uid, pid);
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ if (organizerState == null) {
+ Slog.e(TAG, "The organizer hasn't been registered.");
+ return;
+ }
+
+ organizerState.mRemoteAnimationDefinition = null;
+ }
+ }
+
+ /** Gets the {@link RemoteAnimationDefinition} set on the given organizer if exists. */
+ @Nullable
+ public RemoteAnimationDefinition getRemoteAnimationDefinition(
+ ITaskFragmentOrganizer organizer) {
+ synchronized (mGlobalLock) {
+ final TaskFragmentOrganizerState organizerState =
+ mTaskFragmentOrganizerState.get(organizer.asBinder());
+ return organizerState != null ? organizerState.mRemoteAnimationDefinition : null;
+ }
+ }
+
void onTaskFragmentAppeared(ITaskFragmentOrganizer organizer, TaskFragment taskFragment) {
final TaskFragmentOrganizerState state = validateAndGetState(organizer);
if (!state.addTaskFragment(taskFragment)) {
diff --git a/services/core/java/com/android/server/wm/TaskSnapshotController.java b/services/core/java/com/android/server/wm/TaskSnapshotController.java
index e743710..63951d9 100644
--- a/services/core/java/com/android/server/wm/TaskSnapshotController.java
+++ b/services/core/java/com/android/server/wm/TaskSnapshotController.java
@@ -683,7 +683,8 @@
}
static Rect getSystemBarInsets(Rect frame, InsetsState state) {
- return state.calculateInsets(frame, Type.systemBars(), false /* ignoreVisibility */);
+ return state.calculateInsets(
+ frame, Type.systemBars(), false /* ignoreVisibility */).toRect();
}
void dump(PrintWriter pw, String prefix) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 07f0197..6b93364 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -70,7 +70,7 @@
import android.util.Slog;
import android.view.SurfaceControl;
import android.view.animation.Animation;
-import android.window.IRemoteTransition;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import com.android.internal.annotations.VisibleForTesting;
@@ -123,7 +123,7 @@
private @TransitionFlags int mFlags;
private final TransitionController mController;
private final BLASTSyncEngine mSyncEngine;
- private IRemoteTransition mRemoteTransition = null;
+ private RemoteTransition mRemoteTransition = null;
/** Only use for clean-up after binder death! */
private SurfaceControl.Transaction mStartTransaction = null;
@@ -436,11 +436,11 @@
mSyncEngine.abort(mSyncId);
}
- void setRemoteTransition(IRemoteTransition remoteTransition) {
+ void setRemoteTransition(RemoteTransition remoteTransition) {
mRemoteTransition = remoteTransition;
}
- IRemoteTransition getRemoteTransition() {
+ RemoteTransition getRemoteTransition() {
return mRemoteTransition;
}
@@ -565,7 +565,7 @@
if (mFinishTransaction != null) {
mFinishTransaction.apply();
}
- finishTransition();
+ mController.finishTransition(this);
}
/** @see RecentsAnimationController#attachNavigationBarToApp */
@@ -978,7 +978,7 @@
// Wallpaper must be the top (regardless of how nested it is in DisplayAreas).
boolean skipIntermediateReports = isWallpaper(wc);
for (WindowContainer p = wc.getParent(); p != null; p = p.getParent()) {
- if (!p.isAttached() || !changes.get(p).hasChanged(p)) {
+ if (!p.isAttached() || changes.get(p) == null || !changes.get(p).hasChanged(p)) {
// Again, we're skipping no-ops
break;
}
diff --git a/services/core/java/com/android/server/wm/TransitionController.java b/services/core/java/com/android/server/wm/TransitionController.java
index 419b4c3..69e6a54 100644
--- a/services/core/java/com/android/server/wm/TransitionController.java
+++ b/services/core/java/com/android/server/wm/TransitionController.java
@@ -34,6 +34,7 @@
import android.view.WindowManager;
import android.window.IRemoteTransition;
import android.window.ITransitionPlayer;
+import android.window.RemoteTransition;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -223,7 +224,7 @@
@Nullable
Transition requestTransitionIfNeeded(@WindowManager.TransitionType int type,
@WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger,
- @NonNull WindowContainer readyGroupRef, @Nullable IRemoteTransition remoteTransition) {
+ @NonNull WindowContainer readyGroupRef, @Nullable RemoteTransition remoteTransition) {
if (mTransitionPlayer == null) {
return null;
}
@@ -252,7 +253,7 @@
/** Asks the transition player (shell) to start a created but not yet started transition. */
@NonNull
Transition requestStartTransition(@NonNull Transition transition, @Nullable Task startTask,
- @Nullable IRemoteTransition remoteTransition) {
+ @Nullable RemoteTransition remoteTransition) {
try {
ProtoLog.v(ProtoLogGroup.WM_DEBUG_WINDOW_TRANSITIONS,
"Requesting StartTransition: %s", transition);
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/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index b6c8e13..2882a23 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -987,6 +987,10 @@
return mDisplayContent != null && mDisplayContent.mChangingContainers.contains(this);
}
+ boolean inTransition() {
+ return mWmService.mAtmService.getTransitionController().inTransition(this);
+ }
+
void sendAppVisibilityToClients() {
for (int i = mChildren.size() - 1; i >= 0; --i) {
final WindowContainer wc = mChildren.get(i);
@@ -1376,6 +1380,7 @@
}
}
+ /** Returns whether the window should be shown for current user. */
boolean showToCurrentUser() {
return true;
}
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 132f139..ba0266a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -462,8 +462,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 f37be64..4340a36 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2810,6 +2810,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()")) {
@@ -2817,23 +2842,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);
}
@@ -4331,13 +4340,18 @@
}
}
- /** Registers a hierarchy listener that gets callbacks when the hierarchy changes. */
+ /**
+ * Registers a hierarchy listener that gets callbacks when the hierarchy changes. The listener's
+ * onDisplayAdded() will not be called for the displays returned.
+ *
+ * @return the displayIds for the existing displays
+ */
@Override
- public void registerDisplayWindowListener(IDisplayWindowListener listener) {
+ public int[] registerDisplayWindowListener(IDisplayWindowListener listener) {
mAtmService.enforceTaskPermission("registerDisplayWindowListener");
final long ident = Binder.clearCallingIdentity();
try {
- mDisplayNotificationController.registerListener(listener);
+ return mDisplayNotificationController.registerListener(listener);
} finally {
Binder.restoreCallingIdentity(ident);
}
@@ -7551,28 +7565,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
@@ -8117,9 +8113,14 @@
// This could prevent if there is no container animation, we still have to apply the
// pending transaction and exit waiting.
mAnimator.mNotifyWhenNoAnimation = true;
+ boolean animateStarting = false;
while (timeoutRemaining > 0) {
+ // Waiting until all starting windows has finished animating.
+ animateStarting = !mAtmService.getTransitionController().isShellTransitionsEnabled()
+ && mRoot.forAllActivities(ActivityRecord::hasStartingWindow);
boolean isAnimating = mAnimator.isAnimationScheduled()
- || mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL);
+ || mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL)
+ || animateStarting;
if (!isAnimating) {
// isAnimating is a legacy transition query and will be removed, so also add
// a check for whether this is in a shell-transition when not using legacy.
@@ -8139,13 +8140,14 @@
WindowContainer animatingContainer;
animatingContainer = mRoot.getAnimatingContainer(TRANSITION | CHILDREN,
ANIMATION_TYPE_ALL);
- if (mAnimator.isAnimationScheduled() || animatingContainer != null) {
+ if (mAnimator.isAnimationScheduled() || animatingContainer != null || animateStarting) {
Slog.w(TAG, "Timed out waiting for animations to complete,"
+ " animatingContainer=" + animatingContainer
+ " animationType=" + SurfaceAnimator.animationTypeToString(
animatingContainer != null
? animatingContainer.mSurfaceAnimator.getAnimationType()
- : SurfaceAnimator.ANIMATION_TYPE_NONE));
+ : SurfaceAnimator.ANIMATION_TYPE_NONE)
+ + " animateStarting=" + animateStarting);
}
}
}
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index b568774..8bcd62d 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -275,8 +275,6 @@
syncId = startSyncWithOrganizer(callback);
applyTransaction(t, syncId, null /* transition */, caller);
setSyncReady(syncId);
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY)
- .executeAppTransition();
}
} finally {
Binder.restoreCallingIdentity(ident);
@@ -653,18 +651,10 @@
options = activityOptions.toBundle();
}
- int res = mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
+ mService.mAmInternal.sendIntentSender(hop.getPendingIntent().getTarget(),
hop.getPendingIntent().getWhitelistToken(), 0 /* code */,
hop.getActivityIntent(), resolvedType, null /* finishReceiver */,
null /* requiredPermission */, options);
- if (res != ActivityManager.START_SUCCESS
- && res != ActivityManager.START_TASK_TO_FRONT) {
- if (!mTransitionController.isShellTransitionsEnabled()) {
- final DisplayContent dc =
- mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
- dc.cancelAppTransition();
- }
- }
break;
case HIERARCHY_OP_TYPE_CREATE_TASK_FRAGMENT:
final TaskFragmentCreationParams taskFragmentCreationOptions =
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1ca0c7e..22db297 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -114,10 +114,10 @@
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_FOCUS_LIGHT;
-import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_IME;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_ORIENTATION;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_RESIZE;
import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_STARTING_WINDOW;
+import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_INSETS;
import static com.android.server.am.ActivityManagerService.MY_PID;
import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
import static com.android.server.policy.WindowManagerPolicy.TRANSIT_ENTER;
@@ -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;
@@ -3978,7 +3985,7 @@
* Called when the insets state changed.
*/
void notifyInsetsChanged() {
- ProtoLog.d(WM_DEBUG_IME, "notifyInsetsChanged for %s ", this);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsChanged for %s ", this);
try {
mClient.insetsChanged(getCompatInsetsState(),
hasMoved(),
@@ -3990,7 +3997,7 @@
@Override
public void notifyInsetsControlChanged() {
- ProtoLog.d(WM_DEBUG_IME, "notifyInsetsControlChanged for %s ", this);
+ ProtoLog.d(WM_DEBUG_WINDOW_INSETS, "notifyInsetsControlChanged for %s ", this);
if (mAppDied || mRemoved) {
return;
}
@@ -5952,9 +5959,9 @@
outSurfaceInsets.set(getAttrs().surfaceInsets);
final InsetsState state = getInsetsStateWithVisibilityOverride();
outInsets.set(state.calculateInsets(outFrame, systemBars(),
- false /* ignoreVisibility */));
+ false /* ignoreVisibility */).toRect());
outStableInsets.set(state.calculateInsets(outFrame, systemBars(),
- true /* ignoreVisibility */));
+ true /* ignoreVisibility */).toRect());
}
void setViewVisibility(int viewVisibility) {
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/core/java/com/android/server/wm/WindowTracing.java b/services/core/java/com/android/server/wm/WindowTracing.java
index 0bb97f5..6204824 100644
--- a/services/core/java/com/android/server/wm/WindowTracing.java
+++ b/services/core/java/com/android/server/wm/WindowTracing.java
@@ -54,7 +54,8 @@
private static final int BUFFER_CAPACITY_CRITICAL = 512 * 1024;
private static final int BUFFER_CAPACITY_TRIM = 2048 * 1024;
private static final int BUFFER_CAPACITY_ALL = 4096 * 1024;
- private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace.pb";
+ static final String WINSCOPE_EXT = ".winscope";
+ private static final String TRACE_FILENAME = "/data/misc/wmtrace/wm_trace" + WINSCOPE_EXT;
private static final String TAG = "WindowTracing";
private static final long MAGIC_NUMBER_VALUE = ((long) MAGIC_NUMBER_H << 32) | MAGIC_NUMBER_L;
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 4897ca0..f5f1d49 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -437,7 +437,6 @@
private static final String SYSPROP_START_UPTIME = "sys.system_server.start_uptime";
private Future<?> mZygotePreload;
- private Future<?> mBlobStoreServiceStart;
private final SystemServerDumper mDumper = new SystemServerDumper();
@@ -2255,12 +2254,9 @@
t.traceEnd();
}
- mBlobStoreServiceStart = SystemServerInitThreadPool.submit(() -> {
- final TimingsTraceAndSlog traceLog = TimingsTraceAndSlog.newAsyncLog();
- traceLog.traceBegin(START_BLOB_STORE_SERVICE);
- mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
- traceLog.traceEnd();
- }, START_BLOB_STORE_SERVICE);
+ t.traceBegin(START_BLOB_STORE_SERVICE);
+ mSystemServiceManager.startService(BLOB_STORE_MANAGER_SERVICE_CLASS);
+ t.traceEnd();
// Dreams (interactive idle-time views, a/k/a screen savers, and doze mode)
t.traceBegin("StartDreamManager");
@@ -2659,9 +2655,6 @@
mSystemServiceManager.startService(APP_COMPAT_OVERRIDES_SERVICE_CLASS);
t.traceEnd();
- ConcurrentUtils.waitForFutureNoInterrupt(mBlobStoreServiceStart,
- START_BLOB_STORE_SERVICE);
-
// These are needed to propagate to the runnable below.
final NetworkManagementService networkManagementF = networkManagement;
final NetworkStatsService networkStatsF = networkStats;
diff --git a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
index 4d86c87..85ef8f7 100644
--- a/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/app/GameManagerServiceTests.java
@@ -182,7 +182,14 @@
}
private void mockDeviceConfigPerformance() {
- String configString = "mode=2,downscaleFactor=0.5";
+ String configString = "mode=2,downscaleFactor=0.5,useAngle=false";
+ when(DeviceConfig.getProperty(anyString(), anyString()))
+ .thenReturn(configString);
+ }
+
+ // ANGLE will be disabled for most apps, so treat enabling ANGLE as a special case.
+ private void mockDeviceConfigPerformanceEnableAngle() {
+ String configString = "mode=2,downscaleFactor=0.5,useAngle=true";
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configString);
}
@@ -200,7 +207,7 @@
}
private void mockDeviceConfigInvalid() {
- String configString = "mode=2,downscaleFactor=0.55";
+ String configString = "";
when(DeviceConfig.getProperty(anyString(), anyString()))
.thenReturn(configString);
}
@@ -212,7 +219,8 @@
}
private void mockGameModeOptInAll() throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true);
@@ -224,7 +232,8 @@
}
private void mockGameModeOptInPerformance() throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_PERFORMANCE_MODE_ENABLE, true);
@@ -234,7 +243,8 @@
}
private void mockGameModeOptInBattery() throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_BATTERY_MODE_ENABLE, true);
@@ -244,7 +254,8 @@
}
private void mockInterventionAllowDownscaleTrue() throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, true);
@@ -254,7 +265,8 @@
}
private void mockInterventionAllowDownscaleFalse() throws Exception {
- final ApplicationInfo applicationInfo = new ApplicationInfo();
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
Bundle metaDataBundle = new Bundle();
metaDataBundle.putBoolean(
GameManagerService.GamePackageConfiguration.METADATA_WM_ALLOW_DOWNSCALE, false);
@@ -263,6 +275,27 @@
.thenReturn(applicationInfo);
}
+ private void mockInterventionAllowAngleTrue() throws Exception {
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+ Bundle metaDataBundle = new Bundle();
+ metaDataBundle.putBoolean(
+ GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, true);
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
+ }
+
+ private void mockInterventionAllowAngleFalse() throws Exception {
+ final ApplicationInfo applicationInfo = mMockPackageManager.getApplicationInfoAsUser(
+ mPackageName, PackageManager.GET_META_DATA, USER_ID_1);
+ Bundle metaDataBundle = new Bundle();
+ metaDataBundle.putBoolean(
+ GameManagerService.GamePackageConfiguration.METADATA_ANGLE_ALLOW_ANGLE, false);
+ applicationInfo.metaData = metaDataBundle;
+ when(mMockPackageManager.getApplicationInfoAsUser(anyString(), anyInt(), anyInt()))
+ .thenReturn(applicationInfo);
+ }
+
/**
* By default game mode is not supported.
*/
@@ -340,11 +373,12 @@
*/
@Test
public void testSetGameModePermissionDenied() {
+ mockModifyGameModeGranted();
+ mockDeviceConfigAll();
GameManagerService gameManagerService = new GameManagerService(mMockContext);
gameManagerService.onUserStarting(USER_ID_1);
// Update the game mode so we can read back something valid.
- mockModifyGameModeGranted();
gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_STANDARD, USER_ID_1);
assertEquals(GameManager.GAME_MODE_STANDARD,
gameManagerService.getGameMode(mPackageName, USER_ID_1));
@@ -427,6 +461,19 @@
assertEquals(config.getGameModeConfiguration(gameMode).getScaling(), scaling);
}
+ private void checkAngleEnabled(GameManagerService gameManagerService, int gameMode,
+ boolean angleEnabled) {
+ gameManagerService.updateConfigsForUser(USER_ID_1, mPackageName);
+
+ // Validate GamePackageConfiguration returns the correct value.
+ GameManagerService.GamePackageConfiguration config =
+ gameManagerService.getConfig(mPackageName);
+ assertEquals(config.getGameModeConfiguration(gameMode).getUseAngle(), angleEnabled);
+
+ // Validate GameManagerService.getAngleEnabled() returns the correct value.
+ assertEquals(gameManagerService.getAngleEnabled(mPackageName, USER_ID_1), angleEnabled);
+ }
+
/**
* Phenotype device config exists, but is only propagating the default value.
*/
@@ -592,6 +639,50 @@
}
/**
+ * PERFORMANCE game mode is configured through Phenotype. The app hasn't specified any metadata.
+ */
+ @Test
+ public void testInterventionAllowAngleDefault() throws Exception {
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ gameManagerService.onUserStarting(USER_ID_1);
+ mockDeviceConfigPerformance();
+ mockModifyGameModeGranted();
+ checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false);
+ }
+
+ /**
+ * PERFORMANCE game mode is configured through Phenotype. The app has opted-out of ANGLE.
+ */
+ @Test
+ public void testInterventionAllowAngleFalse() throws Exception {
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ gameManagerService.onUserStarting(USER_ID_1);
+ mockDeviceConfigPerformanceEnableAngle();
+ mockInterventionAllowAngleFalse();
+ mockModifyGameModeGranted();
+ checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, false);
+ }
+
+ /**
+ * PERFORMANCE game mode is configured through Phenotype. The app has redundantly specified
+ * the ANGLE metadata default value of "true".
+ */
+ @Test
+ public void testInterventionAllowAngleTrue() throws Exception {
+ mockDeviceConfigPerformanceEnableAngle();
+ mockInterventionAllowAngleTrue();
+
+ GameManagerService gameManagerService = new GameManagerService(mMockContext);
+ gameManagerService.onUserStarting(USER_ID_1);
+ mockModifyGameModeGranted();
+ gameManagerService.setGameMode(mPackageName, GameManager.GAME_MODE_PERFORMANCE, USER_ID_1);
+ assertEquals(GameManager.GAME_MODE_PERFORMANCE,
+ gameManagerService.getGameMode(mPackageName, USER_ID_1));
+
+ checkAngleEnabled(gameManagerService, GameManager.GAME_MODE_PERFORMANCE, true);
+ }
+
+ /**
* PERFORMANCE game mode is configured through Phenotype, but the app has also opted into the
* same mode. No interventions for this game mode should be available in this case.
*/
diff --git a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
index 34856e2..28cdd63 100644
--- a/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/display/LocalDisplayAdapterTest.java
@@ -142,6 +142,12 @@
.thenReturn(mockArray);
when(mMockedResources.obtainTypedArray(R.array.config_waterfallCutoutArray))
.thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerRadiusArray))
+ .thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerTopRadiusArray))
+ .thenReturn(mockArray);
+ when(mMockedResources.obtainTypedArray(R.array.config_roundedCornerBottomRadiusArray))
+ .thenReturn(mockArray);
}
@After
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
index 0d475c0..91bf4d1 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/AppSearchImplPlatformTest.java
@@ -135,7 +135,8 @@
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
// "schema1" is platform hidden now and package visible to package1
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -167,7 +168,8 @@
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
// Check that "schema1" still has the same visibility settings
SystemUtil.runWithShellPermissionIdentity(() -> assertThat(
@@ -241,7 +243,8 @@
"schema1",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
// "schema1" is platform hidden now and package accessible
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -269,7 +272,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
// Check that "schema1" is no longer considered platform hidden or package accessible
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
@@ -298,7 +302,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -333,7 +338,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -361,7 +367,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.singletonList("Schema"),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
assertThat(mVisibilityStore.isSchemaSearchableByCaller(
"package",
@@ -390,7 +397,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
assertThat(mVisibilityStore
.isSchemaSearchableByCaller(
"package",
@@ -431,7 +439,8 @@
"Schema",
ImmutableList.of(new PackageIdentifier(packageNameFoo, sha256CertFoo))),
/*forceOverride=*/ false,
- /*schemaVersion=*/ 0);
+ /*schemaVersion=*/ 0,
+ /*setSchemaStatsBuilder=*/ null);
assertThat(mVisibilityStore
.isSchemaSearchableByCaller(
"package",
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
index f40a5ad..dd3b3ec 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchImplTest.java
@@ -76,13 +76,14 @@
import java.util.Set;
public class AppSearchImplTest {
- @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- private AppSearchImpl mAppSearchImpl;
/**
* Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
*/
private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchImpl mAppSearchImpl;
+
@Before
public void setUp() throws Exception {
mAppSearchImpl =
@@ -439,7 +440,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert a document and then remove it to generate garbage.
GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -499,7 +501,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert a valid doc
GenericDocument validDoc =
@@ -591,7 +594,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert a valid doc
appSearchImpl.putDocument(
@@ -626,7 +630,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert document
GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -660,7 +665,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package",
"database2",
@@ -669,7 +675,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert documents
GenericDocument document1 =
@@ -714,7 +721,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert document
GenericDocument document = new GenericDocument.Builder<>("namespace", "id", "type").build();
@@ -756,7 +764,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert package2 schema
List<AppSearchSchema> schema2 =
@@ -769,7 +778,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert package1 document
GenericDocument document =
@@ -812,7 +822,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert package2 schema
List<AppSearchSchema> schema2 =
@@ -825,7 +836,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert package1 document
GenericDocument document =
@@ -889,7 +901,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -914,7 +927,8 @@
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
long nextPageToken = searchResultPage.getNextPageToken();
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -932,7 +946,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -962,14 +977,17 @@
AppSearchException e =
assertThrows(
AppSearchException.class,
- () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+ () ->
+ mAppSearchImpl.getNextPage(
+ "package2", nextPageToken, /*statsBuilder=*/ null));
assertThat(e)
.hasMessageThat()
.contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
// Can continue getting next page for package1
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -987,7 +1005,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1019,7 +1038,8 @@
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document2);
long nextPageToken = searchResultPage.getNextPageToken();
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -1037,7 +1057,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1074,14 +1095,17 @@
AppSearchException e =
assertThrows(
AppSearchException.class,
- () -> mAppSearchImpl.getNextPage("package2", nextPageToken));
+ () ->
+ mAppSearchImpl.getNextPage(
+ "package2", nextPageToken, /*statsBuilder=*/ null));
assertThat(e)
.hasMessageThat()
.contains("Package \"package2\" cannot use nextPageToken: " + nextPageToken);
assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
// Can continue getting next page for package1
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -1099,7 +1123,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1132,7 +1157,9 @@
AppSearchException e =
assertThrows(
AppSearchException.class,
- () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+ () ->
+ mAppSearchImpl.getNextPage(
+ "package1", nextPageToken, /*statsBuilder=*/ null));
assertThat(e)
.hasMessageThat()
.contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
@@ -1152,7 +1179,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1189,7 +1217,8 @@
assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
// Can continue getting next page for package1
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -1207,7 +1236,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1247,7 +1277,9 @@
AppSearchException e =
assertThrows(
AppSearchException.class,
- () -> mAppSearchImpl.getNextPage("package1", nextPageToken));
+ () ->
+ mAppSearchImpl.getNextPage(
+ "package1", nextPageToken, /*statsBuilder=*/ null));
assertThat(e)
.hasMessageThat()
.contains("Package \"package1\" cannot use nextPageToken: " + nextPageToken);
@@ -1267,7 +1299,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two package1 documents
GenericDocument document1 =
@@ -1311,7 +1344,8 @@
assertThat(e.getResultCode()).isEqualTo(AppSearchResult.RESULT_SECURITY_ERROR);
// Can continue getting next page for package1
- searchResultPage = mAppSearchImpl.getNextPage("package1", nextPageToken);
+ searchResultPage =
+ mAppSearchImpl.getNextPage("package1", nextPageToken, /*statsBuilder=*/ null);
assertThat(searchResultPage.getResults()).hasSize(1);
assertThat(searchResultPage.getResults().get(0).getGenericDocument()).isEqualTo(document1);
}
@@ -1355,7 +1389,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto =
@@ -1400,7 +1435,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create incompatible schema
List<AppSearchSchema> newSchemas =
@@ -1416,7 +1452,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Text");
assertThat(setSchemaResponse.getIncompatibleTypes()).containsExactly("Email");
}
@@ -1439,7 +1476,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto =
@@ -1472,8 +1510,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
-
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Check the Document type has been deleted.
assertThat(setSchemaResponse.getDeletedTypes()).containsExactly("Document");
@@ -1486,7 +1524,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Check Document schema is removed.
expectedProto =
@@ -1524,7 +1563,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package",
"database2",
@@ -1533,7 +1573,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType proto.
SchemaProto expectedProto =
@@ -1573,7 +1614,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ true,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Create expected schemaType list, database 1 should only contain Email but database 2
// remains in same.
@@ -1618,7 +1660,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert package document
GenericDocument document =
@@ -1680,7 +1723,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"packageB",
"database",
@@ -1689,7 +1733,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Verify these two packages is stored in AppSearch
SchemaProto expectedProto =
@@ -1735,7 +1780,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
assertThat(mAppSearchImpl.getPackageToDatabases())
.containsExactlyEntriesIn(expectedMapping);
@@ -1749,7 +1795,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
assertThat(mAppSearchImpl.getPackageToDatabases())
.containsExactlyEntriesIn(expectedMapping);
@@ -1763,7 +1810,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
assertThat(mAppSearchImpl.getPackageToDatabases())
.containsExactlyEntriesIn(expectedMapping);
}
@@ -1822,7 +1870,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two docs
GenericDocument document1 =
@@ -1973,7 +2022,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Since "package1" doesn't have a document, it get any space attributed to it.
StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForPackage("package1");
@@ -1996,7 +2046,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert document for "package1"
GenericDocument document =
@@ -2012,7 +2063,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert two documents for "package2"
document = new GenericDocument.Builder<>("namespace", "id1", "type").build();
@@ -2061,7 +2113,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// "package2" doesn't exist yet, so it shouldn't have any storage size
StorageInfo storageInfo =
@@ -2084,7 +2137,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Since "package1", "database1" doesn't have a document, it get any space attributed to it.
StorageInfo storageInfo = mAppSearchImpl.getStorageInfoForDatabase("package1", "database1");
@@ -2106,7 +2160,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package1",
"database2",
@@ -2115,7 +2170,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Add a document for "package1", "database1"
GenericDocument document =
@@ -2165,7 +2221,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
appSearchImpl.close();
@@ -2181,7 +2238,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0));
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null));
assertThrows(
IllegalStateException.class, () -> appSearchImpl.getSchema("package", "database"));
@@ -2225,7 +2283,9 @@
assertThrows(
IllegalStateException.class,
- () -> appSearchImpl.getNextPage("package", /*nextPageToken=*/ 1L));
+ () ->
+ appSearchImpl.getNextPage(
+ "package", /*nextPageToken=*/ 1L, /*statsBuilder=*/ null));
assertThrows(
IllegalStateException.class,
@@ -2296,7 +2356,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Add a document and persist it.
GenericDocument document =
@@ -2343,7 +2404,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Add two documents and persist them.
GenericDocument document1 =
@@ -2423,7 +2485,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Add two documents and persist them.
GenericDocument document1 =
@@ -2511,7 +2574,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Add two documents
GenericDocument document1 =
@@ -2562,7 +2626,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert a document which is too large
GenericDocument document =
@@ -2636,7 +2701,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index a document
mAppSearchImpl.putDocument(
@@ -2723,7 +2789,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index 3 documents
mAppSearchImpl.putDocument(
@@ -2836,7 +2903,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package1",
"database2",
@@ -2845,7 +2913,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package2",
"database1",
@@ -2854,7 +2923,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
mAppSearchImpl.setSchema(
"package2",
"database2",
@@ -2863,7 +2933,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index documents in package1/database1
mAppSearchImpl.putDocument(
@@ -3002,7 +3073,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index 3 documents
mAppSearchImpl.putDocument(
@@ -3131,7 +3203,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index a document
mAppSearchImpl.putDocument(
@@ -3210,7 +3283,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Index a document
mAppSearchImpl.putDocument(
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
index 7c97687..2ab5fd5 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/AppSearchLoggerTest.java
@@ -33,6 +33,7 @@
import com.android.server.appsearch.external.localstorage.stats.PutDocumentStats;
import com.android.server.appsearch.external.localstorage.stats.RemoveStats;
import com.android.server.appsearch.external.localstorage.stats.SearchStats;
+import com.android.server.appsearch.external.localstorage.stats.SetSchemaStats;
import com.android.server.appsearch.icing.proto.DeleteStatsProto;
import com.android.server.appsearch.icing.proto.DocumentProto;
import com.android.server.appsearch.icing.proto.InitializeStatsProto;
@@ -41,6 +42,7 @@
import com.android.server.appsearch.icing.proto.PutResultProto;
import com.android.server.appsearch.icing.proto.QueryStatsProto;
import com.android.server.appsearch.icing.proto.ScoringSpecProto;
+import com.android.server.appsearch.icing.proto.SetSchemaResultProto;
import com.android.server.appsearch.icing.proto.StatusProto;
import com.android.server.appsearch.icing.proto.TermMatchType;
@@ -57,14 +59,17 @@
import java.util.List;
public class AppSearchLoggerTest {
- @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
- private AppSearchImpl mAppSearchImpl;
- private TestLogger mLogger;
+ private static final String PACKAGE_NAME = "packageName";
+ private static final String DATABASE = "database";
/**
* Always trigger optimize in this class. OptimizeStrategy will be tested in its own test class.
*/
private static final OptimizeStrategy ALWAYS_OPTIMIZE = optimizeInfo -> true;
+ @Rule public TemporaryFolder mTemporaryFolder = new TemporaryFolder();
+ private AppSearchImpl mAppSearchImpl;
+ private TestLogger mLogger;
+
@Before
public void setUp() throws Exception {
mAppSearchImpl =
@@ -84,6 +89,7 @@
@Nullable SearchStats mSearchStats;
@Nullable RemoveStats mRemoveStats;
@Nullable OptimizeStats mOptimizeStats;
+ @Nullable SetSchemaStats mSetSchemaStats;
@Override
public void logStats(@NonNull CallStats stats) {
@@ -114,6 +120,11 @@
public void logStats(@NonNull OptimizeStats stats) {
mOptimizeStats = stats;
}
+
+ @Override
+ public void logStats(@NonNull SetSchemaStats stats) {
+ mSetSchemaStats = stats;
+ }
}
@Test
@@ -194,7 +205,7 @@
.setExceededMaxTokenNum(nativeExceededMaxNumTokens)
.build())
.build();
- PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder("packageName", "database");
+ PutDocumentStats.Builder pBuilder = new PutDocumentStats.Builder(PACKAGE_NAME, DATABASE);
AppSearchLoggerHelper.copyNativeStats(nativePutDocumentStats, pBuilder);
@@ -248,8 +259,8 @@
.setDocumentRetrievalLatencyMs(nativeDocumentRetrievingLatencyMillis)
.build();
SearchStats.Builder qBuilder =
- new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, "packageName")
- .setDatabase("database");
+ new SearchStats.Builder(SearchStats.VISIBILITY_SCOPE_LOCAL, PACKAGE_NAME)
+ .setDatabase(DATABASE);
AppSearchLoggerHelper.copyNativeStats(nativeQueryStats, qBuilder);
@@ -336,6 +347,35 @@
.isEqualTo(nativeTimeSinceLastOptimizeMillis);
}
+ @Test
+ public void testAppSearchLoggerHelper_testCopyNativeStats_setSchema() {
+ ImmutableList<String> newSchemaTypeChangeList = ImmutableList.of("new1");
+ ImmutableList<String> deletedSchemaTypesList = ImmutableList.of("deleted1", "deleted2");
+ ImmutableList<String> compatibleTypesList = ImmutableList.of("compatible1", "compatible2");
+ ImmutableList<String> indexIncompatibleTypeChangeList = ImmutableList.of("index1");
+ ImmutableList<String> backwardsIncompatibleTypeChangeList = ImmutableList.of("backwards1");
+ SetSchemaResultProto setSchemaResultProto =
+ SetSchemaResultProto.newBuilder()
+ .addAllNewSchemaTypes(newSchemaTypeChangeList)
+ .addAllDeletedSchemaTypes(deletedSchemaTypesList)
+ .addAllFullyCompatibleChangedSchemaTypes(compatibleTypesList)
+ .addAllIndexIncompatibleChangedSchemaTypes(indexIncompatibleTypeChangeList)
+ .addAllIncompatibleSchemaTypes(backwardsIncompatibleTypeChangeList)
+ .build();
+ SetSchemaStats.Builder sBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+
+ AppSearchLoggerHelper.copyNativeStats(setSchemaResultProto, sBuilder);
+
+ SetSchemaStats sStats = sBuilder.build();
+ assertThat(sStats.getNewTypeCount()).isEqualTo(newSchemaTypeChangeList.size());
+ assertThat(sStats.getDeletedTypeCount()).isEqualTo(deletedSchemaTypesList.size());
+ assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypesList.size());
+ assertThat(sStats.getIndexIncompatibleTypeChangeCount())
+ .isEqualTo(indexIncompatibleTypeChangeList.size());
+ assertThat(sStats.getBackwardsIncompatibleTypeChangeCount())
+ .isEqualTo(backwardsIncompatibleTypeChangeList.size());
+ }
+
//
// Testing actual logging
//
@@ -388,7 +428,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
GenericDocument doc2 = new GenericDocument.Builder<>("namespace", "id2", "Type1").build();
appSearchImpl.putDocument(testPackageName, testDatabase, doc1, mLogger);
@@ -439,7 +480,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
// Insert a valid doc
GenericDocument doc1 = new GenericDocument.Builder<>("namespace", "id1", "Type1").build();
@@ -495,7 +537,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document =
new GenericDocument.Builder<>("namespace", "id", "type")
@@ -542,7 +585,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document =
new GenericDocument.Builder<>("namespace", "id", "type")
@@ -592,7 +636,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document1 =
new GenericDocument.Builder<>("namespace", "id1", "type")
.setPropertyString("subject", "testPut example1")
@@ -661,7 +706,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
SearchSpec searchSpec =
new SearchSpec.Builder()
@@ -701,7 +747,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document =
new GenericDocument.Builder<>(testNamespace, testId, "type").build();
mAppSearchImpl.putDocument(testPackageName, testDatabase, document, /*logger=*/ null);
@@ -735,7 +782,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document =
new GenericDocument.Builder<>(testNamespace, testId, "type").build();
@@ -780,7 +828,8 @@
/*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
/*schemasVisibleToPackages=*/ Collections.emptyMap(),
/*forceOverride=*/ false,
- /*version=*/ 0);
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
GenericDocument document1 =
new GenericDocument.Builder<>(testNamespace, "id1", "type").build();
GenericDocument document2 =
@@ -800,7 +849,58 @@
assertThat(rStats.getDatabase()).isEqualTo(testDatabase);
assertThat(rStats.getStatusCode()).isEqualTo(AppSearchResult.RESULT_OK);
// delete by query
- assertThat(rStats.getDeleteType()).isEqualTo(DeleteStatsProto.DeleteType.Code.QUERY_VALUE);
+ assertThat(rStats.getDeleteType())
+ .isEqualTo(DeleteStatsProto.DeleteType.Code.DEPRECATED_QUERY_VALUE);
assertThat(rStats.getDeletedDocumentCount()).isEqualTo(2);
}
+
+ @Test
+ public void testLoggingStats_setSchema() throws Exception {
+ AppSearchSchema schema1 =
+ new AppSearchSchema.Builder("testSchema")
+ .addProperty(
+ new AppSearchSchema.StringPropertyConfig.Builder("subject")
+ .setCardinality(
+ AppSearchSchema.PropertyConfig.CARDINALITY_REQUIRED)
+ .setIndexingType(
+ AppSearchSchema.StringPropertyConfig
+ .INDEXING_TYPE_PREFIXES)
+ .setTokenizerType(
+ AppSearchSchema.StringPropertyConfig
+ .TOKENIZER_TYPE_PLAIN)
+ .build())
+ .build();
+ mAppSearchImpl.setSchema(
+ PACKAGE_NAME,
+ DATABASE,
+ Collections.singletonList(schema1),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ null);
+
+ // create a backwards incompatible schema
+ SetSchemaStats.Builder sStatsBuilder = new SetSchemaStats.Builder(PACKAGE_NAME, DATABASE);
+ AppSearchSchema schema2 = new AppSearchSchema.Builder("testSchema").build();
+ mAppSearchImpl.setSchema(
+ PACKAGE_NAME,
+ DATABASE,
+ Collections.singletonList(schema2),
+ /*visibilityStore=*/ null,
+ /*schemasNotDisplayedBySystem=*/ Collections.emptyList(),
+ /*schemasVisibleToPackages=*/ Collections.emptyMap(),
+ /*forceOverride=*/ false,
+ /*version=*/ 0,
+ /* setSchemaStatsBuilder= */ sStatsBuilder);
+
+ SetSchemaStats sStats = sStatsBuilder.build();
+ assertThat(sStats.getPackageName()).isEqualTo(PACKAGE_NAME);
+ assertThat(sStats.getDatabase()).isEqualTo(DATABASE);
+ assertThat(sStats.getNewTypeCount()).isEqualTo(0);
+ assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(0);
+ assertThat(sStats.getIndexIncompatibleTypeChangeCount()).isEqualTo(1);
+ assertThat(sStats.getBackwardsIncompatibleTypeChangeCount()).isEqualTo(1);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
index c1dc0e4..81aab41 100644
--- a/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
+++ b/services/tests/servicestests/src/com/android/server/appsearch/external/localstorage/stats/AppSearchStatsTest.java
@@ -264,17 +264,15 @@
.setMigratedDocumentCount(6)
.setSavedDocumentCount(7)
.build();
- int nativeLatencyMillis = 1;
- int newTypeCount = 2;
- int compatibleTypeChangeCount = 3;
- int indexIncompatibleTypeChangeCount = 4;
- int backwardsIncompatibleTypeChangeCount = 5;
+ int newTypeCount = 1;
+ int compatibleTypeChangeCount = 2;
+ int indexIncompatibleTypeChangeCount = 3;
+ int backwardsIncompatibleTypeChangeCount = 4;
SetSchemaStats sStats =
new SetSchemaStats.Builder(TEST_PACKAGE_NAME, TEST_DATA_BASE)
.setStatusCode(TEST_STATUS_CODE)
.setSchemaMigrationStats(schemaMigrationStats)
.setTotalLatencyMillis(TEST_TOTAL_LATENCY_MILLIS)
- .setNativeLatencyMillis(nativeLatencyMillis)
.setNewTypeCount(newTypeCount)
.setCompatibleTypeChangeCount(compatibleTypeChangeCount)
.setIndexIncompatibleTypeChangeCount(indexIncompatibleTypeChangeCount)
@@ -287,7 +285,6 @@
assertThat(sStats.getStatusCode()).isEqualTo(TEST_STATUS_CODE);
assertThat(sStats.getSchemaMigrationStats()).isEqualTo(schemaMigrationStats);
assertThat(sStats.getTotalLatencyMillis()).isEqualTo(TEST_TOTAL_LATENCY_MILLIS);
- assertThat(sStats.getNativeLatencyMillis()).isEqualTo(nativeLatencyMillis);
assertThat(sStats.getNewTypeCount()).isEqualTo(newTypeCount);
assertThat(sStats.getCompatibleTypeChangeCount()).isEqualTo(compatibleTypeChangeCount);
assertThat(sStats.getIndexIncompatibleTypeChangeCount())
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
index 2892bf5..b3f7587 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/AuthSessionTest.java
@@ -74,6 +74,7 @@
public class AuthSessionTest {
private static final String TEST_PACKAGE = "test_package";
+ private static final long TEST_REQUEST_ID = 22;
@Mock private Context mContext;
@Mock private ITrustManager mTrustManager;
@@ -112,6 +113,7 @@
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG,
+ TEST_REQUEST_ID,
0 /* operationId */,
0 /* userId */);
@@ -133,6 +135,7 @@
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG,
+ TEST_REQUEST_ID,
operationId,
userId);
assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -153,6 +156,7 @@
eq(userId),
eq(mSensorReceiver),
eq(TEST_PACKAGE),
+ eq(TEST_REQUEST_ID),
eq(sensor.getCookie()),
anyBoolean() /* allowBackgroundAuthentication */);
}
@@ -185,6 +189,33 @@
}
@Test
+ public void testCancelReducesAppetiteForCookies() throws Exception {
+ setupFace(0 /* id */, false /* confirmationAlwaysRequired */,
+ mock(IBiometricAuthenticator.class));
+ setupFingerprint(1 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
+
+ final AuthSession session = createAuthSession(mSensors,
+ false /* checkDevicePolicyManager */,
+ Authenticators.BIOMETRIC_STRONG,
+ TEST_REQUEST_ID,
+ 44 /* operationId */,
+ 2 /* userId */);
+
+ session.goToInitialState();
+
+ for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+ assertEquals(BiometricSensor.STATE_WAITING_FOR_COOKIE, sensor.getSensorState());
+ }
+
+ session.onCancelAuthSession(false /* force */);
+
+ for (BiometricSensor sensor : session.mPreAuthInfo.eligibleSensors) {
+ session.onCookieReceived(sensor.getCookie());
+ assertEquals(BiometricSensor.STATE_CANCELING, sensor.getSensorState());
+ }
+ }
+
+ @Test
public void testMultiAuth_singleSensor_fingerprintSensorStartsAfterDialogAnimationCompletes()
throws Exception {
setupFingerprint(0 /* id */, FingerprintSensorProperties.TYPE_UDFPS_OPTICAL);
@@ -212,6 +243,7 @@
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG,
+ TEST_REQUEST_ID,
operationId,
userId);
assertEquals(mSensors.size(), session.mPreAuthInfo.eligibleSensors.size());
@@ -238,7 +270,7 @@
// fingerprint sensor does not start even if all cookies are received
assertEquals(STATE_AUTH_STARTED, session.getState());
verify(mStatusBarService).showAuthenticationDialog(any(), any(), any(),
- anyBoolean(), anyBoolean(), anyInt(), any(), anyLong(), anyInt());
+ anyBoolean(), anyBoolean(), anyInt(), anyLong(), any(), anyLong(), anyInt());
// Notify AuthSession that the UI is shown. Then, fingerprint sensor should be started.
session.onDialogAnimatedIn();
@@ -277,6 +309,7 @@
final AuthSession session = createAuthSession(mSensors,
false /* checkDevicePolicyManager */,
Authenticators.BIOMETRIC_STRONG,
+ TEST_REQUEST_ID,
0 /* operationId */,
0 /* userId */);
@@ -285,7 +318,8 @@
sessionConsumer.accept(session);
- verify(faceAuthenticator).cancelAuthenticationFromService(eq(mToken), eq(TEST_PACKAGE));
+ verify(faceAuthenticator).cancelAuthenticationFromService(
+ eq(mToken), eq(TEST_PACKAGE), eq(TEST_REQUEST_ID));
}
private PreAuthInfo createPreAuthInfo(List<BiometricSensor> sensors, int userId,
@@ -302,14 +336,14 @@
private AuthSession createAuthSession(List<BiometricSensor> sensors,
boolean checkDevicePolicyManager, @Authenticators.Types int authenticators,
- long operationId, int userId) throws RemoteException {
+ long requestId, long operationId, int userId) throws RemoteException {
final PromptInfo promptInfo = createPromptInfo(authenticators);
final PreAuthInfo preAuthInfo = createPreAuthInfo(sensors, userId, promptInfo,
checkDevicePolicyManager);
return new AuthSession(mContext, mStatusBarService, mSysuiReceiver, mKeyStore,
- mRandom, mClientDeathReceiver, preAuthInfo, mToken, operationId, userId,
+ mRandom, mClientDeathReceiver, preAuthInfo, mToken, requestId, operationId, userId,
mSensorReceiver, mClientReceiver, TEST_PACKAGE, promptInfo,
false /* debugEnabled */, mFingerprintSensorProps);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
index 7c7afb7..69d8e89 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/BiometricServiceTest.java
@@ -85,6 +85,7 @@
import org.mockito.MockitoAnnotations;
import java.util.Random;
+import java.util.concurrent.atomic.AtomicLong;
@Presubmit
@SmallTest
@@ -93,6 +94,7 @@
private static final String TAG = "BiometricServiceTest";
private static final String TEST_PACKAGE_NAME = "test_package";
+ private static final long TEST_REQUEST_ID = 44;
private static final String ERROR_HW_UNAVAILABLE = "hw_unavailable";
private static final String ERROR_NOT_RECOGNIZED = "not_recognized";
@@ -151,6 +153,7 @@
.thenReturn(mock(BiometricStrengthController.class));
when(mInjector.getTrustManager()).thenReturn(mTrustManager);
when(mInjector.getDevicePolicyManager(any())).thenReturn(mDevicePolicyManager);
+ when(mInjector.getRequestGenerator()).thenReturn(new AtomicLong(TEST_REQUEST_ID - 1));
when(mResources.getString(R.string.biometric_error_hw_unavailable))
.thenReturn(ERROR_HW_UNAVAILABLE);
@@ -215,8 +218,7 @@
mBiometricService.mCurrentAuthSession.getState());
verify(mBiometricService.mCurrentAuthSession.mPreAuthInfo.eligibleSensors.get(0).impl)
- .cancelAuthenticationFromService(any(),
- any());
+ .cancelAuthenticationFromService(any(), any(), anyLong());
// Simulate ERROR_CANCELED received from HAL
mBiometricService.mBiometricSensorReceiver.onError(
@@ -272,8 +274,9 @@
eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -357,8 +360,9 @@
eq(false) /* credentialAllowed */,
eq(false) /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -467,6 +471,7 @@
anyInt() /* userId */,
any(IBiometricSensorReceiver.class),
anyString() /* opPackageName */,
+ eq(TEST_REQUEST_ID),
cookieCaptor.capture() /* cookie */,
anyBoolean() /* allowBackgroundAuthentication */);
@@ -488,8 +493,9 @@
eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Hardware authenticated
@@ -543,8 +549,9 @@
eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -705,8 +712,9 @@
anyBoolean() /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
anyString(),
- anyLong() /* sessionId */,
+ anyLong() /* requestId */,
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -805,8 +813,9 @@
eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -885,8 +894,9 @@
eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(TEST_REQUEST_ID),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -1030,8 +1040,7 @@
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
eq(0 /* vendorCode */));
verify(mBiometricService.mSensors.get(0).impl).cancelAuthenticationFromService(
- any(),
- any());
+ any(), any(), anyLong());
assertNull(mBiometricService.mCurrentAuthSession);
}
@@ -1051,7 +1060,7 @@
waitForIdle();
verify(mBiometricService.mSensors.get(0).impl)
- .cancelAuthenticationFromService(any(), any());
+ .cancelAuthenticationFromService(any(), any(), anyLong());
}
@Test
@@ -1071,7 +1080,7 @@
waitForIdle();
verify(mBiometricService.mSensors.get(0).impl)
- .cancelAuthenticationFromService(any(), any());
+ .cancelAuthenticationFromService(any(), any(), anyLong());
}
@Test
@@ -1088,7 +1097,7 @@
waitForIdle();
verify(mBiometricService.mSensors.get(0).impl)
- .cancelAuthenticationFromService(any(), any());
+ .cancelAuthenticationFromService(any(), any(), anyLong());
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_FACE),
eq(BiometricConstants.BIOMETRIC_ERROR_USER_CANCELED),
@@ -1126,7 +1135,7 @@
false /* requireConfirmation */, null /* authenticators */);
mBiometricService.mImpl.cancelAuthentication(mBiometricService.mCurrentAuthSession.mToken,
- TEST_PACKAGE_NAME);
+ TEST_PACKAGE_NAME, TEST_REQUEST_ID);
waitForIdle();
// Pretend that the HAL has responded to cancel with ERROR_CANCELED
@@ -1353,8 +1362,8 @@
int authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_ERROR_SECURITY_UPDATE_REQUIRED,
invokeCanAuthenticate(mBiometricService, authenticators));
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1, false /* requireConfirmation */,
- authenticators);
+ long requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
+ false /* requireConfirmation */, authenticators);
waitForIdle();
verify(mReceiver1).onError(
eq(BiometricAuthenticator.TYPE_FINGERPRINT),
@@ -1366,7 +1375,7 @@
authenticators = Authenticators.BIOMETRIC_WEAK;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
- invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
authenticators);
waitForIdle();
@@ -1377,8 +1386,9 @@
eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Requesting strong and credential, when credential is setup
@@ -1387,7 +1397,7 @@
when(mTrustManager.isDeviceSecure(anyInt())).thenReturn(true);
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
- invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
+ requestId = invokeAuthenticate(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */,
authenticators);
waitForIdle();
@@ -1399,8 +1409,9 @@
eq(true) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
// Un-downgrading the authenticator allows successful strong auth
@@ -1414,7 +1425,7 @@
authenticators = Authenticators.BIOMETRIC_STRONG;
assertEquals(BiometricManager.BIOMETRIC_SUCCESS,
invokeCanAuthenticate(mBiometricService, authenticators));
- invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
+ requestId = invokeAuthenticateAndStart(mBiometricService.mImpl, mReceiver1,
false /* requireConfirmation */, authenticators);
waitForIdle();
verify(mBiometricService.mStatusBarService).showAuthenticationDialog(
@@ -1424,8 +1435,9 @@
eq(false) /* credentialAllowed */,
anyBoolean() /* requireConfirmation */,
anyInt() /* userId */,
+ anyLong() /* operationId */,
eq(TEST_PACKAGE_NAME),
- anyLong() /* sessionId */,
+ eq(requestId),
eq(BIOMETRIC_MULTI_SENSOR_DEFAULT));
}
@@ -1617,11 +1629,12 @@
mBiometricService.mStatusBarService = mock(IStatusBarService.class);
}
- private void invokeAuthenticateAndStart(IBiometricService.Stub service,
+ private long invokeAuthenticateAndStart(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation,
Integer authenticators) throws Exception {
// Request auth, creates a pending session
- invokeAuthenticate(service, receiver, requireConfirmation, authenticators);
+ final long requestId = invokeAuthenticate(
+ service, receiver, requireConfirmation, authenticators);
waitForIdle();
startPendingAuthSession(mBiometricService);
@@ -1629,6 +1642,8 @@
assertNotNull(mBiometricService.mCurrentAuthSession);
assertEquals(STATE_AUTH_STARTED, mBiometricService.mCurrentAuthSession.getState());
+
+ return requestId;
}
private static void startPendingAuthSession(BiometricService service) throws Exception {
@@ -1644,10 +1659,10 @@
service.mImpl.onReadyForAuthentication(cookie);
}
- private static void invokeAuthenticate(IBiometricService.Stub service,
+ private static long invokeAuthenticate(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, boolean requireConfirmation,
Integer authenticators) throws Exception {
- service.authenticate(
+ return service.authenticate(
new Binder() /* token */,
0 /* operationId */,
0 /* userId */,
@@ -1657,9 +1672,9 @@
false /* checkDevicePolicy */));
}
- private static void invokeAuthenticateForWorkApp(IBiometricService.Stub service,
+ private static long invokeAuthenticateForWorkApp(IBiometricService.Stub service,
IBiometricServiceReceiver receiver, Integer authenticators) throws Exception {
- service.authenticate(
+ return service.authenticate(
new Binder() /* token */,
0 /* operationId */,
0 /* userId */,
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
index a41f79e..e3e3900 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/BiometricSchedulerTest.java
@@ -40,6 +40,7 @@
import android.testing.TestableContext;
import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
import androidx.test.InstrumentationRegistry;
import androidx.test.filters.SmallTest;
@@ -193,7 +194,7 @@
// Request it to be canceled. The operation can be canceled immediately, and the scheduler
// should go back to idle, since in this case the framework has not even requested the HAL
// to authenticate yet.
- mScheduler.cancelAuthenticationOrDetection(mToken);
+ mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
assertNull(mScheduler.mCurrentOperation);
}
@@ -303,7 +304,7 @@
mScheduler.mPendingOperations.getFirst().mState);
// Request cancel before the authentication client has started
- mScheduler.cancelAuthenticationOrDetection(mToken);
+ mScheduler.cancelAuthenticationOrDetection(mToken, 1 /* requestId */);
waitForIdle();
assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
mScheduler.mPendingOperations.getFirst().mState);
@@ -318,6 +319,107 @@
}
@Test
+ public void testCancels_whenAuthRequestIdNotSet() {
+ testCancelsWhenRequestId(null /* requestId */, 2, true /* started */);
+ }
+
+ @Test
+ public void testCancels_whenAuthRequestIdNotSet_notStarted() {
+ testCancelsWhenRequestId(null /* requestId */, 2, false /* started */);
+ }
+
+ @Test
+ public void testCancels_whenAuthRequestIdMatches() {
+ testCancelsWhenRequestId(200L, 200, true /* started */);
+ }
+
+ @Test
+ public void testCancels_whenAuthRequestIdMatches_noStarted() {
+ testCancelsWhenRequestId(200L, 200, false /* started */);
+ }
+
+ @Test
+ public void testDoesNotCancel_whenAuthRequestIdMismatched() {
+ testCancelsWhenRequestId(10L, 20, true /* started */);
+ }
+
+ @Test
+ public void testDoesNotCancel_whenAuthRequestIdMismatched_notStarted() {
+ testCancelsWhenRequestId(10L, 20, false /* started */);
+ }
+
+ private void testCancelsWhenRequestId(@Nullable Long requestId, long cancelRequestId,
+ boolean started) {
+ final boolean matches = requestId == null || requestId == cancelRequestId;
+ final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
+ final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+ final TestAuthenticationClient client = new TestAuthenticationClient(
+ mContext, lazyDaemon, mToken, callback);
+ if (requestId != null) {
+ client.setRequestId(requestId);
+ }
+
+ mScheduler.scheduleClientMonitor(client);
+ if (started) {
+ mScheduler.startPreparedClient(client.getCookie());
+ }
+ waitForIdle();
+ mScheduler.cancelAuthenticationOrDetection(mToken, cancelRequestId);
+ waitForIdle();
+
+ assertEquals(matches && started ? 1 : 0, client.mNumCancels);
+
+ if (matches) {
+ if (started) {
+ assertEquals(Operation.STATE_STARTED_CANCELING,
+ mScheduler.mCurrentOperation.mState);
+ }
+ } else {
+ if (started) {
+ assertEquals(Operation.STATE_STARTED,
+ mScheduler.mCurrentOperation.mState);
+ } else {
+ assertEquals(Operation.STATE_WAITING_FOR_COOKIE,
+ mScheduler.mCurrentOperation.mState);
+ }
+ }
+ }
+
+ @Test
+ public void testCancelsPending_whenAuthRequestIdsSet() {
+ final long requestId1 = 10;
+ final long requestId2 = 20;
+ final HalClientMonitor.LazyDaemon<Object> lazyDaemon = () -> mock(Object.class);
+ final ClientMonitorCallbackConverter callback = mock(ClientMonitorCallbackConverter.class);
+ final TestAuthenticationClient client1 = new TestAuthenticationClient(
+ mContext, lazyDaemon, mToken, callback);
+ client1.setRequestId(requestId1);
+ final TestAuthenticationClient client2 = new TestAuthenticationClient(
+ mContext, lazyDaemon, mToken, callback);
+ client2.setRequestId(requestId2);
+
+ mScheduler.scheduleClientMonitor(client1);
+ mScheduler.scheduleClientMonitor(client2);
+ mScheduler.startPreparedClient(client1.getCookie());
+ waitForIdle();
+ mScheduler.cancelAuthenticationOrDetection(mToken, 9999);
+ waitForIdle();
+
+ assertEquals(Operation.STATE_STARTED,
+ mScheduler.mCurrentOperation.mState);
+ assertEquals(Operation.STATE_WAITING_IN_QUEUE,
+ mScheduler.mPendingOperations.getFirst().mState);
+
+ mScheduler.cancelAuthenticationOrDetection(mToken, requestId2);
+ waitForIdle();
+
+ assertEquals(Operation.STATE_STARTED,
+ mScheduler.mCurrentOperation.mState);
+ assertEquals(Operation.STATE_WAITING_IN_QUEUE_CANCELING,
+ mScheduler.mPendingOperations.getFirst().mState);
+ }
+
+ @Test
public void testInterruptPrecedingClients_whenExpected() {
final BaseClientMonitor interruptableMonitor = mock(BaseClientMonitor.class,
withSettings().extraInterfaces(Interruptable.class));
@@ -377,12 +479,10 @@
@Override
protected void stopHalOperation() {
-
}
@Override
protected void startHalOperation() {
-
}
@Override
@@ -397,6 +497,7 @@
}
private static class TestAuthenticationClient extends AuthenticationClient<Object> {
+ int mNumCancels = 0;
public TestAuthenticationClient(@NonNull Context context,
@NonNull LazyDaemon<Object> lazyDaemon, @NonNull IBinder token,
@@ -428,6 +529,11 @@
public boolean wasUserDetected() {
return false;
}
+
+ public void cancel() {
+ mNumCancels++;
+ super.cancel();
+ }
}
private static class TestClientMonitor2 extends TestClientMonitor {
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java
new file mode 100644
index 0000000..09b5c5c
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/CompositeCallbackTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.biometrics.sensors;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import org.junit.Test;
+
+@Presubmit
+@SmallTest
+public class CompositeCallbackTest {
+
+ @Test
+ public void testNullCallback() {
+ BaseClientMonitor.Callback callback1 = mock(BaseClientMonitor.Callback.class);
+ BaseClientMonitor.Callback callback2 = mock(BaseClientMonitor.Callback.class);
+ BaseClientMonitor.Callback callback3 = null;
+
+ BaseClientMonitor.CompositeCallback callback = new BaseClientMonitor.CompositeCallback(
+ callback1, callback2, callback3);
+
+ BaseClientMonitor clientMonitor = mock(BaseClientMonitor.class);
+
+ callback.onClientStarted(clientMonitor);
+ verify(callback1).onClientStarted(eq(clientMonitor));
+ verify(callback2).onClientStarted(eq(clientMonitor));
+
+ callback.onClientFinished(clientMonitor, true /* success */);
+ verify(callback1).onClientFinished(eq(clientMonitor), eq(true));
+ verify(callback2).onClientFinished(eq(clientMonitor), eq(true));
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java
new file mode 100644
index 0000000..38e8dfa
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/FingerprintStateCallbackTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.biometrics.sensors.fingerprint;
+
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.hardware.fingerprint.FingerprintStateListener;
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.server.biometrics.sensors.AuthenticationClient;
+import com.android.server.biometrics.sensors.EnrollClient;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@Presubmit
+@SmallTest
+public class FingerprintStateCallbackTest {
+
+ private FingerprintStateCallback mCallback;
+
+ @Mock
+ FingerprintStateListener mFingerprintStateListener;
+
+ @Before
+ public void setup() {
+ MockitoAnnotations.initMocks(this);
+
+ mCallback = new FingerprintStateCallback();
+ mCallback.registerFingerprintStateListener(mFingerprintStateListener);
+ }
+
+ @Test
+ public void testNoEnrollmentsToEnrollments_callbackNotified() {
+ testEnrollmentCallback(true /* changed */, true /* isNowEnrolled */,
+ true /* expectCallback */, true /* expectedCallbackValue */);
+ }
+
+ @Test
+ public void testEnrollmentsToNoEnrollments_callbackNotified() {
+ testEnrollmentCallback(true /* changed */, false /* isNowEnrolled */,
+ true /* expectCallback */, false /* expectedCallbackValue */);
+ }
+
+ @Test
+ public void testEnrollmentsToEnrollments_callbackNotNotified() {
+ testEnrollmentCallback(false /* changed */, true /* isNowEnrolled */,
+ false /* expectCallback */, false /* expectedCallbackValue */);
+ }
+
+ private void testEnrollmentCallback(boolean changed, boolean isNowEnrolled,
+ boolean expectCallback, boolean expectedCallbackValue) {
+ EnrollClient<?> client = mock(EnrollClient.class);
+
+ final int userId = 10;
+ final int sensorId = 100;
+
+ when(client.hasEnrollmentStateChanged()).thenReturn(changed);
+ when(client.hasEnrollments()).thenReturn(isNowEnrolled);
+ when(client.getTargetUserId()).thenReturn(userId);
+ when(client.getSensorId()).thenReturn(sensorId);
+
+ mCallback.onClientFinished(client, true /* success */);
+ if (expectCallback) {
+ verify(mFingerprintStateListener).onEnrollmentsChanged(eq(userId), eq(sensorId),
+ eq(expectedCallbackValue));
+ } else {
+ verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
+ anyBoolean());
+ }
+ }
+
+ @Test
+ public void testAuthentication_enrollmentCallbackNeverNotified() {
+ AuthenticationClient<?> client = mock(AuthenticationClient.class);
+ mCallback.onClientFinished(client, true /* success */);
+ verify(mFingerprintStateListener, never()).onEnrollmentsChanged(anyInt(), anyInt(),
+ anyBoolean());
+ }
+}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
index 35c37ef..b51918e 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/aidl/FingerprintProviderTest.java
@@ -37,6 +37,7 @@
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.HalClientMonitor;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher;
import org.junit.Before;
@@ -58,6 +59,8 @@
private UserManager mUserManager;
@Mock
private GestureAvailabilityDispatcher mGestureAvailabilityDispatcher;
+ @Mock
+ private FingerprintStateCallback mFingerprintStateCallback;
private SensorProps[] mSensorProps;
private LockoutResetDispatcher mLockoutResetDispatcher;
@@ -87,8 +90,8 @@
mLockoutResetDispatcher = new LockoutResetDispatcher(mContext);
- mFingerprintProvider = new TestableFingerprintProvider(mContext, mSensorProps, TAG,
- mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
+ mFingerprintProvider = new TestableFingerprintProvider(mContext, mFingerprintStateCallback,
+ mSensorProps, TAG, mLockoutResetDispatcher, mGestureAvailabilityDispatcher);
}
@SuppressWarnings("rawtypes")
@@ -133,11 +136,12 @@
private static class TestableFingerprintProvider extends FingerprintProvider {
public TestableFingerprintProvider(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull SensorProps[] props,
@NonNull String halInstanceName,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) {
- super(context, props, halInstanceName, lockoutResetDispatcher,
+ super(context, fingerprintStateCallback, props, halInstanceName, lockoutResetDispatcher,
gestureAvailabilityDispatcher);
}
diff --git a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
index 0a0dcc9..f6b9209 100644
--- a/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
+++ b/services/tests/servicestests/src/com/android/server/biometrics/sensors/fingerprint/hidl/Fingerprint21Test.java
@@ -41,6 +41,7 @@
import com.android.internal.R;
import com.android.server.biometrics.sensors.BiometricScheduler;
import com.android.server.biometrics.sensors.LockoutResetDispatcher;
+import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback;
import org.junit.Before;
import org.junit.Test;
@@ -67,6 +68,8 @@
Fingerprint21.HalResultController mHalResultController;
@Mock
private BiometricScheduler mScheduler;
+ @Mock
+ private FingerprintStateCallback mFingerprintStateCallback;
private LockoutResetDispatcher mLockoutResetDispatcher;
private Fingerprint21 mFingerprint21;
@@ -96,8 +99,9 @@
componentInfo, FingerprintSensorProperties.TYPE_UNKNOWN,
resetLockoutRequiresHardwareAuthToken);
- mFingerprint21 = new TestableFingerprint21(mContext, sensorProps, mScheduler,
- new Handler(Looper.getMainLooper()), mLockoutResetDispatcher, mHalResultController);
+ mFingerprint21 = new TestableFingerprint21(mContext, mFingerprintStateCallback, sensorProps,
+ mScheduler, new Handler(Looper.getMainLooper()), mLockoutResetDispatcher,
+ mHalResultController);
}
@Test
@@ -118,11 +122,13 @@
private static class TestableFingerprint21 extends Fingerprint21 {
TestableFingerprint21(@NonNull Context context,
+ @NonNull FingerprintStateCallback fingerprintStateCallback,
@NonNull FingerprintSensorPropertiesInternal sensorProps,
@NonNull BiometricScheduler scheduler, @NonNull Handler handler,
@NonNull LockoutResetDispatcher lockoutResetDispatcher,
@NonNull HalResultController controller) {
- super(context, sensorProps, scheduler, handler, lockoutResetDispatcher, controller);
+ super(context, fingerprintStateCallback, sensorProps, scheduler, handler,
+ lockoutResetDispatcher, controller);
}
@Override
diff --git a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
index 1ac28ab..4564296 100644
--- a/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/DisplayModeDirectorTest.java
@@ -56,7 +56,11 @@
import android.hardware.display.DisplayManagerInternal.RefreshRateRange;
import android.hardware.fingerprint.IUdfpsHbmListener;
import android.os.Handler;
+import android.os.IThermalEventListener;
+import android.os.IThermalService;
import android.os.Looper;
+import android.os.RemoteException;
+import android.os.Temperature;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.test.mock.MockContentResolver;
@@ -116,6 +120,8 @@
public SensorManagerInternal mSensorManagerInternalMock;
@Mock
public DisplayManagerInternal mDisplayManagerInternalMock;
+ @Mock
+ public IThermalService mThermalServiceMock;
@Before
public void setUp() throws Exception {
@@ -124,6 +130,7 @@
final MockContentResolver resolver = mSettingsProviderRule.mockContentResolver(mContext);
when(mContext.getContentResolver()).thenReturn(resolver);
mInjector = spy(new FakesInjector());
+ when(mInjector.getThermalService()).thenReturn(mThermalServiceMock);
mHandler = new Handler(Looper.getMainLooper());
LocalServices.removeServiceForTest(StatusBarManagerInternal.class);
@@ -1547,12 +1554,52 @@
assertNull(vote);
}
+ @Test
+ public void testSkinTemperature() throws RemoteException {
+ DisplayModeDirector director =
+ createDirectorFromRefreshRateArray(new float[] {60.0f, 90.0f}, 0);
+ director.start(createMockSensorManager());
+
+ ArgumentCaptor<IThermalEventListener> thermalEventListener =
+ ArgumentCaptor.forClass(IThermalEventListener.class);
+
+ verify(mThermalServiceMock).registerThermalEventListenerWithType(
+ thermalEventListener.capture(), eq(Temperature.TYPE_SKIN));
+ final IThermalEventListener listener = thermalEventListener.getValue();
+
+ // Verify that there is no skin temperature vote initially.
+ Vote vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertNull(vote);
+
+ // Set the skin temperature to critical and verify that we added a vote.
+ listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_CRITICAL));
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertVoteForRefreshRateRange(vote, 0f, 60.f);
+
+ // Set the skin temperature to severe and verify that the vote is gone.
+ listener.notifyThrottling(getSkinTemp(Temperature.THROTTLING_SEVERE));
+ vote = director.getVote(DISPLAY_ID, Vote.PRIORITY_SKIN_TEMPERATURE);
+ assertNull(vote);
+ }
+
+ private Temperature getSkinTemp(@Temperature.ThrottlingStatus int status) {
+ return new Temperature(30.0f, Temperature.TYPE_SKIN, "test_skin_temp", status);
+ }
+
private void assertVoteForRefreshRate(Vote vote, float refreshRate) {
assertThat(vote).isNotNull();
final RefreshRateRange expectedRange = new RefreshRateRange(refreshRate, refreshRate);
assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
}
+ private void assertVoteForRefreshRateRange(
+ Vote vote, float refreshRateLow, float refreshRateHigh) {
+ assertThat(vote).isNotNull();
+ final RefreshRateRange expectedRange =
+ new RefreshRateRange(refreshRateLow, refreshRateHigh);
+ assertThat(vote.refreshRateRange).isEqualTo(expectedRange);
+ }
+
public static class FakeDeviceConfig extends FakeDeviceConfigInterface {
@Override
public String getProperty(String namespace, String name) {
@@ -1748,6 +1795,11 @@
return false;
}
+ @Override
+ public IThermalService getThermalService() {
+ return null;
+ }
+
void notifyPeakRefreshRateChanged() {
if (mPeakRefreshRateObserver != null) {
mPeakRefreshRateObserver.dispatchChange(false /*selfChange*/,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
index 71c05b5..ea46eab 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/BuzzBeepBlinkTest.java
@@ -32,6 +32,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
import static org.mockito.Matchers.any;
import static org.mockito.Matchers.anyBoolean;
import static org.mockito.Matchers.anyInt;
@@ -72,6 +73,7 @@
import android.service.notification.NotificationListenerService;
import android.service.notification.StatusBarNotification;
import android.test.suitebuilder.annotation.SmallTest;
+import android.util.Slog;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
import android.view.accessibility.IAccessibilityManager;
@@ -1182,6 +1184,7 @@
when(mAudioManager.getRingerModeInternal()).thenReturn(AudioManager.RINGER_MODE_VIBRATE);
mService.buzzBeepBlinkLocked(r);
+ verifyDelayedVibrate(mService.getVibratorHelper().createFallbackVibration(false));
// quiet update should stop making noise
mService.buzzBeepBlinkLocked(s);
@@ -1564,6 +1567,32 @@
}
@Test
+ public void testRingtoneInsistentBeep_canUpdate() throws Exception {
+ NotificationChannel ringtoneChannel =
+ new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
+ ringtoneChannel.setSound(Uri.fromParts("a", "b", "c"),
+ new AudioAttributes.Builder().setUsage(USAGE_NOTIFICATION_RINGTONE).build());
+ ringtoneChannel.enableVibration(true);
+ NotificationRecord ringtoneNotification = getCallRecord(1, ringtoneChannel, true);
+ mService.addNotification(ringtoneNotification);
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+ verifyBeepLooped();
+ verifyDelayedVibrateLooped();
+ Mockito.reset(mVibrator);
+ Mockito.reset(mRingtonePlayer);
+
+ assertFalse(mService.shouldMuteNotificationLocked(ringtoneNotification));
+ mService.buzzBeepBlinkLocked(ringtoneNotification);
+
+ // beep wasn't reset
+ verifyNeverBeep();
+ verifyNeverVibrate();
+ verify(mRingtonePlayer, never()).stopAsync();
+ verify(mVibrator, never()).cancel();
+ }
+
+ @Test
public void testCannotInterruptRingtoneInsistentBuzz() {
NotificationChannel ringtoneChannel =
new NotificationChannel("ringtone", "", IMPORTANCE_HIGH);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 7bbf3e6..f660af0 100755
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -516,7 +516,7 @@
when(mAssistants.isAdjustmentAllowed(anyString())).thenReturn(true);
- mWorkerHandler = mService.new WorkerHandler(mTestableLooper.getLooper());
+ mWorkerHandler = spy(mService.new WorkerHandler(mTestableLooper.getLooper()));
mService.init(mWorkerHandler, mRankingHandler, mPackageManager, mPackageManagerClient,
mockLightsManager, mListeners, mAssistants, mConditionProviders, mCompanionMgr,
mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager, mGroupHelper, mAm, mAtm,
@@ -2703,6 +2703,42 @@
}
@Test
+ public void testCrossUserSnooze() {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
+ mService.addNotification(r);
+ NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(r2);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(false);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(r.getKey(), 1000, null, mListener);
+
+ verify(mWorkerHandler, never()).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ }
+
+ @Test
+ public void testSameUserSnooze() {
+ NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 10);
+ mService.addNotification(r);
+ NotificationRecord r2 = generateNotificationRecord(mTestNotificationChannel, 0);
+ mService.addNotification(r2);
+
+ mListener = mock(ManagedServices.ManagedServiceInfo.class);
+ mListener.component = new ComponentName(PKG, PKG);
+ when(mListener.enabledAndUserMatches(anyInt())).thenReturn(true);
+ when(mListeners.checkServiceTokenLocked(any())).thenReturn(mListener);
+
+ mService.snoozeNotificationInt(r2.getKey(), 1000, null, mListener);
+
+ verify(mWorkerHandler).post(
+ any(NotificationManagerService.SnoozeNotificationRunnable.class));
+ }
+
+ @Test
public void testSnoozeRunnable_reSnoozeASingleSnoozedNotification() throws Exception {
final NotificationRecord notification = generateNotificationRecord(
mTestNotificationChannel, 1, null, true);
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index bf0ed71..66d1577 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -91,6 +91,7 @@
import android.os.RemoteException;
import android.os.UserHandle;
import android.os.UserManager;
+import android.provider.Settings;
import android.provider.Settings.Global;
import android.provider.Settings.Secure;
import android.service.notification.ConversationChannelWrapper;
@@ -376,27 +377,19 @@
when(mPm.getPackageUidAsUser(eq(packageName), anyInt())).thenReturn(uid);
}
- private static NotificationChannel createNotificationChannel(String id, String name,
- int importance) {
- NotificationChannel channel = new NotificationChannel(id, name, importance);
- channel.setSound(SOUND_URI, Notification.AUDIO_ATTRIBUTES_DEFAULT);
- return channel;
- }
-
@Test
public void testWriteXml_onlyBackupsTargetUser() throws Exception {
// Setup package notifications.
String package0 = "test.package.user0";
int uid0 = 1001;
setUpPackageWithUid(package0, uid0);
- NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+ NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
String package10 = "test.package.user10";
int uid10 = 1001001;
setUpPackageWithUid(package10, uid10);
- NotificationChannel channel10 = createNotificationChannel("id10", "name10",
- IMPORTANCE_HIGH);
+ NotificationChannel channel10 = new NotificationChannel("id10", "name10", IMPORTANCE_HIGH);
assertTrue(mHelper.createNotificationChannel(package10, uid10, channel10, true, false));
ByteArrayOutputStream baos = writeXmlAndPurge(package10, uid10, true, 10);
@@ -421,7 +414,7 @@
String package0 = "test.package.user0";
int uid0 = 1001;
setUpPackageWithUid(package0, uid0);
- NotificationChannel channel0 = createNotificationChannel("id0", "name0", IMPORTANCE_HIGH);
+ NotificationChannel channel0 = new NotificationChannel("id0", "name0", IMPORTANCE_HIGH);
assertTrue(mHelper.createNotificationChannel(package0, uid0, channel0, true, false));
ByteArrayOutputStream baos = writeXmlAndPurge(package0, uid0, true, 0);
@@ -514,8 +507,9 @@
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
NotificationChannel channel1 =
- createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
- NotificationChannel channel2 = createNotificationChannel("id2", "name2", IMPORTANCE_LOW);
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ NotificationChannel channel2 =
+ new NotificationChannel("id2", "name2", IMPORTANCE_LOW);
channel2.setDescription("descriptions for all");
channel2.setSound(SOUND_URI, mAudioAttributes);
channel2.enableLights(true);
@@ -524,7 +518,7 @@
channel2.enableVibration(false);
channel2.setGroup(ncg.getId());
channel2.setLightColor(Color.BLUE);
- NotificationChannel channel3 = createNotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
+ NotificationChannel channel3 = new NotificationChannel("id3", "NAM3", IMPORTANCE_HIGH);
channel3.enableVibration(true);
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
@@ -631,8 +625,7 @@
}
@Test
- public void testRestoreXml_withNonExistentCanonicalizedSoundUri_ignoreChannel()
- throws Exception {
+ public void testRestoreXml_withNonExistentCanonicalizedSoundUri() throws Exception {
Thread.sleep(3000);
doReturn(null)
.when(mTestIContentProvider).canonicalize(any(), eq(CANONICAL_SOUND_URI));
@@ -650,7 +643,7 @@
NotificationChannel actualChannel = mHelper.getNotificationChannel(
PKG_N_MR1, UID_N_MR1, channel.getId(), false);
- assertNull(actualChannel);
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
}
@@ -659,8 +652,7 @@
* handle its restore properly.
*/
@Test
- public void testRestoreXml_withUncanonicalizedNonLocalSoundUri_ignoreChannel()
- throws Exception {
+ public void testRestoreXml_withUncanonicalizedNonLocalSoundUri() throws Exception {
// Not a local uncanonicalized uri, simulating that it fails to exist locally
doReturn(null)
.when(mTestIContentProvider).canonicalize(any(), eq(SOUND_URI));
@@ -679,7 +671,7 @@
backupWithUncanonicalizedSoundUri.getBytes(), true, UserHandle.USER_SYSTEM);
NotificationChannel actualChannel = mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, id, false);
- assertNull(actualChannel);
+ assertEquals(Settings.System.DEFAULT_NOTIFICATION_URI, actualChannel.getSound());
}
@Test
@@ -703,11 +695,11 @@
NotificationChannelGroup ncg = new NotificationChannelGroup("1", "bye");
NotificationChannelGroup ncg2 = new NotificationChannelGroup("2", "hello");
NotificationChannel channel1 =
- createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
NotificationChannel channel2 =
- createNotificationChannel("id2", "name2", IMPORTANCE_HIGH);
+ new NotificationChannel("id2", "name2", IMPORTANCE_HIGH);
NotificationChannel channel3 =
- createNotificationChannel("id3", "name3", IMPORTANCE_LOW);
+ new NotificationChannel("id3", "name3", IMPORTANCE_LOW);
channel3.setGroup(ncg.getId());
mHelper.createNotificationChannelGroup(PKG_N_MR1, UID_N_MR1, ncg, true);
@@ -3062,7 +3054,7 @@
@Test
public void testChannelXml_backupDefaultApp() throws Exception {
NotificationChannel channel1 =
- createNotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
+ new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
mHelper.createNotificationChannel(PKG_O, UID_O, channel1, true, false);
@@ -3343,7 +3335,7 @@
mAppOpsManager, mStatsEventBuilderFactory);
mHelper.createNotificationChannel(
- PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+ PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
assertTrue(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
assertFalse(mHelper.deleteNotificationChannel(PKG_P, UID_P, "id"));
}
@@ -3354,7 +3346,7 @@
mAppOpsManager, mStatsEventBuilderFactory);
mHelper.createNotificationChannel(
- PKG_P, UID_P, createNotificationChannel("id", "id", 2), true, false);
+ PKG_P, UID_P, new NotificationChannel("id", "id", 2), true, false);
mHelper.deleteNotificationChannel(PKG_P, UID_P, "id");
NotificationChannel nc1 = mHelper.getNotificationChannel(PKG_P, UID_P, "id", true);
assertTrue(DateUtils.isToday(nc1.getDeletedTimeMs()));
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 8ca14bc..b95d56b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -173,7 +173,10 @@
@Override
public void onFixedRotationFinished(int displayId) {}
};
- mAtm.mWindowManager.registerDisplayWindowListener(listener);
+ int[] displayIds = mAtm.mWindowManager.registerDisplayWindowListener(listener);
+ for (int i = 0; i < displayIds.length; i++) {
+ added.add(displayIds[i]);
+ }
// Check that existing displays call added
assertEquals(mRootWindowContainer.getChildCount(), added.size());
assertEquals(0, changed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
index 26a6882..a34586b 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskSupervisorTests.java
@@ -30,6 +30,7 @@
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.ArgumentMatchers.anyInt;
@@ -40,8 +41,10 @@
import android.app.WaitResult;
import android.content.ComponentName;
+import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.os.ConditionVariable;
+import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
import android.view.Display;
@@ -190,6 +193,24 @@
verify(taskChangeNotifier, never()).notifyActivityDismissingDockedRootTask();
}
+ /** Ensures that the calling package name passed to client complies with package visibility. */
+ @Test
+ public void testFilteredReferred() {
+ final ActivityRecord activity = new ActivityBuilder(mAtm)
+ .setLaunchedFromPackage("other.package").setCreateTask(true).build();
+ assertNotNull(activity.launchedFromPackage);
+ try {
+ mSupervisor.realStartActivityLocked(activity, activity.app, false /* andResume */,
+ false /* checkConfig */);
+ } catch (RemoteException ignored) {
+ }
+ verify(activity).getFilteredReferrer(eq(activity.launchedFromPackage));
+
+ activity.deliverNewIntentLocked(ActivityBuilder.DEFAULT_FAKE_UID,
+ new Intent(), null /* intentGrants */, "other.package2");
+ verify(activity).getFilteredReferrer(eq("other.package2"));
+ }
+
/**
* Ensures that notify focus task changes.
*/
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
index a165e1c..53bae41 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java
@@ -26,15 +26,19 @@
import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
+import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
import static android.view.WindowManager.TRANSIT_OPEN;
import static android.view.WindowManager.TRANSIT_TO_FRONT;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.doCallRealMethod;
+import static org.mockito.Mockito.verify;
import android.os.Binder;
import android.os.IBinder;
@@ -47,6 +51,8 @@
import android.view.RemoteAnimationDefinition;
import android.view.RemoteAnimationTarget;
import android.view.WindowManager;
+import android.window.ITaskFragmentOrganizer;
+import android.window.TaskFragmentOrganizer;
import androidx.test.filters.SmallTest;
@@ -737,4 +743,38 @@
mAppTransitionController.getRemoteAnimationOverride(
activity, TRANSIT_OLD_ACTIVITY_OPEN, new ArraySet<Integer>()));
}
+
+ @Test
+ public void testGetRemoteAnimationOverrideTaskFragmentOrganizer() {
+ // TaskFragmentOrganizer registers remote animation.
+ final TaskFragmentOrganizer organizer = new TaskFragmentOrganizer(Runnable::run);
+ final ITaskFragmentOrganizer iOrganizer =
+ ITaskFragmentOrganizer.Stub.asInterface(organizer.getOrganizerToken().asBinder());
+ final RemoteAnimationDefinition definition = new RemoteAnimationDefinition();
+ final RemoteAnimationAdapter adapter = new RemoteAnimationAdapter(
+ new TestRemoteAnimationRunner(), 10, 1);
+ definition.addRemoteAnimation(TRANSIT_OLD_TASK_FRAGMENT_CHANGE, adapter);
+ mAtm.mTaskFragmentOrganizerController.registerOrganizer(iOrganizer);
+ mAtm.mTaskFragmentOrganizerController.registerRemoteAnimations(iOrganizer, definition);
+
+ // Create a TaskFragment with embedded activity.
+ final TaskFragment taskFragment = new TaskFragmentBuilder(mAtm)
+ .setParentTask(createTask(mDisplayContent))
+ .createActivityCount(1)
+ .setOrganizer(organizer)
+ .build();
+ final ActivityRecord activity = taskFragment.getTopMostActivity();
+ activity.allDrawn = true;
+ spyOn(mDisplayContent.mAppTransition);
+
+ // Prepare a transition for TaskFragment.
+ mDisplayContent.mAppTransition.prepareAppTransition(TRANSIT_CHANGE, 0);
+ mDisplayContent.mOpeningApps.add(activity);
+ mDisplayContent.mChangingContainers.add(taskFragment);
+ mDisplayContent.mAppTransitionController.handleAppTransitionReady();
+
+ // Check if the transition has been overridden.
+ verify(mDisplayContent.mAppTransition)
+ .overridePendingAppTransitionRemote(adapter, false /* sync */);
+ }
}
\ No newline at end of file
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 14dc33e..4ee0c60 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -25,6 +25,7 @@
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_PORTRAIT;
import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.hardware.display.DisplayManager.VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR;
import static android.os.Build.VERSION_CODES.P;
import static android.os.Build.VERSION_CODES.Q;
import static android.view.Display.DEFAULT_DISPLAY;
@@ -111,6 +112,7 @@
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Region;
+import android.hardware.display.VirtualDisplay;
import android.metrics.LogMaker;
import android.os.Binder;
import android.os.IBinder;
@@ -2292,7 +2294,7 @@
float yScale = 2f;
Rect displayAreaBounds = new Rect(0, 0, Math.round(surfaceSize.x * xScale),
Math.round(surfaceSize.y * yScale));
- virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds);
+ virtualDisplay.updateMirroredSurface(mTransaction, displayAreaBounds, surfaceSize);
// THEN content in the captured DisplayArea is scaled to fit the surface size.
verify(mTransaction, atLeastOnce()).setMatrix(mirroredSurface, 1.0f / yScale, 0, 0,
@@ -2305,6 +2307,72 @@
mockSession.finishMocking();
}
+ @Test
+ public void testVirtualDisplayContent_withoutSurface() {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SurfaceControl.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // mirror.
+ setUpDefaultTaskDisplayAreaWindowToken();
+
+ // GIVEN SurfaceControl can successfully mirror the provided surface.
+ Point surfaceSize = new Point(
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+ surfaceControlMirrors(surfaceSize);
+
+ // GIVEN a new VirtualDisplay with an associated surface.
+ final VirtualDisplay display = createVirtualDisplay(surfaceSize, null /* surface */);
+ final int displayId = display.getDisplay().getDisplayId();
+ mWm.mRoot.onDisplayAdded(displayId);
+
+ // WHEN getting the DisplayContent for the new virtual display.
+ DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
+
+ // THEN mirroring is not started, since a null surface indicates the VirtualDisplay is off.
+ assertThat(actualDC.mTokenToMirror).isNull();
+
+ display.release();
+ mockSession.finishMocking();
+ }
+
+ @Test
+ public void testVirtualDisplayContent_withSurface() {
+ MockitoSession mockSession = mockitoSession()
+ .initMocks(this)
+ .spyStatic(SurfaceControl.class)
+ .strictness(Strictness.LENIENT)
+ .startMocking();
+
+ // GIVEN MediaProjection has already initialized the WindowToken of the DisplayArea to
+ // mirror.
+ final IBinder tokenToMirror = setUpDefaultTaskDisplayAreaWindowToken();
+
+ // GIVEN SurfaceControl can successfully mirror the provided surface.
+ Point surfaceSize = new Point(
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().width(),
+ mDefaultDisplay.getDefaultTaskDisplayArea().getBounds().height());
+ surfaceControlMirrors(surfaceSize);
+
+ // GIVEN a new VirtualDisplay with an associated surface.
+ final VirtualDisplay display = createVirtualDisplay(surfaceSize, new Surface());
+ final int displayId = display.getDisplay().getDisplayId();
+ mWm.mRoot.onDisplayAdded(displayId);
+
+ // WHEN getting the DisplayContent for the new virtual display.
+ DisplayContent actualDC = mWm.mRoot.getDisplayContent(displayId);
+
+ // THEN mirroring is initiated for the default display's DisplayArea.
+ assertThat(actualDC.mTokenToMirror).isEqualTo(tokenToMirror);
+
+ display.release();
+ mockSession.finishMocking();
+ }
+
private class TestToken extends Binder {
}
@@ -2342,6 +2410,11 @@
return mirroredSurface;
}
+ private VirtualDisplay createVirtualDisplay(Point size, Surface surface) {
+ return mWm.mDisplayManager.createVirtualDisplay("VirtualDisplay", size.x, size.y,
+ DisplayMetrics.DENSITY_140, surface, VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR);
+ }
+
private void removeRootTaskTests(Runnable runnable) {
final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea();
final Task rootTask1 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN,
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index f2eb709..4069f0f 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -1008,33 +1008,31 @@
@Test
public void testLockAllProfileTasks() {
- // Make an activity visible with the user id set to 0
- final Task task = new TaskBuilder(mSupervisor).setCreateActivity(true).build();
- final int taskId = task.mTaskId;
- final ActivityRecord activity = task.getTopMostActivity();
+ final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID;
+ final int profileUserId = UserHandle.getUserId(profileUid);
+ // Create an activity belonging to the profile user.
+ final ActivityRecord activity = new ActivityBuilder(mAtm).setCreateTask(true)
+ .setUid(profileUid).build();
+ final Task task = activity.getTask();
- // Create another activity on top and the user id is 1
- final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task)
- .setUid(UserHandle.PER_USER_RANGE + 1).build();
- doReturn(true).when(topActivity).okToShowLocked();
+ // Create another activity belonging to current user on top.
+ final ActivityRecord topActivity = new ActivityBuilder(mAtm).setTask(task).build();
topActivity.intent.setAction(Intent.ACTION_MAIN);
// Make sure the listeners will be notified for putting the task to locked state
TaskChangeNotificationController controller = mAtm.getTaskChangeNotificationController();
spyOn(controller);
- mWm.mRoot.lockAllProfileTasks(0);
- verify(controller).notifyTaskProfileLocked(eq(taskId), eq(0));
+ mWm.mRoot.lockAllProfileTasks(profileUserId);
+ verify(controller).notifyTaskProfileLocked(eq(task.mTaskId), eq(profileUserId));
// Create the work lock activity on top of the task
- final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task)
- .setUid(UserHandle.PER_USER_RANGE + 1).build();
- doReturn(true).when(workLockActivity).okToShowLocked();
+ final ActivityRecord workLockActivity = new ActivityBuilder(mAtm).setTask(task).build();
workLockActivity.intent.setAction(ACTION_CONFIRM_DEVICE_CREDENTIAL_WITH_USER);
doReturn(workLockActivity.mActivityComponent).when(mAtm).getSysUiServiceComponentLocked();
// Make sure the listener won't be notified again.
clearInvocations(controller);
- mWm.mRoot.lockAllProfileTasks(0);
+ mWm.mRoot.lockAllProfileTasks(profileUserId);
verify(controller, never()).notifyTaskProfileLocked(anyInt(), anyInt());
}
diff --git a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
index 8e7ba4bc..5bc45d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SystemServicesTestRule.java
@@ -271,7 +271,6 @@
doNothing().when(amInternal).cleanUpServices(anyInt(), any(), any());
doReturn(UserHandle.USER_SYSTEM).when(amInternal).getCurrentUserId();
doReturn(TEST_USER_PROFILE_IDS).when(amInternal).getCurrentProfileIds();
- doReturn(true).when(amInternal).isCurrentProfile(anyInt());
doReturn(true).when(amInternal).isUserRunning(anyInt(), anyInt());
doReturn(true).when(amInternal).hasStartedUserState(anyInt());
doReturn(false).when(amInternal).shouldConfirmCredentials(anyInt());
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
index 5c79f5c..98c1eabe 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentOrganizerControllerTest.java
@@ -21,6 +21,7 @@
import static com.android.server.wm.testing.Assert.assertThrows;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNull;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
@@ -36,6 +37,7 @@
import android.os.IBinder;
import android.os.RemoteException;
import android.platform.test.annotations.Presubmit;
+import android.view.RemoteAnimationDefinition;
import android.view.SurfaceControl;
import android.window.ITaskFragmentOrganizer;
import android.window.TaskFragmentCreationParams;
@@ -70,6 +72,7 @@
private IBinder mFragmentToken;
private WindowContainerTransaction mTransaction;
private WindowContainerToken mFragmentWindowToken;
+ private RemoteAnimationDefinition mDefinition;
@Before
public void setup() {
@@ -83,6 +86,7 @@
new TaskFragment(mAtm, mFragmentToken, true /* createdByOrganizer */);
mTransaction = new WindowContainerTransaction();
mFragmentWindowToken = mTaskFragment.mRemoteToken.toWindowContainerToken();
+ mDefinition = new RemoteAnimationDefinition();
spyOn(mController);
spyOn(mOrganizer);
@@ -208,6 +212,18 @@
}
@Test
+ public void testRegisterRemoteAnimations() {
+ mController.registerOrganizer(mIOrganizer);
+ mController.registerRemoteAnimations(mIOrganizer, mDefinition);
+
+ assertEquals(mDefinition, mController.getRemoteAnimationDefinition(mIOrganizer));
+
+ mController.unregisterRemoteAnimations(mIOrganizer);
+
+ assertNull(mController.getRemoteAnimationDefinition(mIOrganizer));
+ }
+
+ @Test
public void testWindowContainerTransaction_setTaskFragmentOrganizer() {
mOrganizer.applyTransaction(mTransaction);
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
index e7ef6ae..454ecd7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java
@@ -67,6 +67,7 @@
import android.annotation.IntDef;
import android.annotation.NonNull;
+import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityOptions;
import android.app.IApplicationThread;
@@ -100,6 +101,7 @@
import android.view.WindowManager.DisplayImePolicy;
import android.window.ITransitionPlayer;
import android.window.StartingWindowInfo;
+import android.window.TaskFragmentOrganizer;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -878,6 +880,7 @@
private int mConfigChanges;
private int mLaunchedFromPid;
private int mLaunchedFromUid;
+ private String mLaunchedFromPackage;
private WindowProcessController mWpc;
private Bundle mIntentExtras;
private boolean mOnTop = false;
@@ -988,6 +991,11 @@
return this;
}
+ ActivityBuilder setLaunchedFromPackage(String packageName) {
+ mLaunchedFromPackage = packageName;
+ return this;
+ }
+
ActivityBuilder setUseProcess(WindowProcessController wpc) {
mWpc = wpc;
return this;
@@ -1077,6 +1085,7 @@
final ActivityRecord activity = new ActivityRecord.Builder(mService)
.setLaunchedFromPid(mLaunchedFromPid)
.setLaunchedFromUid(mLaunchedFromUid)
+ .setLaunchedFromPackage(mLaunchedFromPackage)
.setIntent(intent)
.setActivityInfo(aInfo)
.setActivityOptions(options)
@@ -1128,6 +1137,8 @@
private boolean mCreateParentTask;
private boolean mCreateEmbeddedTask;
private int mCreateActivityCount = 0;
+ @Nullable
+ private TaskFragmentOrganizer mOrganizer;
TaskFragmentBuilder(ActivityTaskManagerService service) {
mAtm = service;
@@ -1154,11 +1165,16 @@
return this;
}
+ TaskFragmentBuilder setOrganizer(@Nullable TaskFragmentOrganizer organizer) {
+ mOrganizer = organizer;
+ return this;
+ }
+
TaskFragment build() {
SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock);
final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */,
- false /* createdByOrganizer */);
+ mOrganizer != null);
if (mParentTask == null && mCreateParentTask) {
mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build();
}
@@ -1176,6 +1192,10 @@
taskFragment.addChild(activity);
mCreateActivityCount--;
}
+ if (mOrganizer != null) {
+ taskFragment.setTaskFragmentOrganizer(
+ mOrganizer.getOrganizerToken(), 10000 /* pid */);
+ }
return taskFragment;
}
}
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/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
index 7b6ccd3..49ea9df 100644
--- a/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
+++ b/services/usb/java/com/android/server/usb/UsbUserPermissionManager.java
@@ -689,8 +689,10 @@
try {
ApplicationInfo aInfo = mContext.getPackageManager().getApplicationInfo(packageName, 0);
if (aInfo.uid != uid) {
- throw new IllegalArgumentException("package " + packageName
+ Slog.w(TAG, "package " + packageName
+ " does not match caller's uid " + uid);
+ throw new IllegalArgumentException("package " + packageName
+ + " not found");
}
} catch (PackageManager.NameNotFoundException e) {
throw new IllegalArgumentException("package " + packageName + " not found");
diff --git a/telecomm/java/android/telecom/Connection.java b/telecomm/java/android/telecom/Connection.java
index 759afd7..f2f1645 100644
--- a/telecomm/java/android/telecom/Connection.java
+++ b/telecomm/java/android/telecom/Connection.java
@@ -775,6 +775,21 @@
"android.telecom.extra.REMOTE_PHONE_ACCOUNT_HANDLE";
/**
+ * The Telecom call ID of the conference an existing connection should be added to. This is
+ * required when {@link com.android.services.telephony.TelephonyConnectionService} adds a
+ * {@link Conference} to Telecom using the
+ * {@link ConnectionService#addExistingConnection(PhoneAccountHandle, Connection, Conference)}
+ * API. That API specifies a parent conference associated with the new existing connection
+ * being added, and there is no equivalent as part of the {@link RemoteConnectionService} API.
+ * This extra key is used to stack the ID of the conference to which the existing connection
+ * will be added so that Telecom can link it up correctly when the {@link RemoteConference}
+ * is added to Telecom by the connection manager.
+ * @hide
+ */
+ public static final String EXTRA_ADD_TO_CONFERENCE_ID =
+ "android.telecom.extra.ADD_TO_CONFERENCE_ID";
+
+ /**
* Extra key set from a {@link ConnectionService} when using the remote connection APIs
* (e.g. {@link RemoteConnectionService#createRemoteConnection(PhoneAccountHandle,
* ConnectionRequest, boolean)}) to create a remote connection. Provides the receiving
diff --git a/telecomm/java/android/telecom/Phone.java b/telecomm/java/android/telecom/Phone.java
index a427ed61..bc0a146 100644
--- a/telecomm/java/android/telecom/Phone.java
+++ b/telecomm/java/android/telecom/Phone.java
@@ -23,6 +23,8 @@
import android.os.Bundle;
import android.util.ArrayMap;
+import com.android.internal.annotations.GuardedBy;
+
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -115,6 +117,7 @@
public static final int SDK_VERSION_R = 30;
// A Map allows us to track each Call by its Telecom-specified call ID
+ @GuardedBy("mLock")
private final Map<String, Call> mCallByTelecomCallId = new ArrayMap<>();
// A List allows us to keep the Calls in a stable iteration order so that casually developed
@@ -139,6 +142,8 @@
*/
private final int mTargetSdkVersion;
+ private final Object mLock = new Object();
+
Phone(InCallAdapter adapter, String callingPackage, int targetSdkVersion) {
mInCallAdapter = adapter;
mCallingPackage = callingPackage;
@@ -152,12 +157,16 @@
return;
}
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call == null) {
call = new Call(this, parcelableCall.getId(), mInCallAdapter,
parcelableCall.getState(), mCallingPackage, mTargetSdkVersion);
- mCallByTelecomCallId.put(parcelableCall.getId(), call);
- mCalls.add(call);
+
+ synchronized (mLock) {
+ mCallByTelecomCallId.put(parcelableCall.getId(), call);
+ mCalls.add(call);
+ }
+
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
fireCallAdded(call);
@@ -169,8 +178,10 @@
}
final void internalRemoveCall(Call call) {
- mCallByTelecomCallId.remove(call.internalGetCallId());
- mCalls.remove(call);
+ synchronized (mLock) {
+ mCallByTelecomCallId.remove(call.internalGetCallId());
+ mCalls.remove(call);
+ }
InCallService.VideoCall videoCall = call.getVideoCall();
if (videoCall != null) {
@@ -183,14 +194,14 @@
if (mTargetSdkVersion < SDK_VERSION_R
&& parcelableCall.getState() == Call.STATE_AUDIO_PROCESSING) {
Log.i(this, "removing audio processing call during update for sdk compatibility");
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call != null) {
internalRemoveCall(call);
}
return;
}
- Call call = mCallByTelecomCallId.get(parcelableCall.getId());
+ Call call = getCallById(parcelableCall.getId());
if (call != null) {
checkCallTree(parcelableCall);
call.internalUpdate(parcelableCall, mCallByTelecomCallId);
@@ -207,8 +218,14 @@
}
}
+ Call getCallById(String callId) {
+ synchronized (mLock) {
+ return mCallByTelecomCallId.get(callId);
+ }
+ }
+
final void internalSetPostDialWait(String telecomId, String remaining) {
- Call call = mCallByTelecomCallId.get(telecomId);
+ Call call = getCallById(telecomId);
if (call != null) {
call.internalSetPostDialWait(remaining);
}
@@ -222,7 +239,7 @@
}
final Call internalGetCallByTelecomId(String telecomId) {
- return mCallByTelecomCallId.get(telecomId);
+ return getCallById(telecomId);
}
final void internalBringToForeground(boolean showDialpad) {
@@ -241,35 +258,35 @@
}
final void internalOnConnectionEvent(String telecomId, String event, Bundle extras) {
- Call call = mCallByTelecomCallId.get(telecomId);
+ Call call = getCallById(telecomId);
if (call != null) {
call.internalOnConnectionEvent(event, extras);
}
}
final void internalOnRttUpgradeRequest(String callId, int requestId) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnRttUpgradeRequest(requestId);
}
}
final void internalOnRttInitiationFailure(String callId, int reason) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnRttInitiationFailure(reason);
}
}
final void internalOnHandoverFailed(String callId, int error) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnHandoverFailed(error);
}
}
final void internalOnHandoverComplete(String callId) {
- Call call = mCallByTelecomCallId.get(callId);
+ Call call = getCallById(callId);
if (call != null) {
call.internalOnHandoverComplete();
}
diff --git a/telecomm/java/android/telecom/RemoteConnectionService.java b/telecomm/java/android/telecom/RemoteConnectionService.java
index bf6a6ef7..efe35d2 100644
--- a/telecomm/java/android/telecom/RemoteConnectionService.java
+++ b/telecomm/java/android/telecom/RemoteConnectionService.java
@@ -239,13 +239,9 @@
conference.addConnection(c);
}
}
- if (conference.getConnections().size() == 0) {
- // A conference was created, but none of its connections are ones that have been
- // created by, and therefore being tracked by, this remote connection service. It
- // is of no interest to us.
- Log.d(this, "addConferenceCall - skipping");
- return;
- }
+ // We used to skip adding empty conferences; however in the world of IMS conference
+ // calls we need to add them to the remote connection service because they will always
+ // start with no participants.
conference.setState(parcel.getState());
conference.setConnectionCapabilities(parcel.getConnectionCapabilities());
@@ -379,6 +375,8 @@
@Override
public void addExistingConnection(String callId, ParcelableConnection connection,
Session.Info sessionInfo) {
+ Log.i(RemoteConnectionService.this, "addExistingConnection: callId=%s, conn=%s", callId,
+ connection);
String callingPackage = mOurConnectionServiceImpl.getApplicationContext().
getOpPackageName();
int callingTargetSdkVersion = mOurConnectionServiceImpl.getApplicationInfo()
@@ -390,6 +388,20 @@
Bundle newExtras = new Bundle();
newExtras.putParcelable(Connection.EXTRA_REMOTE_PHONE_ACCOUNT_HANDLE,
connection.getPhoneAccount());
+ if (connection.getParentCallId() != null) {
+ RemoteConference parentConf = mConferenceById.get(connection.getParentCallId());
+ // If there is a parent being set, we need to stash the conference ID here.
+ // Telephony can add an existing connection while specifying a parent conference.
+ // There is no equivalent version of that operation as part of the remote connection
+ // API, so we will stash the pre-defined parent's ID in the extras. When the
+ // connectionmanager copies over the extras from the remote connection to the
+ // actual one, it'll get passed to Telecom so that it can make the association.
+ if (parentConf != null) {
+ newExtras.putString(Connection.EXTRA_ADD_TO_CONFERENCE_ID, parentConf.getId());
+ Log.i(this, "addExistingConnection: stash parent of %s as %s",
+ connection.getParentCallId(), parentConf.getId());
+ }
+ }
remoteConnection.putExtras(newExtras);
mConnectionById.put(callId, remoteConnection);
remoteConnection.registerCallback(new RemoteConnection.Callback() {
diff --git a/telephony/java/android/telephony/AvailableNetworkInfo.java b/telephony/java/android/telephony/AvailableNetworkInfo.java
index a1c5bbe..ae597e0 100644
--- a/telephony/java/android/telephony/AvailableNetworkInfo.java
+++ b/telephony/java/android/telephony/AvailableNetworkInfo.java
@@ -19,6 +19,7 @@
import android.annotation.NonNull;
import android.os.Parcel;
import android.os.Parcelable;
+import android.telephony.RadioAccessSpecifier;
import java.util.ArrayList;
import java.util.Arrays;
@@ -76,13 +77,28 @@
* Opportunistic network service will use these bands to scan.
*
* When no specific bands are specified (empty array or null) CBRS band
- * {@link AccessNetworkConstants.EutranBand.BAND_48} will be used for network scan.
+ * {@link AccessNetworkConstants.EutranBand.BAND_48
+ * } will be used for network scan.
*
* See {@link AccessNetworkConstants} for details.
+ *
+ * @deprecated use {@link #mRadioAccessSpecifiers} instead
*/
+ @Deprecated
private ArrayList<Integer> mBands;
/**
+ * Returns a list of {@link RadioAccessSpecifier} associated with the available network.
+ * Opportunistic network service will use this to determine which bands to scan for.
+ *
+ * If this entry is left empty, {@link RadioAcccessSpecifier}s with {@link AccessNetworkType}s
+ * of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
+ * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
+ * by Opportunistic network service.
+ */
+ private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers;
+
+ /**
* Return subscription Id of the available network.
* This value must be one of the entry retrieved from
* {@link SubscriptionManager#getOpportunisticSubscriptions}
@@ -129,6 +145,22 @@
return (List<Integer>) mBands.clone();
}
+ /**
+ * Returns a list of {@link RadioAccessSpecifier} associated with the available network.
+ * Opportunistic network service will use this to determine which bands to scan for.
+ *
+ * the returned value is one of {@link AccessNetworkConstants.AccessNetworkType}. When no
+ * specific access network type is specified, {@link RadioAccessSpecifier}s with {@link
+ * AccessNetworkType}s of {@link AccessNetworkConstants.AccessNetworkType.EUTRAN} and {@link
+ * AccessNetworkConstants.AccessNetworkType.NGRAN} with bands 48 and 71 on each will be assumed
+ * by Opportunistic network service.
+ * @return the access network type associated with the available network.
+ * @hide
+ */
+ public List<RadioAccessSpecifier> getRadioAccessSpecifiers() {
+ return (List<RadioAccessSpecifier>) mRadioAccessSpecifiers.clone();
+ }
+
@Override
public int describeContents() {
return 0;
@@ -140,6 +172,7 @@
dest.writeInt(mPriority);
dest.writeStringList(mMccMncs);
dest.writeList(mBands);
+ dest.writeList(mRadioAccessSpecifiers);
}
private AvailableNetworkInfo(Parcel in) {
@@ -149,14 +182,25 @@
in.readStringList(mMccMncs);
mBands = new ArrayList<>();
in.readList(mBands, Integer.class.getClassLoader());
+ mRadioAccessSpecifiers = new ArrayList<>();
+ in.readList(mRadioAccessSpecifiers, RadioAccessSpecifier.class.getClassLoader());
}
public AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
@NonNull List<Integer> bands) {
+ this(subId, priority, mccMncs, bands,
+ new ArrayList<RadioAccessSpecifier>());
+ }
+
+ /** @hide */
+ private AvailableNetworkInfo(int subId, int priority, @NonNull List<String> mccMncs,
+ @NonNull List<Integer> bands, @NonNull List<RadioAccessSpecifier>
+ radioAccessSpecifiers) {
mSubId = subId;
mPriority = priority;
mMccMncs = new ArrayList<String>(mccMncs);
mBands = new ArrayList<Integer>(bands);
+ mRadioAccessSpecifiers = new ArrayList<RadioAccessSpecifier>(radioAccessSpecifiers);
}
@Override
@@ -177,12 +221,13 @@
&& mPriority == ani.mPriority
&& (((mMccMncs != null)
&& mMccMncs.equals(ani.mMccMncs)))
- && mBands.equals(ani.mBands));
+ && mBands.equals(ani.mBands))
+ && mRadioAccessSpecifiers.equals(ani.getRadioAccessSpecifiers());
}
@Override
public int hashCode() {
- return Objects.hash(mSubId, mPriority, mMccMncs, mBands);
+ return Objects.hash(mSubId, mPriority, mMccMncs, mBands, mRadioAccessSpecifiers);
}
public static final @android.annotation.NonNull Parcelable.Creator<AvailableNetworkInfo> CREATOR =
@@ -204,6 +249,72 @@
+ " mSubId: " + mSubId
+ " mPriority: " + mPriority
+ " mMccMncs: " + Arrays.toString(mMccMncs.toArray())
- + " mBands: " + Arrays.toString(mBands.toArray()));
+ + " mBands: " + Arrays.toString(mBands.toArray())
+ + " mRadioAccessSpecifiers: " + Arrays.toString(mRadioAccessSpecifiers.toArray()));
+ }
+
+ /**
+ * Provides a convenient way to set the fields of a {@link AvailableNetworkInfo} when
+ * creating a new instance.
+ *
+ * <p>The example below shows how you might create a new {@code AvailableNetworkInfo}:
+ *
+ * <pre><code>
+ *
+ * AvailableNetworkInfo aNI = new AvailableNetworkInfo.Builder()
+ * .setSubId(1)
+ * .setPriority(AvailableNetworkInfo.PRIORITY_MED)
+ * .build();
+ * </code></pre>
+ *
+ * @hide
+ */
+ public static final class Builder {
+ private int mSubId = Integer.MIN_VALUE;
+ private int mPriority = AvailableNetworkInfo.PRIORITY_LOW;
+ private ArrayList<String> mMccMncs = new ArrayList<>();
+ private ArrayList<Integer> mBands = new ArrayList<>();
+ private ArrayList<RadioAccessSpecifier> mRadioAccessSpecifiers = new ArrayList<>();
+
+ public @NonNull Builder setSubId(int subId) {
+ mSubId = subId;
+ return this;
+ }
+
+ public @NonNull Builder setPriority(int priority) {
+ if (priority > AvailableNetworkInfo.PRIORITY_LOW
+ || priority < AvailableNetworkInfo.PRIORITY_HIGH) {
+ throw new IllegalArgumentException("A valid priority must be set");
+ }
+ mPriority = priority;
+ return this;
+ }
+
+ public @NonNull Builder setMccMncs(@NonNull ArrayList<String> mccMncs) {
+ Objects.requireNonNull(mccMncs, "A non-null ArrayList of mccmncs must be set. An empty "
+ + "list is still accepted. Please read documentation in "
+ + "AvailableNetworkService to see consequences of an empty Arraylist.");
+ mMccMncs = mccMncs;
+ return this;
+ }
+
+ public @NonNull Builder setRadioAccessSpecifiers(
+ @NonNull ArrayList<RadioAccessSpecifier> radioAccessSpecifiers) {
+ Objects.requireNonNull(radioAccessSpecifiers, "A non-null ArrayList of "
+ + "RadioAccessSpecifiers must be set. An empty list is still accepted. Please "
+ + "read documentation in AvailableNetworkService to see consequences of an "
+ + "empty Arraylist.");
+ mRadioAccessSpecifiers = radioAccessSpecifiers;
+ return this;
+ }
+
+ public @NonNull AvailableNetworkInfo build() {
+ if (mSubId == Integer.MIN_VALUE) {
+ throw new IllegalArgumentException("A valid subId must be set");
+ }
+
+ return new AvailableNetworkInfo(mSubId, mPriority, mMccMncs, mBands,
+ mRadioAccessSpecifiers);
+ }
}
}
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 72ad23b..68ef754 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -3751,6 +3751,109 @@
"opportunistic_network_max_backoff_time_long";
/**
+ * Controls SS-RSRP threshold in dBm at which 5G opportunistic network will be considered good
+ * enough for internet data.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT =
+ "opportunistic_network_entry_threshold_ss_rsrp_int";
+
+ /**
+ * Controls SS-RSRQ threshold in dB at which 5G opportunistic network will be considered good
+ * enough for internet data.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE =
+ "opportunistic_network_entry_threshold_ss_rsrq_double";
+
+ /**
+ * Controls SS-RSRP threshold in dBm below which 5G opportunistic network available will not
+ * be considered good enough for internet data.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT =
+ "opportunistic_network_exit_threshold_ss_rsrp_int";
+
+ /**
+ * Controls SS-RSRQ threshold in dB below which 5G opportunistic network available will not
+ * be considered good enough for internet data.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE =
+ "opportunistic_network_exit_threshold_ss_rsrq_double";
+
+ /**
+ * Controls back off time in milliseconds for switching back to
+ * 5G opportunistic subscription. This time will be added to
+ * {@link CarrierConfigManager#KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG} to
+ * determine hysteresis time if there is ping pong situation
+ * (determined by system app or 1st party app) between primary and 5G opportunistic
+ * subscription. Ping ping situation is defined in
+ * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG.
+ * If ping pong situation continuous #KEY_OPPORTUNISTIC_5G_NETWORK_BACKOFF_TIME_LONG
+ * will be added to previously determined hysteresis time.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG =
+ "opportunistic_network_5g_backoff_time_long";
+
+ /**
+ * Controls the max back off time in milliseconds for switching back to
+ * 5G opportunistic subscription.
+ * This time will be the max hysteresis that can be determined irrespective of there is
+ * continuous ping pong situation or not as described in
+ * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG and
+ * #KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG =
+ "opportunistic_network_5g_max_backoff_time_long";
+
+ /**
+ * Controls the ping pong determination of 5G opportunistic network.
+ * If opportunistic network is determined as out of service or below
+ * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT or
+ * #KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_INT within
+ * #KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG of switching to opportunistic network,
+ * it will be determined as ping pong situation by system app or 1st party app.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG =
+ "opportunistic_network_5g_ping_pong_time_long";
+
+ /**
+ * Controls hysteresis time in milliseconds for which will be waited before switching
+ * data to a 5G opportunistic network.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG =
+ "opportunistic_network_5g_data_switch_hysteresis_time_long";
+
+ /**
+ * Controls hysteresis time in milliseconds for which will be waited before switching from
+ * 5G opportunistic network to primary network.
+ *
+ * @hide
+ */
+ public static final String KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG =
+ "opportunistic_network_5g_data_switch_exit_hysteresis_time_long";
+ /**
+ * Controls whether 4G opportunistic networks should be scanned for possible data switch.
+ *
+ * @hide
+ */
+ public static final String KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL =
+ "enabled_4g_opportunistic_network_scan_bool";
+
+ /**
* Indicates zero or more emergency number prefix(es), because some carrier requires
* if users dial an emergency number address with a specific prefix, the combination of the
* prefix and the address is also a valid emergency number to dial. For example, an emergency
@@ -5058,6 +5161,16 @@
"display_no_data_notification_on_permanent_failure_bool";
/**
+ * Boolean indicating if the VoNR setting is visible in the Call Settings menu.
+ * If true, the VoNR setting menu will be visible. If false, the menu will be gone.
+ *
+ * Disabled by default.
+ *
+ * @hide
+ */
+ public static final String KEY_VONR_SETTING_VISIBILITY_BOOL = "vonr_setting_visibility_bool";
+
+ /**
* Determine whether unthrottle data retry when tracking area code (TAC/LAC) from cell changes
*
* @hide
@@ -5581,7 +5694,25 @@
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_BACKOFF_TIME_LONG, 10000);
/* Default value is 60 seconds. */
sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_MAX_BACKOFF_TIME_LONG, 60000);
- sDefaults.putAll(ImsServiceEntitlement.getDefaults());
+ /* Default value is -111 dBm. */
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRP_INT, -111);
+ /* Default value is -18.5 dB. */
+ sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_ENTRY_THRESHOLD_SS_RSRQ_DOUBLE, -18.5);
+ /* Default value is -120 dBm. */
+ sDefaults.putInt(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRP_INT, -120);
+ /* Default value is -18.5 dB. */
+ sDefaults.putDouble(KEY_OPPORTUNISTIC_NETWORK_EXIT_THRESHOLD_SS_RSRQ_DOUBLE, -18.5);
+ /* Default value is 10 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_BACKOFF_TIME_LONG, 10000);
+ /* Default value is 60 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_MAX_BACKOFF_TIME_LONG, 60000);
+ /* Default value is 60 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_PING_PONG_TIME_LONG, 60000);
+ /* Default value is 2 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_HYSTERESIS_TIME_LONG, 2000);
+ /* Default value is 2 seconds. */
+ sDefaults.putLong(KEY_OPPORTUNISTIC_NETWORK_5G_DATA_SWITCH_EXIT_HYSTERESIS_TIME_LONG, 2000);
+ sDefaults.putBoolean(KEY_ENABLE_4G_OPPORTUNISTIC_NETWORK_SCAN_BOOL, true);
sDefaults.putAll(Gps.getDefaults());
sDefaults.putIntArray(KEY_CDMA_ENHANCED_ROAMING_INDICATOR_FOR_HOME_NETWORK_INT_ARRAY,
new int[] {
@@ -5653,6 +5784,7 @@
sDefaults.putString(KEY_CARRIER_PROVISIONING_APP_STRING, "");
sDefaults.putBoolean(KEY_DISPLAY_NO_DATA_NOTIFICATION_ON_PERMANENT_FAILURE_BOOL, false);
sDefaults.putBoolean(KEY_UNTHROTTLE_DATA_RETRY_WHEN_TAC_CHANGES_BOOL, false);
+ sDefaults.putBoolean(KEY_VONR_SETTING_VISIBILITY_BOOL, false);
}
/**
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 255a612..abab426 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3483,7 +3483,8 @@
*/
private int getLogicalSlotIndex(int physicalSlotIndex) {
UiccSlotInfo[] slotInfos = getUiccSlotsInfo();
- if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length) {
+ if (slotInfos != null && physicalSlotIndex >= 0 && physicalSlotIndex < slotInfos.length
+ && slotInfos[physicalSlotIndex] != null) {
return slotInfos[physicalSlotIndex].getLogicalSlotIdx();
}
@@ -12143,6 +12144,100 @@
}
/**
+ * No error. Operation succeeded.
+ * @hide
+ */
+ public static final int ENABLE_VONR_SUCCESS = 0;
+
+ /**
+ * Radio is not available.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_NOT_AVAILABLE = 2;
+
+ /**
+ * Internal Radio error.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_ERROR = 3;
+
+ /**
+ * Voice over NR enable/disable request is received when system is in invalid state.
+ * @hide
+ */
+ public static final int ENABLE_VONR_RADIO_INVALID_STATE = 4;
+
+ /**
+ * Voice over NR enable/disable request is not supported.
+ * @hide
+ */
+ public static final int ENABLE_VONR_REQUEST_NOT_SUPPORTED = 5;
+
+ /** @hide */
+ @Retention(RetentionPolicy.SOURCE)
+ @IntDef(prefix = {"EnableVoNrResult"}, value = {
+ ENABLE_VONR_SUCCESS,
+ ENABLE_VONR_RADIO_NOT_AVAILABLE,
+ ENABLE_VONR_RADIO_ERROR,
+ ENABLE_VONR_RADIO_INVALID_STATE,
+ ENABLE_VONR_REQUEST_NOT_SUPPORTED})
+ public @interface EnableVoNrResult {}
+
+ /**
+ * Enable or disable Voice over NR (VoNR)
+ *
+ * <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
+ * given subId. Otherwise, applies to {@link SubscriptionManager#getDefaultDataSubscriptionId()}
+ *
+ * <p>Requires Permission:
+ * {@link android.Manifest.permission#MODIFY_PHONE_STATE MODIFY_PHONE_STATE}.
+ *
+ * @param enabled enable or disable VoNR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
+ public @EnableVoNrResult int setVoNrEnabled(boolean enabled) {
+ try {
+ ITelephony service = getITelephony();
+ if (service != null) {
+ return service.setVoNrEnabled(
+ getSubId(SubscriptionManager.getDefaultDataSubscriptionId()), enabled);
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException e) {
+ Log.e(TAG, "Error calling ITelephony#setVoNrEnabled", e);
+ }
+
+ return ENABLE_VONR_RADIO_INVALID_STATE;
+ }
+
+ /**
+ * Is Voice over NR (VoNR) enabled.
+ * @return true if Voice over NR (VoNR) is enabled else false. Enabled state does not mean
+ * voice call over NR is active or voice ove NR is available. It means the device is allowed to
+ * register IMS over NR.
+ * @throws IllegalStateException if the Telephony process is not currently available.
+ * @hide
+ */
+ @RequiresPermission(android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE)
+ public boolean isVoNrEnabled() {
+ try {
+ ITelephony telephony = getITelephony();
+ if (telephony != null) {
+ return telephony.isVoNrEnabled(getSubId());
+ } else {
+ throw new IllegalStateException("telephony service is null.");
+ }
+ } catch (RemoteException ex) {
+ Rlog.e(TAG, "isVoNrEnabled RemoteException", ex);
+ ex.rethrowFromSystemServer();
+ }
+ return false;
+ }
+
+ /**
* Carrier action to start or stop reporting default network available events.
*
* <p>If this object has been created with {@link #createForSubscriptionId}, applies to the
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 018dabf..89e3925 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -2228,6 +2228,20 @@
List<String> getEquivalentHomePlmns(int subId, String callingPackage, String callingFeatureId);
/**
+ * Enable or disable Voice over NR (VoNR)
+ * @param subId the subscription ID that this action applies to.
+ * @param enabled enable or disable VoNR.
+ * @return operation result.
+ */
+ int setVoNrEnabled(int subId, boolean enabled);
+
+ /**
+ * Is voice over NR enabled
+ * @return true if VoNR is enabled else false
+ */
+ boolean isVoNrEnabled(int subId);
+
+ /**
* Enable/Disable E-UTRA-NR Dual Connectivity
* @return operation result. See TelephonyManager.EnableNrDualConnectivityResult for
* details
diff --git a/telephony/java/com/android/internal/telephony/RILConstants.java b/telephony/java/com/android/internal/telephony/RILConstants.java
index fe8e671..fadc23b 100644
--- a/telephony/java/com/android/internal/telephony/RILConstants.java
+++ b/telephony/java/com/android/internal/telephony/RILConstants.java
@@ -528,6 +528,8 @@
int RIL_REQUEST_SET_ALLOWED_NETWORK_TYPES_BITMAP = 222;
int RIL_REQUEST_GET_ALLOWED_NETWORK_TYPES_BITMAP = 223;
int RIL_REQUEST_GET_SLICING_CONFIG = 224;
+ int RIL_REQUEST_ENABLE_VONR = 225;
+ int RIL_REQUEST_IS_VONR_ENABLED = 225;
/* Responses begin */
int RIL_RESPONSE_ACKNOWLEDGEMENT = 800;
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
index 08c9e5d..2cc1943 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/CommonAssertions.kt
@@ -36,30 +36,35 @@
}
}
+/**
+ * If [allStates] is true, checks if the stack space of all displays is fully covered
+ * by any visible layer, during the whole transitions
+ *
+ * Otherwise, checks if the stack space of all displays is fully covered
+ * by any visible layer, at the start and end of the transition
+ *
+ * @param allStates if all states should be checked, othersie, just initial and final
+ */
@JvmOverloads
-fun FlickerTestParameter.entireScreenCovered(
- beginRotation: Int,
- endRotation: Int = beginRotation,
- allStates: Boolean = true
-) {
- val startingBounds = WindowUtils.getDisplayBounds(beginRotation)
- val endingBounds = WindowUtils.getDisplayBounds(endRotation)
+fun FlickerTestParameter.entireScreenCovered(allStates: Boolean = true) {
if (allStates) {
assertLayers {
- if (startingBounds == endingBounds) {
- this.coversAtLeast(startingBounds)
- } else {
- this.coversAtLeast(startingBounds)
- .then()
- .coversAtLeast(endingBounds)
+ this.invoke("entireScreenCovered") { entry ->
+ entry.entry.displays.forEach { display ->
+ entry.visibleRegion().coversAtLeast(display.layerStackSpace)
+ }
}
}
} else {
assertLayersStart {
- this.visibleRegion().coversAtLeast(startingBounds)
+ this.entry.displays.forEach { display ->
+ this.visibleRegion().coversAtLeast(display.layerStackSpace)
+ }
}
assertLayersEnd {
- this.visibleRegion().coversAtLeast(endingBounds)
+ this.entry.displays.forEach { display ->
+ this.visibleRegion().coversAtLeast(display.layerStackSpace)
+ }
}
}
}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
index f9e6bab..1efb6da 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/close/CloseAppTransition.kt
@@ -123,9 +123,7 @@
@Presubmit
@Test
- open fun entireScreenCovered() {
- testSpec.entireScreenCovered(testSpec.config.startRotation, Surface.ROTATION_0)
- }
+ open fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
@@ -152,4 +150,4 @@
open fun launcherLayerReplacesApp() {
testSpec.replacesLayer(testApp.component, LAUNCHER_COMPONENT)
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
new file mode 100644
index 0000000..3074e28
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/NonResizeableAppHelper.kt
@@ -0,0 +1,32 @@
+/*
+ * 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.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import com.android.server.wm.flicker.testapp.ActivityOptions
+
+class NonResizeableAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy)
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
new file mode 100644
index 0000000..19fefb9
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/helpers/TwoActivitiesAppHelper.kt
@@ -0,0 +1,50 @@
+/*
+ * 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.helpers
+
+import android.app.Instrumentation
+import android.content.ComponentName
+import android.support.test.launcherhelper.ILauncherStrategy
+import android.support.test.launcherhelper.LauncherStrategyFactory
+import androidx.test.uiautomator.By
+import androidx.test.uiautomator.UiDevice
+import androidx.test.uiautomator.Until
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import com.android.server.wm.traces.parser.windowmanager.WindowManagerStateHelper
+
+class TwoActivitiesAppHelper @JvmOverloads constructor(
+ instr: Instrumentation,
+ launcherName: String = ActivityOptions.BUTTON_ACTIVITY_LAUNCHER_NAME,
+ component: ComponentName = ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME,
+ launcherStrategy: ILauncherStrategy = LauncherStrategyFactory
+ .getInstance(instr)
+ .launcherStrategy
+) : StandardAppHelper(instr, launcherName, component, launcherStrategy) {
+ fun openSecondActivity(device: UiDevice, wmHelper: WindowManagerStateHelper) {
+ val button = device.wait(
+ Until.findObject(By.res(getPackage(), "launch_second_activity")),
+ FIND_TIMEOUT)
+
+ require(button != null) {
+ "Button not found, this usually happens when the device " +
+ "was left in an unknown state (e.g. in split screen)"
+ }
+ button.click()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(component)
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
index 384d8e8..d17e77d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToAppTest.kt
@@ -119,7 +119,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
index ade215b..6f0f55a 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeAutoOpenWindowToHomeTest.kt
@@ -116,8 +116,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
- Surface.ROTATION_0)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
index cdfcff3..6751439 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToAppTest.kt
@@ -115,7 +115,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
@@ -165,4 +165,4 @@
.getConfigNonRotationTests(repetitions = 5)
}
}
-}
\ No newline at end of file
+}
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
index 05fc267..8aaf925 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/CloseImeWindowToHomeTest.kt
@@ -125,8 +125,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
- Surface.ROTATION_0)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
index f35a180..665204b 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/OpenImeWindowTest.kt
@@ -108,7 +108,7 @@
@Presubmit
@Test
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
index 3bcf793..fe1b1cd 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/ime/ReOpenImeWindowTest.kt
@@ -143,8 +143,7 @@
@Presubmit
@Test
// During testing the launcher is always in portrait mode
- fun entireScreenCovered() = testSpec.entireScreenCovered(testSpec.config.startRotation,
- testSpec.config.endRotation)
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
new file mode 100644
index 0000000..42c252e
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/ActivitiesTransitionTest.kt
@@ -0,0 +1,116 @@
+/*
+ * 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.launch
+
+import android.app.Instrumentation
+import android.platform.test.annotations.Presubmit
+import androidx.test.filters.RequiresDevice
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.server.wm.flicker.entireScreenCovered
+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.repetitions
+import com.android.server.wm.flicker.annotation.Group1
+import com.android.server.wm.flicker.dsl.FlickerBuilder
+import com.android.server.wm.flicker.helpers.TwoActivitiesAppHelper
+import com.android.server.wm.flicker.testapp.ActivityOptions
+import org.junit.FixMethodOrder
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * Test the back and forward transition between 2 activities.
+ * To run this test: `atest FlickerTests:ActivitiesTransitionTest`
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class ActivitiesTransitionTest(val testSpec: FlickerTestParameter) {
+ val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp: TwoActivitiesAppHelper = TwoActivitiesAppHelper(instrumentation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ withTestName { testSpec.name }
+ repeat { testSpec.config.repetitions }
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+ teardown {
+ test {
+ testApp.exit()
+ }
+ }
+ transitions {
+ testApp.openSecondActivity(device, wmHelper)
+ device.pressBack()
+ wmHelper.waitForAppTransitionIdle()
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun finishSubActivity() {
+ testSpec.assertWm {
+ this.isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+ .then()
+ .isAppWindowOnTop(ActivityOptions.SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME)
+ .then()
+ .isAppWindowOnTop(ActivityOptions.BUTTON_ACTIVITY_COMPONENT_NAME)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun entireScreenCovered() = testSpec.entireScreenCovered()
+
+ @Presubmit
+ @Test
+ fun launcherWindowNotVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(LAUNCHER_COMPONENT, ignoreActivity = true)
+ }
+ }
+
+ @Presubmit
+ @Test
+ fun launcherLayerNotVisible() {
+ testSpec.assertLayers { this.isInvisible(LAUNCHER_COMPONENT) }
+ }
+
+ companion object {
+ @Parameterized.Parameters(name = "{0}")
+ @JvmStatic
+ fun getParams(): Collection<FlickerTestParameter> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(repetitions = 5)
+ }
+ }
+}
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
new file mode 100644
index 0000000..b717612
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/launch/OpenAppNonResizeableTest.kt
@@ -0,0 +1,244 @@
+/*
+ * 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.launch
+
+import android.content.ComponentName
+import android.platform.test.annotations.Postsubmit
+import android.platform.test.annotations.Presubmit
+import android.view.Surface
+import android.view.WindowManagerPolicyConstants
+import androidx.test.filters.FlakyTest
+import androidx.test.filters.RequiresDevice
+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.annotation.Group1
+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
+import org.junit.runners.MethodSorters
+import org.junit.runners.Parameterized
+
+/**
+ * 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)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@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() = { args ->
+ super.transition(this, args)
+ setup {
+ eachRun {
+ device.sleep()
+ wmHelper.waitFor("noAppWindowsOnTop") {
+ it.wmState.topVisibleAppWindow.isEmpty()
+ }
+ }
+ }
+ teardown {
+ eachRun {
+ testApp.exit(wmHelper)
+ }
+ }
+ transitions {
+ testApp.launchViaIntent(wmHelper)
+ wmHelper.waitForFullScreenApp(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the nav bar layer starts visible, becomes invisible during unlocking animation
+ * and becomes visible at the end
+ */
+ @Presubmit
+ @Test
+ 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 appLayerBecomesVisible() {
+ testSpec.assertLayers {
+ this.notContains(testApp.component)
+ .then()
+ .isInvisible(testApp.component)
+ .then()
+ .isVisible(testApp.component)
+ }
+ }
+
+ /**
+ * 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 appWindowBecomesVisible() {
+ testSpec.assertWm {
+ this.notContains(testApp.component)
+ .then()
+ .isAppWindowInvisible(testApp.component,
+ ignoreActivity = true, isOptional = true)
+ .then()
+ .isAppWindowVisible(testApp.component, ignoreActivity = true)
+ }
+ }
+
+ /**
+ * Checks if [testApp] is visible at the end of the transition
+ */
+ @Presubmit
+ @Test
+ fun appWindowBecomesVisibleAtEnd() {
+ testSpec.assertWmEnd {
+ this.isVisible(testApp.component)
+ }
+ }
+
+ /**
+ * 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
+ 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()
+
+ /**
+ * Checks that the screen is locked at the start of the transition ([colorFadComponent])
+ * layer is visible
+ */
+ @Postsubmit
+ @Test
+ fun screenLockedStart() {
+ testSpec.assertLayersStart {
+ isVisible(colorFadComponent)
+ }
+ }
+
+ /**
+ * 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() {
+ 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> {
+ return FlickerTestParameterFactory.getInstance()
+ .getConfigNonRotationTests(
+ repetitions = 5,
+ supportedNavigationModes =
+ listOf(WindowManagerPolicyConstants.NAV_BAR_MODE_GESTURAL_OVERLAY),
+ supportedRotations = listOf(Surface.ROTATION_0)
+ )
+ }
+ }
+}
\ No newline at end of file
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 860a5ae..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 val testApp: StandardAppHelper = SimpleAppHelper(instrumentation)
+ 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,13 +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(Surface.ROTATION_0, testSpec.config.endRotation)
- }
+ open fun entireScreenCovered() = testSpec.entireScreenCovered()
+ /**
+ * Checks that the focus changes from the launcher to [testApp]
+ */
@Presubmit
@Test
open fun focusChanges() {
@@ -136,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() {
@@ -150,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/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
new file mode 100644
index 0000000..ca8f8af
--- /dev/null
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/quickswitch/QuickSwitchFromLauncherTest.kt
@@ -0,0 +1,347 @@
+/*
+ * 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.Presubmit
+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.entireScreenCovered
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.server.wm.flicker.helpers.WindowUtils
+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 to last opened app from launcher
+ *
+ * To run this test: `atest FlickerTests:QuickSwitchFromLauncherTest`
+ *
+ * Actions:
+ * Launch an app
+ * Navigate home to show launcher
+ * Swipe right from the bottom of the screen to quick switch back to the app
+ *
+ */
+@RequiresDevice
+@RunWith(Parameterized::class)
+@Parameterized.UseParametersRunnerFactory(FlickerParametersRunnerFactory::class)
+@FixMethodOrder(MethodSorters.NAME_ASCENDING)
+@Group1
+class QuickSwitchFromLauncherTest(private val testSpec: FlickerTestParameter) {
+ private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+ private val testApp = SimpleAppHelper(instrumentation)
+ private val startDisplayBounds = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
+
+ @FlickerBuilderProvider
+ fun buildFlicker(): FlickerBuilder {
+ return FlickerBuilder(instrumentation).apply {
+ setup {
+ eachRun {
+ testApp.launchViaIntent(wmHelper)
+ device.pressHome()
+ wmHelper.waitForHomeActivityVisible()
+ wmHelper.waitForWindowSurfaceDisappeared(testApp.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,
+ 50
+ )
+
+ wmHelper.waitForFullScreenApp(testApp.component)
+ wmHelper.waitForAppTransitionIdle()
+ }
+
+ teardown {
+ eachRun {
+ testApp.exit()
+ }
+ }
+ }
+ }
+
+ /**
+ * Checks that [testApp] windows fill the entire screen (i.e. is "fullscreen") at the end of the
+ * transition once we have fully quick switched from the launcher back to the [testApp].
+ */
+ @Presubmit
+ @Test
+ fun endsWithAppWindowsCoveringFullScreen() {
+ testSpec.assertWmEnd {
+ this.frameRegion(testApp.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that [testApp] layers fill the entire screen (i.e. is "fullscreen") at the end of the
+ * transition once we have fully quick switched from the launcher back to the [testApp].
+ */
+ @Presubmit
+ @Test
+ fun endsWithAppLayersCoveringFullScreen() {
+ testSpec.assertLayersEnd {
+ this.visibleRegion(testApp.component).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that [testApp] is the top window at the end of the transition once we have fully quick
+ * switched from the launcher back to the [testApp].
+ */
+ @Presubmit
+ @Test
+ fun endsWithAppBeingOnTop() {
+ testSpec.assertWmEnd {
+ this.isAppWindowOnTop(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the home activity being tagged as visible.
+ */
+ @Presubmit
+ @Test
+ fun startsWithHomeActivityFlaggedVisible() {
+ testSpec.assertWmStart {
+ this.isHomeActivityVisible(true)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the launcher windows filling/covering exactly the
+ * entirety of the display.
+ */
+ @Presubmit
+ @Test
+ fun startsWithLauncherWindowsCoverFullScreen() {
+ testSpec.assertWmStart {
+ this.frameRegion(LAUNCHER_COMPONENT).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the launcher layers filling/covering exactly the
+ * entirety of the display.
+ */
+ @Presubmit
+ @Test
+ fun startsWithLauncherLayersCoverFullScreen() {
+ testSpec.assertLayersStart {
+ this.visibleRegion(LAUNCHER_COMPONENT).coversExactly(startDisplayBounds)
+ }
+ }
+
+ /**
+ * Checks that the transition starts with the launcher being the top window.
+ */
+ @Presubmit
+ @Test
+ fun startsWithLauncherBeingOnTop() {
+ testSpec.assertWmStart {
+ this.isAppWindowOnTop(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that the transition ends with the home activity being flagged as not visible. By this
+ * point we should have quick switched away from the launcher back to the [testApp].
+ */
+ @Presubmit
+ @Test
+ fun endsWithHomeActivityFlaggedInvisible() {
+ testSpec.assertWmEnd {
+ this.isHomeActivityVisible(false)
+ }
+ }
+
+ /**
+ * Checks that [testApp]'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.
+ */
+ @Presubmit
+ @Test
+ fun appWindowBecomesAndStaysVisible() {
+ testSpec.assertWm {
+ this.isAppWindowInvisible(testApp.component, ignoreActivity = true)
+ .then()
+ .isAppWindowVisible(testApp.component, ignoreActivity = true)
+ }
+ }
+
+ /**
+ * Checks that [testApp]'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.
+ */
+ @Presubmit
+ @Test
+ fun appLayerBecomesAndStaysVisible() {
+ testSpec.assertLayers {
+ this.isInvisible(testApp.component)
+ .then()
+ .isVisible(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the launcher 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.
+ */
+ @Presubmit
+ @Test
+ fun launcherWindowBecomesAndStaysInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowInvisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that the launcher 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.
+ */
+ @Presubmit
+ @Test
+ fun launcherLayerBecomesAndStaysInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isInvisible(LAUNCHER_COMPONENT)
+ }
+ }
+
+ /**
+ * Checks that the launcher window is visible at least until the app window is visible. Ensures
+ * that at any point, either the launcher or [testApp] windows are at least partially visible.
+ */
+ @Presubmit
+ @Test
+ fun appWindowIsVisibleOnceLauncherWindowIsInvisible() {
+ testSpec.assertWm {
+ this.isAppWindowVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isAppWindowVisible(SNAPSHOT_COMPONENT)
+ .then()
+ .isAppWindowVisible(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the launcher layer is visible at least until the app layer is visible. Ensures
+ * that at any point, either the launcher or [testApp] layers are at least partially visible.
+ */
+ @Presubmit
+ @Test
+ fun appLayerIsVisibleOnceLauncherLayerIsInvisible() {
+ testSpec.assertLayers {
+ this.isVisible(LAUNCHER_COMPONENT)
+ .then()
+ .isVisible(SNAPSHOT_COMPONENT)
+ .then()
+ .isVisible(testApp.component)
+ }
+ }
+
+ /**
+ * Checks that the navbar window is visible throughout the entire transition.
+ */
+ @Presubmit
+ @Test
+ fun navBarWindowIsAlwaysVisible() = testSpec.navBarWindowIsVisible()
+
+ /**
+ * Checks that the navbar layer is visible throughout the entire transition.
+ */
+ @Presubmit
+ @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.
+ */
+ @Presubmit
+ @Test
+ fun navbarIsAlwaysInRightPosition() =
+ testSpec.navBarLayerRotatesAndScales(testSpec.config.startRotation)
+
+ /**
+ * Checks that the status bar window is visible throughout the entire transition.
+ */
+ @Presubmit
+ @Test
+ fun statusBarWindowIsAlwaysVisible() = testSpec.statusBarWindowIsVisible()
+
+ /**
+ * Checks that the status bar layer is visible throughout the entire transition.
+ */
+ @Presubmit
+ @Test
+ fun statusBarLayerIsAlwaysVisible() = testSpec.statusBarLayerIsVisible()
+
+ /**
+ * Checks that the screen is always fully covered by visible layers throughout the transition.
+ */
+ @Presubmit
+ @Test
+ fun screenIsAlwaysFilled() = testSpec.entireScreenCovered()
+
+ 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
+ ),
+ // TODO: Test with 90 rotation
+ supportedRotations = listOf(Surface.ROTATION_0)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
index 73986b6..d57c6698 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/ChangeAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import androidx.test.filters.FlakyTest
import androidx.test.filters.RequiresDevice
@@ -85,7 +84,7 @@
testSpec.statusBarWindowIsVisible()
}
- @Postsubmit
+ @Presubmit
@Test
fun statusBarLayerIsVisible() {
testSpec.statusBarLayerIsVisible()
@@ -98,30 +97,12 @@
testSpec.config.startRotation, testSpec.config.endRotation)
}
- @Presubmit
- @Test
- override fun navBarWindowIsVisible() {
- super.navBarWindowIsVisible()
- }
-
- @Postsubmit
- @Test
- override fun navBarLayerIsVisible() {
- super.navBarLayerIsVisible()
- }
-
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() {
super.navBarLayerRotatesAndScales()
}
- @Postsubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
companion object {
@Parameterized.Parameters(name = "{0}")
@JvmStatic
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
index 2b0b3c2..612ff9d 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/RotationTransition.kt
@@ -25,7 +25,6 @@
import com.android.server.wm.flicker.dsl.FlickerBuilder
import com.android.server.wm.flicker.endRotation
import com.android.server.wm.flicker.helpers.StandardAppHelper
-import com.android.server.wm.flicker.helpers.WindowUtils
import com.android.server.wm.flicker.helpers.setRotation
import com.android.server.wm.flicker.navBarLayerIsVisible
import com.android.server.wm.flicker.navBarLayerRotatesAndScales
@@ -39,8 +38,6 @@
protected abstract val testApp: StandardAppHelper
protected val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
- protected val startingPos get() = WindowUtils.getDisplayBounds(testSpec.config.startRotation)
- protected val endingPos get() = WindowUtils.getDisplayBounds(testSpec.config.endRotation)
protected open val transition: FlickerBuilder.(Map<String, Any?>) -> Unit = {
setup {
@@ -107,10 +104,7 @@
@Presubmit
@Test
- open fun entireScreenCovered() {
- testSpec.entireScreenCovered(testSpec.config.startRotation,
- testSpec.config.endRotation, allStates = false)
- }
+ open fun entireScreenCovered() = testSpec.entireScreenCovered()
@Presubmit
@Test
@@ -124,7 +118,9 @@
@Test
open fun appLayerRotates_StartingPos() {
testSpec.assertLayersStart {
- this.visibleRegion(testApp.component).coversExactly(startingPos)
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+ }
}
}
@@ -132,7 +128,9 @@
@Test
open fun appLayerRotates_EndingPos() {
testSpec.assertLayersEnd {
- this.visibleRegion(testApp.component).coversExactly(endingPos)
+ this.entry.displays.map { display ->
+ this.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+ }
}
}
}
\ No newline at end of file
diff --git a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index b97b977..48efe73 100644
--- a/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -16,7 +16,6 @@
package com.android.server.wm.flicker.rotation
-import android.platform.test.annotations.Postsubmit
import android.platform.test.annotations.Presubmit
import android.view.WindowManager
import androidx.test.filters.FlakyTest
@@ -99,13 +98,15 @@
}
}
- @Postsubmit
+ @Presubmit
@Test
fun appLayerRotates() {
testSpec.assertLayers {
- this.coversExactly(startingPos, testApp.component)
- .then()
- .coversExactly(endingPos, testApp.component)
+ this.invoke("entireScreenCovered") { entry ->
+ entry.entry.displays.map { display ->
+ entry.visibleRegion(testApp.component).coversExactly(display.layerStackSpace)
+ }
+ }
}
}
@@ -125,24 +126,6 @@
}
}
- @Presubmit
- @Test
- override fun visibleLayersShownMoreThanOneConsecutiveEntry() {
- super.visibleLayersShownMoreThanOneConsecutiveEntry()
- }
-
- @Postsubmit
- @Test
- override fun navBarWindowIsVisible() {
- super.navBarWindowIsVisible()
- }
-
- @Postsubmit
- @Test
- override fun navBarLayerIsVisible() {
- super.navBarLayerIsVisible()
- }
-
@FlakyTest
@Test
override fun navBarLayerRotatesAndScales() = super.navBarLayerRotatesAndScales()
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 1599ed4..3b9f33a 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -59,5 +59,26 @@
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
+ <activity android:name=".NonResizeableActivity"
+ android:resizeableActivity="false"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
+ android:label="NonResizeableApp"
+ android:exported="true"
+ android:showOnLockScreen="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
+ <activity android:name=".ButtonActivity"
+ android:taskAffinity="com.android.server.wm.flicker.testapp.ButtonActivity"
+ android:configChanges="orientation|screenSize"
+ android:label="ButtonActivity"
+ android:exported="true">
+ <intent-filter>
+ <action android:name="android.intent.action.MAIN"/>
+ <category android:name="android.intent.category.LAUNCHER"/>
+ </intent-filter>
+ </activity>
</application>
</manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
new file mode 100644
index 0000000..fe7bced
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_button.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 The Android Open Source Project
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:background="@android:color/holo_orange_light">
+ <Button
+ android:id="@+id/launch_second_activity"
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="Second activity" />
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
new file mode 100644
index 0000000..6d5a9dd
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 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.
+-->
+<LinearLayout
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"
+ android:orientation="vertical"
+ android:background="@android:color/holo_orange_light">
+
+ <TextView
+ android:id="@+id/NonResizeableTest"
+ android:layout_width="fill_parent"
+ android:layout_height="fill_parent"
+ android:gravity="center_vertical|center_horizontal"
+ android:text="NonResizeableActivity"
+ android:textAppearance="?android:attr/textAppearanceLarge"/>
+
+</LinearLayout>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 0ccc498..224d2ac 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -41,4 +41,14 @@
public static final ComponentName SIMPLE_ACTIVITY_AUTO_FOCUS_COMPONENT_NAME =
new ComponentName(FLICKER_APP_PACKAGE,
FLICKER_APP_PACKAGE + ".SimpleActivity");
+
+ public static final String NON_RESIZEABLE_ACTIVITY_LAUNCHER_NAME = "NonResizeableApp";
+ public static final ComponentName NON_RESIZEABLE_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".NonResizeableActivity");
+
+ public static final String BUTTON_ACTIVITY_LAUNCHER_NAME = "ButtonApp";
+ public static final ComponentName BUTTON_ACTIVITY_COMPONENT_NAME =
+ new ComponentName(FLICKER_APP_PACKAGE,
+ FLICKER_APP_PACKAGE + ".ButtonActivity");
}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
new file mode 100644
index 0000000..b42ac2a
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ButtonActivity.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.content.Intent;
+import android.os.Bundle;
+import android.view.WindowManager;
+import android.widget.Button;
+
+public class ButtonActivity extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ WindowManager.LayoutParams p = getWindow().getAttributes();
+ p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
+ .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
+ getWindow().setAttributes(p);
+ setContentView(R.layout.activity_button);
+
+ Button button = findViewById(R.id.launch_second_activity);
+ button.setOnClickListener(v -> {
+ Intent intent = new Intent(ButtonActivity.this, SimpleActivity.class);
+ startActivity(intent);
+ });
+ }
+}
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
new file mode 100644
index 0000000..61019d8
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NonResizeableActivity.java
@@ -0,0 +1,37 @@
+/*
+ * 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.testapp;
+
+import android.app.Activity;
+import android.app.KeyguardManager;
+import android.os.Bundle;
+
+public class NonResizeableActivity extends Activity {
+
+ @Override
+ protected void onCreate(Bundle icicle) {
+ super.onCreate(icicle);
+ setContentView(R.layout.activity_non_resizeable);
+
+ setShowWhenLocked(true);
+ setTurnScreenOn(true);
+ KeyguardManager keyguardManager = getSystemService(KeyguardManager.class);
+ if (keyguardManager != null) {
+ keyguardManager.requestDismissKeyguard(this, null);
+ }
+ }
+}